MySQL DDL Trigger, схема Diff-таблицы для переименования столбца

Я создаю PHP script для сравнения схемы двух баз данных.

Мне удалось проверить изменения схемы в отношении упавших/добавленных таблиц, столбцов, индексов, ссылок, но когда дело доходит до переименованных столбцов, я немного застрял.

В следующем примере исходная база данных содержит самую современную схему, а база данных назначения содержит аналогичную схему, но, вероятно, устарела.

Предпосылки:

  • Мне не известны изменения, произошедшие со времени последнего разлома.
  • Данные в базах данных не будут совпадать, но схема должна после diff.

Возьмем, к примеру, следующую схему в базе данных назначения.

Field   Type    Null    Key Default Extra
field1  int(11) NO      NULL     
field2  int(11) NO      NULL     
field3  int(11) NO      NULL     

И затем предположим следующую схему в исходной базе данных.

Field   Type    Null    Key Default Extra
field1  int(11) NO      NULL     
field4  int(11) NO      NULL     
field3  int(11) NO      NULL     

Не зная, что произошло, я не могу определить, изменился ли field2 на field4 с помощью DROP, ADD AFTER или CHANGE COLUMN. Следующие два запроса достигают одного и того же результата с точки зрения структуры таблицы, но данные теряются с использованием первого.

(1)    ALTER TABLE `demo` DROP `field2`
       ALTER TABLE `demo` ADD `field4` INT( 11 ) NOT NULL AFTER `field1` 

(2)    ALTER TABLE `demo` CHANGE `field2` `field4` INT( 11 ) NOT NULL 

Я могу, очевидно, отказаться от старого имени столбца и создать новый, но затем терять любые данные в исходном столбце. Мне нужно использовать запрос ALTER TABLE table CHANGE COLUMN field new_name structure;, а не DROP column FROM table, за которым следует ALTER TABLE table ADD column definition;

Я надеялся, что могу использовать триггер DDL для отслеживания изменений в схеме и вставить запись таких изменений в таблицу в исходной базе данных. Я мог бы позже запросить эту таблицу, чтобы определить, как появился определенный столбец. Однако, насколько я могу судить, невозможно запускать триггеры в DDL-запросах в MySQL, что исключает регистрацию этих изменений. Я прочитал этот worklog (WL # 2418: Триггеры DDL) в MySQL Forge (теперь он находится в зоне разработки MySQL), но, похоже, это ожидаемая реализация все еще, к сожалению.

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

Я просмотрел такие вещи, как MySQLDiff, но он должен быть встроен в существующий бит кода, поэтому мне нужно построить это сам.

Идеи, которые я рассмотрел

  • Добавьте комментарий к каждому столбцу, который является уникальным номером или строкой (назовите это хэш для аргумента). Запросите таблицу information_schema для получения этого значения и сравните его с каждым столбцом. Если он уникален, то это новый столбец, или если он соответствует хешу, но не имя или структура, то он был переименован/реконфигурирован.

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

Ответ 1

Я не думаю, что вы должны синхронизировать схему таким образом. Вы должны проверять скрипты миграции на исходный код каждый раз, когда вы что-то меняете, а затем иметь таблицу в своей базе данных, которая регистрирует, какая миграция была применена. Таким образом, вы можете убедиться, что все миграции были применены ко всем базам данных. например `

CREATE TABLE `ddl_version` (
version` varchar(32)  NOT NULL,
`applied_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY `version` (`version`)

)`  

Ответ 2

ALTER TABLE table
 CHANGE COLUMN old_col_name
 new_col_name column_definition;

Это изменяет имя столбца, не теряя данные в столбце (если вы не измените тип данных, а новый тип данных меньше старого типа данных, например, изменив BIGINT на SMALLINT).

Эта команда, к сожалению, требует повторения текущего определения столбца, например. тип данных, NOT NULL и другие параметры. В MySQL нет команды для простого переименования столбца.

Предложение CHANGE COLUMN - это расширение MySQL для стандартного SQL, которое не содержит синтаксиса для переименования столбца на месте.

Другим решением, если вы хотите придерживаться стандартного SQL, является добавление нового столбца, копирование данных из старого столбца в новый столбец, а затем удаление старого столбца:

ALTER TABLE table ADD COLUMN new_col_name column_definition;

UPDATE table SET new_col_name = old_col_name;

ALTER TABLE table DROP COLUMN old_col_name;

Ответ 3

Самая большая проблема здесь заключается в том, что если было изменено более одного имени столбца (одного и того же типа) для одной и той же таблицы, нет способа определить, какой из столбцов был изменен на какой. (Может быть, есть возможность фактически сравнить данные и надеяться, что некоторые данные будут одинаковыми в обеих таблицах, таким образом, чтобы можно было определить, какой столбец изменился на что, но он будет полностью ненадежным)

Чем изменена проблема с 1 (или более) полем и добавлено 1 (или более), вы снова будете работать с тем же самым вопросом, что и выше.

MySQLDiff, упомянутый выше, сможет рассказать вам, какие поля являются новыми и старыми (и больше похожими на новые таблицы и т.д.), но он не сможет сказать вам, какое имя столбца было изменено на то, т даже пытаюсь. (Никакое программное обеспечение не может надежно сделать это, особенно если ваши данные не совпадают между db's) Вы можете увидеть, что он делает: mysql-1.5.0/library/database.lib.php и mysql-1.5.0/library/generator.lib.php

Одна вещь, которую я бы очень рекомендовал, представляет собой очень простой процесс в вашей команде разработчиков. - Каждый раз, когда выполняется изменение структуры db (или любые записи, которые необходимы для работы системы), следует записывать, например. db_changes.sql, который находится под управлением версиями. Для каждой новой ревизии, если необходимы такие изменения в db, файл db_changes.sql стирается, изменения записываются и сохраняются как новая ревизия. Таким образом, изменения в структуре базы данных должным образом пересматриваются, и их применение - это просто вопрос о двух точках пересмотра. (MysqlWorkbench - один из клиентов, который, если вы меняете таблицы, покажет вам запрос, который он будет выполнять внутри, если ваши разработчики должны вообще использовать клиента)

Ответ 4

MySQL не поддерживает триггеры DDL. В своем рабочем журнале я вижу, что они запланировали его для сервера 7.1.

Идентификатор задачи - WL # 2418.

Ответ 5

Невозможно обнаружить это, но если вам это нужно для вашей локальной машины, тогда есть способ сделать это.

  • Включить Общий журнал Mysql до table
  • Теперь все запросы будут сохранены в таблице mysql.general_log.
  • Теперь вы можете запустить такой запрос, как SELECT * FROM mysql.general_log WHERE argument LIKE 'ALTER%', чтобы предоставить вам все инструкции SQL, относящиеся к модификации базы данных, включая переименования столбцов.

Надеюсь, что это поможет.