2013-12-03 2 views
22

Я хотел бы изменить тип столбца с int на uuid. Я использую следующее заявлениеPostgresql изменить тип столбца от int до UUID

ALTER TABLE tableA ALTER COLUMN colA SET DATA TYPE UUID; 

Но я получаю сообщение об ошибке

ERROR: column "colA" cannot be cast automatically to type uuid 
HINT: Specify a USING expression to perform the conversion. 

Я смущен, как использовать USING сделать бросок.

ответ

30

Вы не можете просто ввести int4 в uuid; это был бы недействительный uuid, только с 32 битами, причем высокие 96 бит равны нулю.

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

Не запускайте этот без резервной копии ваших данных. Он постоянно отбрасывает старые значения в colA.

ALTER TABLE tableA ALTER COLUMN colA SET DATA TYPE UUID USING (uuid_generate_v4()); 

Лучший подход, как правило, к добавить UUID колонку, а затем исправить любые внешние ключевые ссылки, чтобы указать на него, и, наконец, удаление исходной колонки.

Вам нужен модуль UUID установлен:

CREATE EXTENSION "uuid-ossp"; 

кавычки необходимы.

+0

Я получаю «ОШИБКА: функция uuid_generate_v4() не существует». Есть ли какие-то дополнения, которые мне нужны? – user1802143

+1

@ user1802143 Да, см. Редактирование. Или Google ;-) –

+1

'ОШИБКА: значение по умолчанию для столбца« Идентификатор »не может быть автоматически добавлено для ввода uuid Состояние SQL: 42804' при запуске команды, добавление швов столбцов является единственным рабочим вариантом – konzo

4

Мне пришлось конвертировать из текста в uuid-тип и из миграции Django, поэтому после его решения я написал его в http://baltaks.com/2015/08/how-to-change-text-fields-to-a-real-uuid-type-for-django-and-postgresql в случае, если кто-то поможет. Те же методы будут работать для преобразования целого числа в uuid.

На основе комментариев, я добавил полное решение здесь:

Джанго, скорее всего, создать миграцию для вас, что выглядит примерно так:

class Migration(migrations.Migration): 

    dependencies = [ 
     ('app', '0001_auto'), 
    ] 

    operations = [ 
     migrations.AlterField(
      model_name='modelname', 
      name='uuid', 
      field=models.UUIDField(db_index=True, unique=True), 
     ), 
    ] 

Сначала ставят авто создана миграции операции в операцию RunSQL как параметр state_operations. Это позволяет вам настроить пользовательскую миграцию, но сообщите Django о том, что произошло с схемой базы данных.

class Migration(migrations.Migration): 

    dependencies = [ 
     ('app', '0001_auto'), 
    ] 

    operations = [ 
    migrations.RunSQL(sql_commands, None, [ 
      migrations.AlterField(
       model_name='modelname', 
       name='uuid', 
       field=models.UUIDField(db_index=True, unique=True), 
      ), 
     ]), 
    ] 

Теперь вы должны будете предоставить некоторые команды SQL для этой sql_commands переменной. Я решил поставить SQL в отдельный файл, а затем загрузить в со следующим кодом питона:

sql_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '0001.sql') 
with open(sql_path, "r") as sqlfile: 
    sql_commands = sqlfile.read() 

Теперь для реальной сложной части, где мы на самом деле выполнить миграцию. Основная команда, которую вы хотите выглядеть так:

alter table tablename alter column uuid type uuid using uuid::uuid;

Но причина, мы здесь из-индексов. И, как я обнаружил, Django любит использовать ваши миграции для создания случайно названных индексов в ваших полях во время выполнения тестов, поэтому ваши тесты не удастся, если вы просто удалите и затем заново создадите индекс фиксированного имени или два.Итак, следующее: sql, который удалит одно ограничение и все индексы в текстовом поле перед преобразованием в поле uuid. Он также работает для нескольких таблиц за один раз.

DO $$ 
DECLARE 
    table_names text[]; 
    this_table_name text; 
    the_constraint_name text; 
    index_names record; 

BEGIN 

SELECT array['table1', 
      'table2' 
      ] 
    INTO table_names; 


FOREACH this_table_name IN array table_names 
LOOP 
    RAISE notice 'migrating table %', this_table_name; 

    SELECT CONSTRAINT_NAME INTO the_constraint_name 
    FROM information_schema.constraint_column_usage 
    WHERE CONSTRAINT_SCHEMA = current_schema() 
     AND COLUMN_NAME IN ('uuid') 
     AND TABLE_NAME = this_table_name 
    GROUP BY CONSTRAINT_NAME 
    HAVING count(*) = 1; 
    if the_constraint_name is not NULL then 
     RAISE notice 'alter table % drop constraint %', 
      this_table_name, 
      the_constraint_name; 
     execute 'alter table ' || this_table_name 
      || ' drop constraint ' || the_constraint_name; 
    end if; 

    FOR index_names IN 
    (SELECT i.relname AS index_name 
    FROM pg_class t, 
      pg_class i, 
      pg_index ix, 
      pg_attribute a 
    WHERE t.oid = ix.indrelid 
     AND i.oid = ix.indexrelid 
     AND a.attrelid = t.oid 
     AND a.attnum = any(ix.indkey) 
     AND t.relkind = 'r' 
     AND a.attname = 'uuid' 
     AND t.relname = this_table_name 
    ORDER BY t.relname, 
       i.relname) 
    LOOP 
     RAISE notice 'drop index %', quote_ident(index_names.index_name); 
     EXECUTE 'drop index ' || quote_ident(index_names.index_name); 
    END LOOP; -- index_names 

    RAISE notice 'alter table % alter column uuid type uuid using uuid::uuid;', 
     this_table_name; 
    execute 'alter table ' || quote_ident(this_table_name) 
     || ' alter column uuid type uuid using uuid::uuid;'; 
    RAISE notice 'CREATE UNIQUE INDEX %_uuid ON % (uuid);', 
     this_table_name, this_table_name; 
    execute 'create unique index ' || this_table_name || '_uuid on ' 
     || this_table_name || '(uuid);'; 

END LOOP; -- table_names 

END; 
$$ 
+0

Внимание! Это не устраняет ссылки на внешние ключи для использования нужного типа данных. –

1

В PostgreSQL 9.3 вы можете сделать это:

ALTER TABLE "tableA" ALTER COLUMN "ColA" SET DATA TYPE UUID USING "ColA"::UUID; 

и низверг тип данных UUID и это позволит избежать сообщение об ошибке.

+6

ОШИБКА: нельзя использовать тип integer для uuid –

1

Просто, если кто-то сталкивается с этой старой темой. Я решил проблему, сначала изменив поле на тип CHAR, а затем на тип UUID.

+0

Можете ли вы объяснить, как вы это делаете дальше? – friek108

Смежные вопросы