Oracle — измените тип столбца без перетасовки идентификаторов столбцов

#oracle

Вопрос:

У меня есть простая таблица Oracle, в которой уже есть данные:

 CRATE NUMBER(10)  2V5 FLOAT(126)  tstamp TIMESTAMP(6)¨  

Я пытаюсь преобразовать его в это, включая данные внутри:

 CRATE NUMBER(10)  2V5 FLOAT(126)  tstamp TIMESTAMP(6) WITH TIME ZONE  

Мне удалось сделать это с помощью следующего набора команд:

 ALTER TABLE "TIMESTAMP_DEBUG_TABLE" ADD( "temp_ts" TIMESTAMP WITH TIME ZONE );  UPDATE "TIMESTAMP_DEBUG_TABLE" SET "temp_ts" = "tstamp" AT TIME ZONE 'Europe/Zurich';  ALTER TABLE "TIMESTAMP_DEBUG_TABLE" DROP COLUMN "tstamp";  ALTER TABLE "TIMESTAMP_DEBUG_TABLE" RENAME COLUMN "temp_ts" TO "tstamp";  

Однако есть одна проблема. Каждый столбец имеет идентификатор столбца в oracle, который получается путем выполнения: SELECT column_id FROM USER_TAB_COLUMNS WHERE table_name = 'A' AND column_name = 'B';

Я использую этот идентификатор столбца в своем программном обеспечении, и на самом деле в моей базе данных есть еще одна таблица, которая рассматривает его как своего рода внешний ключ. При выполнении вышеуказанного набора команд идентификаторы столбцов перемешиваются, и целостность ссылок нарушается.

Как я могу решить эту проблему?

  1. Есть ли какой-либо способ повторно ввести этот столбец, не перетасовывая идентификаторы столбцов таблицы?
  2. Есть ли способ формализовать взаимосвязь идентификатора столбца? Могу ли я добавить ограничение FK в свою таблицу, которое указывает на идентификаторы столбцов других таблиц? Тогда я мог бы каскадировать.
  3. Какие-нибудь другие идеи/обходные пути?

Комментарии:

1. Oracle использует эту информацию для своих нужд. Вам не следует полагаться на это: у вас будет точно такое же отношение (таблица), если вы объявите cols в другом порядке. Вы даже можете заменить таблицу представлением, в котором столбцы проецируются в другом порядке: модель данных останется прежней с точки зрения потребления (и это основная причина, по которой мы используем базу данных, а не потому, что создавать таблицы слишком круто). Итак, вы использовали внутреннюю информацию БД как часть своей модели, и у вас возникли некоторые проблемы: пришло время погасить этот долг. Столбец адреса по его названию: lt;schemagt;.lt;objectgt;.lt;columngt;

Ответ №1:

Полагаться на column_id это в первую очередь кажется немного проблематичным. Казалось бы, имеет больше смысла полагаться на имя столбца, поскольку именно его эффективно использует в качестве ключа любая другая инструкция SQL в мире. Но я предполагаю, что изменение этого не является стартовым.

Это дороже с точки зрения ввода-вывода и времени, но вы можете создать новую таблицу, переместить данные, а затем переименовать ее. Это должно привести к конечному состоянию, в котором две таблицы имеют одинаковые column_id значения (при условии, что timestamp_debug_table в настоящее время ранее не было добавлено или удалено никаких столбцов, которые могли бы привести column_id к неправильному порядку значений).

 create table timestamp_debug_table2 (  crate number(10),  "2V5" float(126),  "tstamp" timestamp(6) with time zone );  insert into timestamp_debug_table2  select crate, "2V5", "tstamp" at time zone 'Europe/Zurich'  from timestamp_debug_table;   drop table timestamp_debug_table;  alter table timestamp_debug_table2 rename to timestamp_debug_table;  

Предполагая, что вы находитесь на 12c или более поздней версии, вы также можете сделать столбец невидимым и снова видимым, прежде чем удалить его, что также изменит column_id значения. Это еще одна причина не зависеть от чего-то подобного column_id , потому что Oracle может свободно возиться с ним, чтобы реализовать другие функциональные возможности. Никто, вероятно, не догадается, что выполнение чего-то вроде повторного создания невидимого и видимого столбца приведет к тому, что ваше программное обеспечение перестанет работать правильно.

 ALTER TABLE "TIMESTAMP_DEBUG_TABLE" ADD( "temp_ts" TIMESTAMP WITH TIME ZONE );  UPDATE "TIMESTAMP_DEBUG_TABLE" SET "temp_ts" = "tstamp" AT TIME ZONE 'Europe/Zurich';  -- This causes the column_id in user_tab_columns to be set to NULL and "temp_ts" -- will have a value of 3 alter table TIMESTAMP_DEBUG_TABLE  column "tstamp" invisible;  -- Now the column_id in user_tab_columns will be 4 for "tstamp". "temp_ts" will -- still have a value of 3 alter table TIMESTAMP_DEBUG_TABLE  column "tstamp" visible;  ALTER TABLE "TIMESTAMP_DEBUG_TABLE" DROP COLUMN "tstamp";  ALTER TABLE "TIMESTAMP_DEBUG_TABLE" RENAME COLUMN "temp_ts" TO "tstamp";