Статьи

Совет: как постоянно изменять режим SQL в MySQL

Недавно я работал над устаревшим проектом, и мне нужно было импортировать некоторые данные из MySQL 5.5. Все запросы в коде отлично работали в MySQL 5.5, поэтому я предположил, что обновление до 5.7 будет беспроблемным. Не так.

Логотип MySQL

Сначала я получил ошибки из-за заполнения столбцов DateTime нулями во время импорта, а затем при выполнении этого запроса:

select * from ebay_order_items where z_shipmentno is null and ExternalTransactionID is not null and orderstatus = 'Completed' and timestamp > '2015-02-25' group by ExternalTransactionID order by timestamp desc 

Я получил это:

 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column '1066export.ebay_order_items.TransactionID' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by 

Оказалось, что режим only_full_group_by был установлен по умолчанию в версии 5.7.5., only_full_group_by нарушает многие из таких наивных запросов. На самом деле, смотрите здесь для получения дополнительной информации.

Я мог бы переписать все запросы, чтобы они были 5.7-совместимыми (как подсказку Джорджу Фекете для решения), и сделать что-то столь же ужасное, как это:

 select extf . * from ( select ExternalTransactionID from ebay_order_items where ExternalTransactionID is not null group by ExternalTransactionID ) extf JOIN ebay_order_items eoi ON ( eoi . ExternalTransactionID = extf . ExternalTransactionID ) where eoi . z_shipmentno is null and eoi . orderstatus = 'Completed' and eoi . timestamp > '2015-02-25' order by eoi . timestamp desc 

… но это сделало бы и без того сложный рефакторинг гораздо более сложным. Было бы намного лучше временно отключить эти проверки и заставить MySQL действовать так же, как в 5.6.

Постоянно меняющийся режим SQL

Сначала мы выясняем, какой конфигурационный файл предпочитает наша установка MySQL. Для этого нам нужно местоположение двоичного файла:

 $ which mysqld /usr/sbin/mysqld 

Затем мы используем этот путь для выполнения поиска:

 $ /usr/sbin/mysqld --verbose --help | grep -A 1 "Default options" Default options are read from the following files in the given order: /etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf 

Мы видим, что первый предпочитаемый файл конфигурации находится в корне папки etc Однако этого файла не было в моей системе, поэтому я выбрал второй.

Сначала мы узнаем текущий режим sql:

 mysql -u homestead -psecret -e "select @@sql_mode" +-------------------------------------------------------------------------------------------------------------------------------------------+ | @@sql_mode | +-------------------------------------------------------------------------------------------------------------------------------------------+ | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | +-------------------------------------------------------------------------------------------------------------------------------------------+ 

Затем мы копируем текущую строку, созданную этим запросом, и удаляем все, что нам не нравится. В моем случае мне нужно было избавиться от NO_ZERO_IN_DATE , NO_ZERO_DATE и, конечно, ONLY_FULL_GROUP_BY . Вновь сформированная строка выглядит следующим образом:

 STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 

Мы открываем файл конфигурации, который мы определили ранее ( /etc/mysql/my.cnf ), и добавляем следующую строку в раздел [mysqld] :

 [mysqld] # ... other stuff will probably be here sql_mode = "STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION" 

Сохраните, выйдите и перезапустите MySQL:

 sudo service mysql restart 

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