Восстановление БД из сценария SQL с ограничениями внешнего ключа - PullRequest
0 голосов
/ 01 ноября 2011

Я пытаюсь восстановить БД с помощью сценария SQL, но мешают ограничения по внешнему ключу

Я беру базу данных MySQL и переносу ее в PostgreSQL.Так как синтаксис таблицы создания MySQL оказался совершенно другим, я взял другую базу данных PostgreSQL с той же схемой, но с другими данными, и восстановил только схему.Другими словами, у меня теперь есть база данных с таблицами, ограничениями, последовательностями и всем этим shnaz, но без данных внутри.

Итак, пришло время восстановить данные.Я беру резервную копию базы данных MySQL с phpMyAdmin (только данные) в качестве сценария SQL (pgAdmin, похоже, не принимает файлы zip или gzip по какой-то причине), и запускаю сценарий SQL.Теперь, когда проблемы начинают возникать, это естественно, я перехожу с MySQL на PostgreSQL, поэтому неизбежны синтаксические ошибки.

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

ERROR: insert or update on table "_account" violates foreign key constraint "fk_1_account"
DETAIL:  Key (accountid)=(2) is not present in table "_entity".

Итак, да, в принципе, существует внешнее ограничение, запрос пытается вставить данные в таблицу _account, но соответствующие данные не были вставлены в таблицу _entityеще.Как мне обойти это?Есть ли способ заставить pgAdmin3 / PostgreSQL отключить ВСЕ ограничения, вставить данные и затем снова включить ограничения?

С синтаксической ошибкой, с которой я столкнулся, была эта:

 INSERT INTO _accounttype_seq (id) VALUES (11);

PostgreSQL-эквивалент этого оператора (если я прав) -

 ALTER SEQUENCE _accounttype_seq INCREMENT BY 11; 

Но немного пройти через весь сценарий и изменить все 200+ операторов вставки Sequence.Итак, мне здесь лень, но есть ли более простой способ разобраться с последовательностями?

Или, у вас, ребята, есть какие-то предложения по другому набору инструментов, чтобы сделать это проще?

Спасибо за ваше время, хорошего дня.

Ответы [ 2 ]

2 голосов
/ 01 ноября 2011

Не пытайтесь обойти ограничения внешнего ключа. Это способ убедиться, что данные плохие.

Сначала посмотрите на ограничения и убедитесь, что вы вставляете в таблицы в правильном порядке. Если _entity является родительским для "_account, то он должен быть заполнен первым.

Далее необходимо, чтобы скрипт переместил все ошибочные записи в таблицу исключений. Затем вы можете посмотреть на них и увидеть, в чем заключается проблема целостности данных, и если вам нужно постоянно отбрасывать записи или попытаться выяснить, каким должно быть отсутствующее родительское значение. Если это важные данные, такие как заказы, в которых клиент больше не существует (возможно, в любой системе, в которой не было правильных fks для начала), и вы должны вести запись и не можете определить, какое родительское значение должно было быть, вы можете создать «Неизвестная» запись в таблице клиентов и назначение всех плохих заказов этому идентификатору клиента.

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

Я бы попытался найти инструмент импорта данных для PostgreSQL - я живу в мире SQL-серверов, где я бы использовал SSIS, но вам нужен эквивалент SSIS для мира PostgreSQL.

2 голосов
/ 01 ноября 2011

Очевидно, что внешние ключи фактически не применялись в MySQL (возможно, из-за использования MyISAM), или сгенерированный SQL просто делает это в неправильном порядке.

Если это «только» неправильный порядок, я вижу два возможных решения:

  1. отредактируйте сгенерированный скрипт и либо переместите все определения FK в конец скрипта
  2. Отредактируйте определение каждого ограничения FK и установите для всех них значение initially deferred. Затем запустите сценарий как одну транзакцию, только с фиксацией в самом конце.

Редактировать (потому что это слишком много для комментария)

Использование SET CONSTRAINTS ALL DEFERRED будет работать только в том случае, если ограничения были созданы с опцией DEFERRABLE.

Чтобы запустить все в одной транзакции, вы должны убедиться, что отключили автокоммит. Затем просто запустите INSERT s и в самом конце введите COMMIT. ; будет фиксироваться, только если вы включили автокоммит.

Если вы хотите быть независимым от настройки автоматической фиксации, запустите ваш скрипт с [BEGIN][1] и убедитесь, что в самом конце есть только один COMMIT.

BEGIN DEFERRABLE
   INSERT INTO table_one ... ;
   INSERT INTO table_two ... ; 
   .....
COMMIT;
...