RussianLDP Рейтинг@Mail.ru
WebMoney: 
WMZ Z294115950220 
WMR R409981405661 
WME E134003968233 
YandexMoney: 
41001198119846 
E-gold:
5128052

Глава 14. Синтаксис SQL

Эта глава описывает синтаксис для запросов SQL в MySQL.

14.1. Запросы определения данных

14.1.1. ALTER DATABASE

ALTER {DATABASE | SCHEMA} [db_name]
alter_specification ...

alter_specification:
[DEFAULT] CHARACTER SET [=] charset_name
    | [DEFAULT] COLLATE [=] collation_name
ALTER DATABASE позволяет Вам изменить полные характеристики базы данных. Эти характеристики сохранены в словаре данных. Чтобы использовать ALTER DATABASE, нужна привилегия ALTER на базе данных. ALTER SCHEMA синоним ALTER DATABASE .

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

Национальные языковые характеристики

CHARACTER SET изменяет набор символов базы данных по умолчанию. COLLATE изменяет сопоставление базы данных по умолчанию. Раздел 11.1 обсуждает имена сопоставления и набор символов.

Вы можете видеть, какие наборы символов и сопоставления доступны, соответственно, через SHOW CHARACTER SET и SHOW COLLATION. См. разделы 14.7.5.3 и 14.7.5.4.

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

14.1.2. ALTER EVENT

ALTER
[DEFINER = { user | CURRENT_USER }]
EVENT event_name
[ON SCHEDULE schedule]
[ON COMPLETION [NOT] PRESERVE]
[RENAME TO new_event_name]
[ENABLE | DISABLE | DISABLE ON SLAVE]
[COMMENT 'comment']
[DO event_body]
ALTER EVENT изменяет одну или больше характеристик существующего события без потребности обновить это. Синтаксис для DEFINER, ON SCHEDULE, ON COMPLETION, COMMENT, ENABLE / DISABLE и DO точно тот же самый, как с CREATE EVENT. См. раздел 14.1.10.

Любой пользователь может изменить событие, определенное в базе данных, для которой этот пользователь имеет привилегию EVENT. Когда пользователь выполняет успешный запрос ALTER EVENT, этот пользователь становится определителем для затронутого события.

ALTER EVENT работает только с существующим событием:

mysql> ALTER EVENT no_such_event
     > ON SCHEDULE
     >    EVERY '2:3' DAY_HOUR;
ERROR 1517 (HY000): Unknown event 'no_such_event'
В каждом из следующих примеров, предположите, что событие называется myevent и определено, как показано здесь:
CREATE EVENT myevent ON SCHEDULE EVERY 6 HOUR
       COMMENT 'A sample comment.' DO
       UPDATE myschema.mytable SET mycol = mycol + 1;
Следующий запрос изменяет график для myevent с однажды каждые шесть часов с немедленным стартом на однажды каждые двенадцать часов, запускаясь четыре часа со времени выполнения запроса:
ALTER EVENT myevent ON SCHEDULE EVERY 12 HOUR
      STARTS CURRENT_TIMESTAMP + INTERVAL 4 HOUR;
Возможно изменить многократные характеристики в единственном запросе. Этот пример изменяет запрос SQL, выполненный myevent к тому, который удаляет все записи из mytable, это также изменяет график, таким образом, что это выполняется однажды, спустя один день после этого ALTER EVENT.
ALTER EVENT myevent ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY
      DO TRUNCATE TABLE myschema.mytable;
Определите опции в ALTER EVENT только для тех характеристик, которые Вы хотите изменить, пропущенные опции сохраняют свои существующие значения. Это включает любые значения по умолчанию для CREATE EVENT, например, ENABLE.

Чтобы выключить myevent, используйте ALTER EVENT:

ALTER EVENT myevent DISABLE;
ON SCHEDULE может использовать выражения, вовлекающие встроенные функции MySQL и пользовательские переменные, чтобы получить любое из значений timestamp или interval, которые это содержит. Вы не можете использовать сохраненные подпрограммы или определяемые пользователем функции в таких выражениях, и Вы не можете использовать табличные ссылки, однако, Вы можете использовать SELECT FROM DUAL. Это верно для ALTER EVENT и CREATE EVENT. Ссылки на сохраненные подпрограммы, определяемые пользователем функции и таблицы в таких случаях определенно не разрешены и терпят неудачу с ошибкой (см. Bug #22830).

Хотя ALTER EVENT, который содержит другой ALTER EVENT в DO, кажется, преуспевает, когда сервер пытается запустить получающееся запланированное событие, выполнение терпит неудачу с ошибкой.

Чтобы переименовать событие, используйте ALTER EVENT RENAME TO. Это запрос переименовывает myevent в yourevent:

ALTER EVENT myevent RENAME TO yourevent;
Вы можете также переместить событие в иную базу данных через ALTER EVENT ... RENAME TO ... с db_name.event_name:
ALTER EVENT olddb.myevent RENAME TO newdb.myevent;
Чтобы выполнить предыдущий запрос, пользователь, выполняющий это, должен иметь привилегию EVENT на обоих базах данных olddb и newdb.

Запроса RENAME EVENT нет.

DISABLE ON SLAVE используется на ведомом устройстве вместо ENABLE или DISABLE, чтобы указать на событие, которое создавалось на ведущем устройстве и копировалось к ведомому устройству, но это не выполнено на ведомом устройстве. Обычно DISABLE ON SLAVE установлен автоматически как требуется, однако, есть некоторые обстоятельства, при которых Вы можете хотеть или должны изменить это вручную. См. раздел 19.4.1.12.

14.1.3. ALTER FUNCTION

ALTER FUNCTION func_name [characteristic ...]
characteristic:
COMMENT 'string'
  | LANGUAGE SQL
  | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }
Это запрос может использоваться, чтобы изменить характеристики сохраненной функции. Больше чем одно изменение может быть определено в ALTER FUNCTION. Однако, Вы не можете изменить параметры или тело сохраненной функции, используя это запрос, чтобы произвести такие изменения, Вы должны обновить функцию через DROP FUNCTION и CREATE FUNCTION.

Вы должны иметь привилегию ALTER ROUTINE для функции (предоставляется автоматически создателю). Если двоичное журналирование включено, ALTER FUNCTION может также потребовать привилегию SUPER, см. раздел 21.7.

14.1.4. ALTER INSTANCE

ALTER INSTANCE ROTATE INNODB MASTER KEY
ALTER INSTANCE определяет действия, применимые к серверу MySQL. Требует привилегии SUPER .

ALTER INSTANCE ROTATE INNODB MASTER KEY используется для ротации основного ключа шифрования, используемого для InnoDB. Плагин keyring должен быть загружен, чтобы использовать этот запрос. По умолчанию сервер MySQL загружает плагин keyring_file.

ALTER INSTANCE ROTATE INNODB MASTER KEY поддерживает параллельный DML. Однако, это не может быть выполнено одновременно с CREATE TABLE ... ENCRYPTION или ALTER TABLE ... ENCRYPTION, и блокировки взяты, чтобы предотвратить конфликты, которые могли явиться результатом параллельного выполнения этих запросов. Если один из противоречивых запросов работает, он должен завершиться прежде, чем другой может продолжиться.

ALTER INSTANCE записан в двоичный журнал так, чтобы он мог быть выполнен на копируемых серверах.

14.1.5. ALTER PROCEDURE

ALTER PROCEDURE proc_name [characteristic ...]
characteristic:
COMMENT 'string'
  | LANGUAGE SQL
  | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }
Этот запрос может использоваться, чтобы изменить характеристики хранимой процедуры. Больше чем одно изменение может быть определено в ALTER PROCEDURE. Однако, Вы не можете изменить параметры или тело хранимой процедуры, используя этот запрос, здесь нужно применить DROP PROCEDURE и CREATE PROCEDURE.

Вы должны иметь привилегию ALTER ROUTINE для процедуры. По умолчанию эту привилегию предоставляют автоматически создателю процедуры. Это поведение может быть изменено, отключая automatic_sp_privileges. См. раздел 21.2.2.

14.1.6. ALTER SERVER

ALTER SERVER  server_name
OPTIONS (option [, option] ...)
Меняет информацию сервера для server_name, корректируя любую из опций, разрешенных в CREATE SERVER. Соответствующие области в mysql.servers обновлены соответственно. Этот запрос требует привилегии SUPER.

Например, чтобы обновить USER:

ALTER SERVER s OPTIONS (USER 'sally');
ALTER SERVER не вызывает автоматическое завершение транзакции.

В MySQL 8.0 ALTER SERVER не записан в двоичный журнал, независимо от формата журналирования, который используется.

14.1.7. ALTER TABLE

ALTER TABLE tbl_name
[alter_specification [, alter_specification] ...]
[partition_options]

alter_specification:
table_options
  | ADD [COLUMN] col_name column_definition
[FIRST | AFTER col_name ]
  | ADD [COLUMN] (col_name column_definition,...)
  | ADD {INDEX|KEY} [index_name]
[index_type] (index_col_name,...) [index_option] ...
  | ADD [CONSTRAINT [symbol]] PRIMARY KEY
[index_type] (index_col_name,...) [index_option] ...
  | ADD [CONSTRAINT [symbol]]
UNIQUE [INDEX|KEY] [index_name]
[index_type] (index_col_name,...) [index_option] ...
  | ADD FULLTEXT [INDEX|KEY] [index_name]
(index_col_name,...) [index_option] ...
  | ADD SPATIAL [INDEX|KEY] [index_name]
(index_col_name,...) [index_option] ...
  | ADD [CONSTRAINT [symbol]]
FOREIGN KEY [index_name] (index_col_name,...)
reference_definition
  | ALGORITHM [=] {DEFAULT|INPLACE|COPY}
  | ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT}
  | CHANGE [COLUMN] old_col_name new_col_name column_definition
[FIRST|AFTER col_name]
  | LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}
  | MODIFY [COLUMN] col_name column_definition
[FIRST | AFTER col_name]
  | DROP [COLUMN] col_name
  | DROP PRIMARY KEY
  | DROP {INDEX|KEY} index_name
  | DROP FOREIGN KEY fk_symbol
  | ALTER INDEX index_name {VISIBLE | INVISIBLE}
  | DISABLE KEYS
  | ENABLE KEYS
  | RENAME [TO|AS] new_tbl_name
  | RENAME {INDEX|KEY} old_index_name TO new_index_name
  | ORDER BY col_name [, col_name] ...
  | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]
  | [DEFAULT] CHARACTER SET [=] charset_name [COLLATE [=] collation_name]
  | DISCARD TABLESPACE
  | IMPORT TABLESPACE
  | FORCE
  | {WITHOUT|WITH} VALIDATION
  | ADD PARTITION (partition_definition)
  | DROP PARTITION partition_names
  | DISCARD PARTITION {partition_names | ALL} TABLESPACE
  | IMPORT PARTITION {partition_names | ALL} TABLESPACE
  | TRUNCATE PARTITION {partition_names | ALL}
  | COALESCE PARTITION number
  | REORGANIZE PARTITION partition_names INTO (partition_definitions)
  | EXCHANGE PARTITION partition_name WITH TABLE tbl_name [{WITH|WITHOUT} VALIDATION]
  | ANALYZE PARTITION {partition_names | ALL}
  | CHECK PARTITION {partition_names | ALL}
  | OPTIMIZE PARTITION {partition_names | ALL}
  | REBUILD PARTITION {partition_names | ALL}
  | REPAIR PARTITION {partition_names | ALL}
  | REMOVE PARTITIONING
  | UPGRADE PARTITIONING

index_col_name:
col_name [(length)] [ASC | DESC]

index_type:
USING {BTREE | HASH}

index_option:
KEY_BLOCK_SIZE [=] value
  | index_type
  | WITH PARSER parser_name
  | COMMENT 'string'
  | {VISIBLE | INVISIBLE}

table_options:
table_option [[,] table_option] ...
(см. опции CREATE TABLE)

partition_options:
(см. опции CREATE TABLE)
ALTER TABLE изменяет структуру таблицы. Например, Вы можете добавить или удалить столбцы, создать или разрушить индекс, изменить тип существующих столбцов, переименовать столбцы или таблицу непосредственно. Вы можете также изменить характеристики, такие как механизм хранения, используемый для таблицы или табличного комментария.

После имени таблицы, определите изменения, которые будут сделаны. Если ни одно не дано, ALTER TABLE ничего не делает.

Синтаксис для многих из допустимых изменений подобен параметрам CREATE TABLE. См. раздел 14.1.15.

table_options показывает табличные опции вида, который может использоваться в CREATE TABLE, например, ENGINE, AUTO_INCREMENT, AVG_ROW_LENGTH, MAX_ROWS, ROW_FORMAT или TABLESPACE. Для списка всех табличных опций и описания каждой см. раздел 14.1.15. Однако, ALTER TABLE игнорирует опции DATA DIRECTORY и INDEX DIRECTORY.

Использование табличных опций с ALTER TABLE обеспечивает удобный способ изменить единственные табличные характеристики. Например, если t1 сейчас не таблица InnoDB, этот запрос изменяет механизм хранения на InnoDB:

ALTER TABLE t1 ENGINE = InnoDB;
Изменить InnoDB, чтобы использовать на сжатый формат хранения строки:
ALTER TABLE t1 ROW_FORMAT = COMPRESSED;
Если опция шифрования табличного пространства активирована (см. раздел 16.7.10), шифрование для t1 может быть включено или отключено:
ALTER TABLE t1 ENCRYPTION='Y';
ALTER TABLE t1 ENCRYPTION='N';
Чтобы отключить шифрование для InnoDB, установите ENCRYPTION='N', используя ALTER TABLE.

Сбрасывать текущее значение auto-increment:

ALTER TABLE t1 AUTO_INCREMENT = 13;
Изменить табличный набор символов по умолчанию:
ALTER TABLE t1 CHARACTER SET = utf8;
Добавить (или изменить) табличный комментарий:
ALTER TABLE t1 COMMENT = 'New table comment';
Чтобы проверить, что табличные опции были изменены, удобно использовать SHOW CREATE TABLE.

partition_options показывает опции, которые могут использоваться с разделенными таблицами для того, чтобы повторно разделить, добавить, удалить, импортировать, слить и разделить разделение, и для того, чтобы выполнить обслуживание разделения. Это возможно для ALTER TABLE, который включает параметр PARTITION BY или REMOVE PARTITIONING, который должен быть определен последним после любых других технических требований. ADD PARTITION, DROP PARTITION, DISCARD PARTITION, IMPORT PARTITION, COALESCE PARTITION, REORGANIZE PARTITION, EXCHANGE PARTITION, ANALYZE PARTITION, CHECK PARTITION и REPAIR PARTITION не могут быть объединены с другими изменениями технических требований в ALTER TABLE, так как опции только перечислены на отдельном разделе. Для получения дополнительной информации об опциях разделения см. разделы 14.1.15 и 14.1.7.1.

До MySQL 5.7.6 разделенные таблицы InnoDB использовали непатентованное средство ha_partition в качестве обработчика, используемого MyISAM и другими механизмами хранения, не поставляющих их собственные обработчики разделения, в MySQL 5.7.6 и позже такие таблицы составлены, используя собственный обработчик механизма хранения InnoDB. После MySQL 5.7.9 Вы можете обновить таблицу InnoDB, которая была составлена в MySQL 5.7.6 или ранее (то есть, с ha_partition) на InnoDB, используя ALTER TABLE ... UPGRADE PARTITIONING (Bug #76734, Bug #20727344). Эта версия ALTER TABLE не принимает никакие другие опции и может использоваться только на единственной таблице за один раз.

Вы можете также использовать mysql_upgrade, чтобы обновить более старые разделенные таблицы InnoDB.

Некоторые операции могут привести к предупреждениям, если предприняты на таблице, для которой механизм хранения не поддерживает такую работу. Эти предупреждения могут быть выведены на экран SHOW WARNINGS. См. раздел 14.7.5.40.

Для информации о поиске неисправностей ALTER TABLE см. раздел B.5.6.1.

Хранение, работа и соображения параллелизма

В большинстве случаев ALTER TABLE делает временную копию оригинальной таблицы. MySQL ждет других операций, которые изменяют таблицу, затем продолжается. Это включает изменение в копию, удаляет оригинальную таблицу и переименовывает новую. В то время как ALTER TABLE выполняется, оригинальная таблица читаема другими сеансами. Обновления и записи таблицы, которые начинаются после ALTER TABLE остановлены, пока новая таблица не готова, затем автоматически перенаправлена к новой таблице без любых неудавшихся обновлений. Временная копия оригинальной таблицы создается в каталоге базы данных новой таблицы. Это может отличаться от каталога базы данных оригинальной таблицы для ALTER TABLE, которые переименовывают таблицу к иной базе данных.

Исключение, упомянутое ранее, это блокировка чтения ALTER TABLE (не только записи) в пункте, где это готово очистить устаревшие структуры таблиц от таблицы и табличных кэшей определения. В этом пункте это должно приобрести исключительную блокировку. Чтобы сделать так, это ждет завершения текущих чтений и блокирует новые чтения и записи.

Для таблиц MyISAM Вы можете убыстрить воссоздание индекса (самая медленная часть процесса изменения), устанавливая к высокому значению myisam_sort_buffer_size.

Для некоторых операций, оперативное выполнение ALTER TABLE возможно, которое не требует временной таблицы:

  • ALTER TABLE tbl_name RENAME TO new_tbl_name без любых других опций MySQL просто переименовывает любые файлы, которые соответствуют таблице tbl_name. Вы можете также использовать RENAME TABLE, чтобы переименовать таблицы. См. раздел 14.1.29. Любые привилегии, предоставленные определенно для переименованной таблицы, не мигрируются к новому имени. Они должны быть изменены вручную.

  • Изменения, которые изменяют только табличные метаданные и не табличные данные, являются немедленными, потому что сервер должен только изменить табличные метаданные, не табличное содержание. Следующие изменения быстрые:

    • Переименование столбца.

    • Изменение значения по умолчанию столбца.
    • Изменение определения ENUM или SET, добавляя новое перечисление или членов набора в конец списка допустимых членских значений, пока размер хранения типа данных не изменяется. Например, добавление участника к SET, у которого есть 8 участников, изменяет необходимое хранение для значения от 1 байта до 2 байтов, это потребует табличной копии. Добавление участников в середине изменения нумерации списка существующих участников, тоже требует табличной копии.

  • ALTER TABLE с DISCARD ... PARTITION ... TABLESPACE или IMPORT ... PARTITION ... TABLESPACE не составляют временные таблицы или временные файлы разделения.

    ALTER TABLE с ADD PARTITION, DROP PARTITION, COALESCE PARTITION, REBUILD PARTITION или REORGANIZE PARTITION не составляют временных таблиц (кроме тех случаев, когда используется с таблицами NDB), однако, эти операции могут действительно создавать временные файлы разделения.

    ADD или DROP для разделений типов RANGE или LIST непосредственные операции. ADD или COALESCE для HASH или KEY не копирует данные между всеми разделами, если применено LINEAR HASH или LINEAR KEY, это имеет тот же самый эффект, как составление новой таблицы, хотя ADD или COALESCE работают по разделам. REORGANIZE копирует только измененный раздел и не касается неизменных.

  • Переименование индекса.
  • Добавление или удаление индексирования для InnoDB.
  • Изменение видимости индекса с ALTER INDEX.

Вы можете предписать ALTER TABLE работу, которая иначе не потребовалась бы, чтобы табличная копия использовала временный табличный метод (как поддержано в MySQL 5.0), устанавливая old_alter_table в ON, или указав параметр ALGORITHM=COPY в alter_specification. Если есть конфликт между old_alter_table и параметром ALGORITHM со значением кроме DEFAULT, ALGORITHM имеет приоритет. ALGORITHM=DEFAULT аналогичен отсутствию ALGORITHM вовсе.

Определение ALGORITHM=INPLACE заставляет использовать оперативный метод для пунктов и механизмов хранения, которые поддерживают это, и приводит к ошибке иначе, таким образом избегая длинной табличной копии, если Вы пытаетесь изменить таблицу, которая использует иной механизм хранения, чем Вы ожидаете. См. раздел 16.12.

Для таблиц InnoDB копирование ALTER TABLE на таблице, которая находится в совместно используемом табличном пространстве, таком как общее табличное пространство или системное табличное пространство может увеличить количество пространства, использованного табличным пространством. Такие операции требуют такого большого количества дополнительного пространства, как данные в таблице плюс индекс. Для таблицы, которая находится в совместно используемом табличном пространстве, дополнительное пространство, используемое во время копирования таблицы ALTER TABLE не выпущено назад к операционной системе, как для таблицы, которая находится в табличном пространстве file-per-table.

С MySQL 5.7.4 ALTER TABLE обновляет временные столбцы MySQL 5.5 до формата 5.6 для ADD COLUMN, CHANGE COLUMN, MODIFY COLUMN, ADD INDEX и FORCE. Это преобразование не может быть сделано, используя алгоритм INPLACE, потому что таблица должна быть восстановлена, таким образом, определение ALGORITHM=INPLACE в этих случаях приводит к ошибке. Определите ALGORITHM=COPY в случае необходимости.

С MySQL 5.7.6 ALTER TABLE на многостолбцовом индексе используемом, чтобы разделить таблицу по KEY не может быть выполнен онлайн, когда работа изменила бы порядок столбцов. В таких случаях Вы должны использовать копирование ALTER TABLE (Bug #17896265).

Вы можете управлять уровнем параллельного чтения и записи таблицы, в то время как это изменяется, используя параметр LOCK. Определение значения не по умолчанию для этого пункта позволяет Вам требовать определенного количества параллельного доступа или исключительности во время изменений и останавливает работу, если требуемая степень блокировки недоступна. Параметры для LOCK:

  • LOCK = DEFAULT
    
    Максимальный уровень параллелизма для данного ALGORITHM (если есть) и ALTER TABLE: допускает параллельные чтения и записи, если поддержаны. В противном случае разрешает параллельные чтения, если поддержано. В противном случае проводит в жизнь эксклюзивный доступ.
  • LOCK = NONE
    
    Если поддержано, разрешит параллельные чтения и записи. Иначе, возвратит сообщение об ошибке.
  • LOCK = SHARED
    
    Если поддержано, разрешите параллельные чтения, но блокирует записи. Отметьте, что запись будет заблокирована, даже если параллельные записи поддержаны механизмом хранения для данного ALGORITHM (если есть) и ALTER TABLE. Если параллельные чтения не поддержаны, возвратит сообщение об ошибке.
  • LOCK = EXCLUSIVE
    
    Проведет в жизнь эксклюзивный доступ. Это будет сделано, даже если параллельные чтения и записи поддержаны механизмом хранения для данного ALGORITHM (если есть) и ALTER TABLE.

WITHOUT VALIDATION и WITH VALIDATION затрагивают ALTER TABLE, если он выполняет оперативную работу для модификаций произведенных виртуальных столбцов. См. раздел 14.1.7.2.

Вы можете также использовать ALTER TABLE tbl_name FORCE, чтобы выполнить null-работу, которая восстанавливает таблицу. Для получения дополнительной информации см. раздел 16.12.1.

Примечания использования

  • Чтобы использовать ALTER TABLE , нужны привилегии ALTER, CREATE и INSERT для таблицы. Переименование таблицы требует ALTER и DROP на старой таблице, ALTER, CREATE и INSERT на новой.

  • table_option показывает табличную опцию вида, который может использоваться в CREATE TABLE, например, в ENGINE, AUTO_INCREMENT, AVG_ROW_LENGTH, MAX_ROWS, ROW_FORMAT или TABLESPACE. См. раздел 14.1.15. Но ALTER TABLE игнорирует табличные опции DATA DIRECTORY и INDEX DIRECTORY.

    • Например, чтобы преобразовать таблицу в InnoDB:

      ALTER TABLE t1 ENGINE = InnoDB;
      
      См. раздел 16.8.4 для соображений переключения таблицы на InnoDB.

      Когда Вы определяете параметр ENGINE, ALTER TABLE пересоздает таблицу. Это истина, даже если у таблицы уже есть указанный механизм хранения.

      Запуск ALTER TABLE tbl_name ENGINE=INNODB на существующей таблице InnoDB выполняет null ALTER TABLE, что можно использовать для дефрагментации таблицы, см. раздел 16.11.4. Запуск ALTER TABLE tbl_name FORCE на таблице InnoDB выполняет ту же самую функцию.

      ALTER TABLE tbl_name ENGINE=INNODB и ALTER TABLE tbl_name FORCE применяют online DDL (ALGORITHM=COPY). См. раздел 16.12.1.

      Результат попытки изменить механизм хранения таблицы затронут тем, доступен ли желаемый механизм хранения, и установкой режима SQL NO_ENGINE_SUBSTITUTION, см. раздел 6.1.8.

      Чтобы предотвратить потерю данных, ALTER TABLE не может использоваться, чтобы изменить механизм хранения таблицы к MERGE или BLACKHOLE.

    • Чтобы изменить значение AUTO_INCREMENT для новых строк:
      ALTER TABLE t2 AUTO_INCREMENT = value;
      
      Вы не можете сбросить счетчик к значению меньше или равным значению, которое используется в настоящее время. Для InnoDB и MyISAM, если значение в настоящее время меньше или равно максимальному значению в столбце AUTO_INCREMENT, значение сброшено к текущему максимуму AUTO_INCREMENT+1.
    • Вы можете использовать ALTER TABLE с TABLESPACE , чтобы переместить неразделенные таблицы InnoDB между существующими общими табличными пространствами, табличными пространствами file-per-table и системным табличным пространством.

      Для разделенных таблиц ALTER TABLE tbl_name TABLESPACE [=] tablespace_name только изменяет табличное пространство по умолчанию таблицы. Это не перемещает разделение от одного табличного пространства в другое. Чтобы переместить табличное разделение, Вы должны переместить каждый раздел, используя ALTER TABLE tbl_name REORGANIZE PARTITION.

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

      ALTER TABLE ... TABLESPACE не поддерживает перемещение таблицы от временного табличного пространства в постоянное.

      DATA DIRECTORY, который поддержан с CREATE TABLE ... TABLESPACE, не поддержан с ALTER TABLE ... TABLESPACE и проигнорирован, если определен.

  • Вы можете использовать несколько ADD, ALTER, DROP и CHANGE в одном ALTER TABLE, отделенных запятыми. Это расширение MySQL к стандартному SQL, который разрешает только один из каждого типа параметра за запрос ALTER TABLE. Например, чтобы удалить много столбцов в единственном запросе, сделайте это:
    ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;
    
  • CHANGE col_name, DROP col_name и DROP INDEX расширения MySQL к стандартному SQL.
  • COLUMN является дополнительным и может быть пропущено.
  • column_definition использует тот же самый синтаксис для ADD и CHANGE как в CREATE TABLE. См. раздел 14.1.15.
  • Для информации о произведенных столбцах см. раздел 14.1.7.2.
  • Вы можете переименовать столбец, используя CHANGE old_col_name new_col_name column_definition. Чтобы сделать так, определите старые и новые имена столбцов и определение, которое в настоящее время имеет столбец. Например, чтобы переименовать INTEGER из a в b:
    ALTER TABLE t1 CHANGE a b INTEGER;
    
    Чтобы изменить тип столбца, но не имя, CHANGE все еще требует старого и нового имени столбца, даже если они одинаковы:
    ALTER TABLE t1 CHANGE b b BIGINT NOT NULL;
    
    Вы можете также использовать MODIFY, чтобы изменить тип столбца, не переименовывая это:
    ALTER TABLE t1 MODIFY b BIGINT NOT NULL;
    

    MODIFY расширение ALTER TABLE для совместимости с Oracle.

    Когда Вы используете CHANGE или MODIFY, column_definition должен включать тип данных и все признаки, которые должны относиться к новому столбцу, кроме индексных признаков вроде PRIMARY KEY или UNIQUE. Признаки, существующие в оригинальном определении, но не определенные для нового определения, не применены. Предположите, что столбец col1 определен как INT UNSIGNED DEFAULT 1 COMMENT 'my column', и Вы изменяете столбец следующим образом:

    ALTER TABLE t1 MODIFY col1 BIGINT;
    
    Получающийся столбец будет определен как BIGINT, но не будет включать признаки UNSIGNED DEFAULT 1 COMMENT 'my column'. Чтобы сохранить их, запрос должен быть:
    ALTER TABLE t1 MODIFY col1 BIGINT UNSIGNED DEFAULT 1 COMMENT 'my column';
    
  • Когда Вы изменяете использование типа данных через CHANGE или MODIFY, MySQL пытается преобразовать существующие значения столбцов в новый тип так, как возможно.

    Это преобразование может привести к изменению данных. Например, если Вы сокращаете строковый столбец, значения могут быть усеченными. Чтобы препятствовать этому, если бы преобразования в новый тип данных привело бы к потере данных, включите строгий режим SQL перед использованием ALTER TABLE (см. раздел 6.1.8).

  • Чтобы добавить столбец в определенной позиции в пределах строки таблицы, надо использовать FIRST или AFTER col_name . Значение по умолчанию должно добавить последний столбец. Вы можете также использовать FIRST и AFTER в CHANGE или MODIFY, чтобы переупорядочить столбцы в пределах таблицы.
  • ALTER ... SET DEFAULT или ALTER ... DROP DEFAULT определит новое значение по умолчанию для столбца или удалит старое значение по умолчанию, соответственно. Если старое значение по умолчанию удалено, и столбец может быть NULL, новое значение по умолчанию NULL. Если столбец не может быть NULL, MySQL назначает значение по умолчанию как описано в разделе 12.7.
  • DROP INDEX удаляет индекс. Это расширение MySQL к стандартному SQL. См. раздел 14.1.22. Если Вы неуверены в имени индекса, надо использовать SHOW INDEX FROM tbl_name.
  • Если столбцы исключены из таблицы, столбцы также удалены из любого индекса. Если все столбцы, которые составляют индекс, удалены, индекс удален также. Если Вы используете CHANGE или MODIFY, чтобы сократить столбец, для которого индекс существует на столбце, и получающаяся длина столбца меньше, чем длина индекса, MySQL сокращает индексирование автоматически.
  • Если таблица содержит только один столбец, он не может быть удален. Если то, что Вы предназначаете, должно удалить таблицу, надо использовать команду DROP TABLE.
  • DROP PRIMARY KEY удаляет primary key. Если нет никакого первичного ключа, ошибка происходит. Для информации о технических характеристиках первичных ключей, специально для InnoDB, см. раздел 9.3.2.

    Если Вы добавляете UNIQUE INDEX или PRIMARY KEY, MySQL хранит это прежде, чем любой групповой индекс, чтобы обнаружить дубликаты ключа как можно раньше.

  • Некоторые механизмы хранения разрешают Вам определять тип индекса, создавая индексирование. Синтаксис для index_type: USING type_name. См. раздел 14.1.12. Привилегированная позиция после списка столбца. Поддержка использования опции перед списком столбца будет удалена в будущем выпуске MySQL.

    index_option определяют дополнительные опции для индексирования. USING одна такая опция. Для деталей о допустимых значениях index_option см. раздел 14.1.12.

  • RENAME INDEX old_index_name TO new_index_name переименовывает индекс. Это расширение MySQL к стандартному SQL. Контент таблицы остается неизменным. old_index_name должно быть названием существующего индекса в таблице, которая не удалена тем же самым ALTER TABLE. new_index_name новое индексное имя, которое не может дублировать название индексирования в получающейся таблице после того, как изменения были применены. Ни одно имя индекса не может быть PRIMARY.
  • После ALTER TABLE может быть необходимо выполнить ANALYZE TABLE, чтобы обновить индексируют информацию о количестве элементов. См. раздел 14.7.5.22.
  • ORDER BY позволяет Вам составить новую таблицу со строками в определенном порядке. Эта опция полезна прежде всего, когда Вы знаете, что должны главным образом запросить строки в определенном порядке большую часть времени. При использовании этой опции после существенных изменений таблицы Вы могли бы быть в состоянии получить более высокую производительность. В некоторых случаях, это могло бы сделать сортировку легче для MySQL, если таблица в порядке столбцов, которым Вы хотите упорядочить это позже.

    Таблица не остается в указанном порядке после вставок и удалений.

    ORDER BY разрешает одному или более именам столбцов быть определенными для того, чтобы быть критерием сортировки, каждый из которых произвольно может сопровождаться ASC или DESC, чтобы указать на сортировку по возрастанию или сортировку по убыванию, соответственно. Значение по умолчанию: по возрастанию. Только имена столбцов разрешены как критерии сортировки, произвольные выражения не разрешены. Этот параметр должен быть дан последним после любых других.

    ORDER BY не имеет смысла для InnoDB, потому что InnoDB всегда обрабатывает строки таблицы согласно кластеризируемому индексу.

    Когда используется на разделенной таблице, ALTER TABLE ... ORDER BY сортирует строки только в пределах каждого раздела.

  • ALTER INDEX разрешает индексированию быть сделанным видимым или невидимым. Невидимый индекс не используется оптимизатором. Модификация невидимости относится к индексам кроме первичных ключей (явных или неявных). С MySQL 8.0.1 эта особенность поддержана для любого механизма хранения. В MySQL 8.0.0 это применяется только к InnoDB. См. раздел 9.3.10.

  • Если Вы используете ALTER TABLE на MyISAM, все групповые индексы создаются в отдельном пакете (как для REPAIR TABLE). Это должно сделать ALTER TABLE намного быстрее, когда Вы имеете много индексов.

    Для MyISAM ключевым обновлением можно управлять явно. Используйте ALTER TABLE ... DISABLE KEYS, чтобы сказать MySQL прекратить обновлять групповой индекс. Затем примените ALTER TABLE ... ENABLE KEYS для пересоздания потерянных индексов. MyISAM делает это со специальным алгоритмом, который намного быстрее, чем вставка ключей один за другим, так что отключение ключей прежде, чем вставить много данных, должно дать значительное ускорение. Использование ALTER TABLE ... DISABLE KEYS требует привилегию INDEX в дополнение к привилегиям, упомянутым ранее.

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

  • В MySQL 8.0 сервер запрещает изменения столбцов внешнего ключа, у которых есть потенциал, чтобы вызвать потерю справочной целостности. Это также запрещает изменения типа данных таких столбцов, которые могут быть опасными. Например, изменение VARCHAR(20) на VARCHAR(30) разрешено, но изменение этого к VARCHAR(1024) нет, потому что это изменяет число байтов длины, требуемых, чтобы сохранить отдельные значения. Обходное решение должно использовать ALTER TABLE ... DROP FOREIGN KEY прежде, чем изменить определение столбца и ALTER TABLE ... ADD FOREIGN KEY после.
  • FOREIGN KEY и REFERENCES поддержаны InnoDB, который осуществляет ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (...) REFERENCES ... (...). См. раздел 16.8.6. Для других механизмов хранения параметры разобраны, но проигнорированы. CHECK разобран, но проигнорирован всеми механизмами хранения. См. раздел 14.1.15. Причина того, чтобы принять, но проигнорировать пункты синтаксиса: для совместимости, чтобы облегчить перенос кода от других SQL-серверов и запускать приложения, которые составляют таблицы со ссылками. См. раздел 1.8.2.

    Для ALTER TABLE, в отличие от этого CREATE TABLE , ADD FOREIGN KEY игнорирует index_name , если дано и использовано автоматически произведенное имя внешнего ключа. Как обходное решение, включайте CONSTRAINT, чтобы определить имя внешнего ключа:

    ADD CONSTRAINT name FOREIGN KEY (....) ...
    

    Действующие технические требования REFERENCES, где ссылки определены как часть спецификации столбца, тихо проигнорированы. MySQL принимает только REFERENCES, определенные как часть отдельной спецификации FOREIGN KEY.

    Разделенные таблицы InnoDB не поддерживают внешние ключи. См. раздел 20.6.2.

  • MySQL поддерживает использование ALTER TABLE, чтобы удалить внешние ключи:
    ALTER TABLE tbl_name
          DROP FOREIGN KEY fk_symbol;
    
    См. раздел 16.8.6.
  • Добавление и удаление внешнего ключа в том же самом ALTER TABLE поддержано для ALTER TABLE ... ALGORITHM=INPLACE, но не для ALTER TABLE ... ALGORITHM=COPY .
  • Для таблицы InnoDB, которая составлена с ее собственным табличным пространством file-per-table в файле .ibd, от того файла можно отказаться и импортировать другой. Отказаться от файла .ibd так:
    ALTER TABLE tbl_name DISCARD TABLESPACE;
    
    Это удаляет текущий файл .ibd, так что надо убедиться, что у Вас есть резервная копия. Попытка изменить табличное содержание, в то время как от файла табличного пространства отказываются приводит к ошибке. Вы можете выполнить операции DDL, перечисленные в раздел 16.12 в то время, как от файла табличного пространства отказываются.

    Чтобы импортировать резервный файл .ibd назад в таблицу, скопируйте его в каталог базы данных, а затем сделайте этот запрос:

    ALTER TABLE tbl_name IMPORT TABLESPACE;
    
    Файл табличного пространства не должен обязательно быть создан на сервере, в который он будет импортирован позже. В MySQL 8.0 импорт файла табличного пространства из другого сервера работает, если у обоих серверов есть статус GA (General Availablility), и их версии в пределах того же самого ряда. Иначе файл должен быть создан на сервере, в который он импортирован.

    ALTER TABLE ... IMPORT TABLESPACE не проводит в жизнь ограничения внешнего ключа на импортированные данные.

    ALTER TABLE ... DISCARD TABLESPACE и ALTER TABLE ...IMPORT TABLESPACE не поддержаны для таблиц, которые принадлежат общему табличному пространству.

    См. раздел 16.7.4.

  • Чтобы изменить табличный набор символов по умолчанию и все символьные столбцы (CHAR, VARCHAR, TEXT) к новому набору символов, используйте запрос:
    ALTER TABLE tbl_name CONVERT TO CHARACTER SET
          charset_name;
    
    Запрос также изменяет сопоставление всех символьных столбцов. Если Вы не определяете COLLATE, чтобы указать, которое сопоставление использовать, запрос использует сопоставление по умолчанию набора символов. Если это сопоставление является несоответствующим для намеченного табличного использования (например, если это изменило бы от чувствительного к регистру сопоставления до нечувствительного к регистру), определите сопоставление явно.

    Для столбца, у которого есть тип данных VARCHAR, или один из типов TEXT, CONVERT TO CHARACTER SET изменит тип данных по мере необходимости, чтобы гарантировать, что новый столбец достаточно длинен, чтобы сохранить так много символов, как оригинальный столбец. Например, у TEXT есть два байта длины, которые хранят длину значений в столбце, до максимума 65535. Для столбца latin1 TEXT каждый символ требует единственный байт, таким образом, столбец может сохранить до 65535 символов. Если столбец преобразован в utf8, каждый символ мог бы потребовать до трех байтов для максимальной возможной длины 3 * 65535 = 196605 байт. Та длина не будет помещаться в байты длины столбца TEXT, таким образом, MySQL преобразует тип данных в MEDIUMTEXT, который является самым маленьким строковым типом, для которого байты длины могут сделать запись значения 196605. Точно так же VARCHAR мог бы быть преобразован в MEDIUMTEXT.

    Чтобы избежать изменений типа данных, не следует использовать CONVERT TO CHARACTER SET. Вместо этого используйте MODIFY, чтобы изменить отдельные столбцы. Например:

    ALTER TABLE t MODIFY latin1_text_col TEXT CHARACTER SET utf8;
    ALTER TABLE t MODIFY latin1_varchar_col VARCHAR(M)
          CHARACTER SET utf8;
    
    Если Вы определяете CONVERT TO CHARACTER SET binary, CHAR, VARCHAR и TEXT преобразованы в их соответствующие двоичные строковые типы (BINARY, VARBINARY, BLOB). Это означает, что у столбцов больше не будет набора символов и последующие CONVERT TO не будут относиться к ним.

    Если charset_name = DEFAULT, набор символов базы данных используется.

    CONVERT TO преобразовывает значения столбцов между наборами символов. Это не то, что Вы хотите, если у Вас есть столбец в одном наборе символов (как latin1) но сохраненные значения фактически используют некоторый другой, несовместимый, набор символов (как utf8). В этом случае, Вы должны сделать следующее для каждого такого столбца:

    ALTER TABLE t1 CHANGE c1 c1 BLOB;
    ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8;
    
    Причина того, что это работает, состоит в том, что нет никакого преобразования, когда Вы преобразовываете в или от BLOB.

    Чтобы изменить только набор символов default для таблицы, используйте этот запрос:

    ALTER TABLE tbl_name DEFAULT CHARACTER SET
          charset_name;
    
    Слово DEFAULT опционально. Набор символов значения по умолчанию это набор символов, который используется, если Вы не определяете набор символов для столбцов, которые Вы добавляете к таблице позже (например, с помощью ALTER TABLE ... ADD column).

    При включении foreign_key_checks, что является настройкой по умолчанию, преобразование набора символов не разрешено на таблицах, которые включают столбец строки символов, используемый в ограничении внешнего ключа. Обходное решение должно отключить foreign_key_checks прежде, чем выполнить преобразование набора символов. Вы должны выполнить преобразование на обеих таблицах, вовлеченных в ограничение внешнего ключа перед включением foreign_key_checks . Если Вы повторно включаете foreign_key_checks после преобразования только одной из таблиц, ON DELETE CASCADE или ON UPDATE CASCADE могут повредить данные в таблице ссылки из-за неявного преобразования, которое происходит во время этих операций (Bug #45290, Bug #74816).

С функцией mysql_info() C API Вы можете узнать, сколько было скопировано строк ALTER TABLE. См. раздел 25.8.7.36.

14.1.7.1. Операции разделения ALTER TABLE

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

  • Просто использование partition_options с ALTER TABLE на разделенной таблице перераспределяет таблицу, согласно схеме разделения, определенной partition_options. Этот пункт всегда начинается PARTITION BY и и следует за тем же самым синтаксисом и другими правилами, как в partition_options для CREATE TABLE (см. раздел 14.1.15), может также использоваться, чтобы разделить существующую таблицу, которая еще не разделена. Например, считайте (неразделенную) таблицу определенной, как показано здесь:

    CREATE TABLE t1 (id INT, year_col INT);
    
    Эта таблица может быть разделена HASH с применением столбца id как ключа разделения на 8 разделов посредством этого запроса:
    ALTER TABLE t1 PARTITION BY HASH(id) PARTITIONS 8;
    
    MySQL поддерживает ALGORITHM с [SUB]PARTITION BY [LINEAR] KEY. ALGORITHM=1 заставляет сервер использовать те же самые хеширующие ключ функции как в MySQL 5.1, вычисляя размещение строк в разделении, ALGORITHM=2 указывает, что сервер использует хеширующие ключ функции, осуществленные и используемые по умолчанию для новых разделенных таблиц KEY в MySQL 5.5 и выше. Разделенные таблицы, составленные с хеширующими ключ функциями, используемыми в MySQL 5.5 и позже, не могут использоваться MySQL 5.1. Не определение опции имеет тот же самый эффект, как использование ALGORITHM=2. Эта опция предназначена для использования в основном, обновляя или удаляя разделенные таблицы [LINEAR] KEY между MySQL 5.1 и более поздними версиями MySQL, или для того, чтобы составить таблицы, разделенные KEY или LINEAR KEY в MySQL 5.5 или более позднем сервере, которые могут использоваться на MySQL 5.1.

    Чтобы обновить разделенную таблицу KEY, которая была составлена в MySQL 5.1, сначала выполните SHOW CREATE TABLE и отметьте точные столбцы и число показанного разделения. Теперь выполните ALTER TABLE, использующий точно тот же самый список столбцов и число разделов, как в CREATE TABLE, добавляя ALGORITHM=2 сразу после PARTITION BY. Вы должны также включать LINEAR, если это использовалось для оригинального табличного определения. Пример сеанса в mysql:

    mysql> SHOW CREATE TABLE p\G
    *************************** 1. row ***************************
       Table: p
    Create Table: CREATE TABLE `p` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `cd` datetime NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1
    /*!50100 PARTITION BY LINEAR KEY (id)
    PARTITIONS 32 */
    1 row in set (0.00 sec)
    
    mysql> ALTER TABLE p PARTITION BY LINEAR KEY ALGORITHM=2 (id)
                    PARTITIONS 32;
    Query OK, 0 rows affected (5.34 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> SHOW CREATE TABLE p\G
    *************************** 1. row ***************************
       Table: p
    Create Table: CREATE TABLE `p` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `cd` datetime NOT NULL,
      PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=latin1
    /*!50100 PARTITION BY LINEAR KEY (id)
    PARTITIONS 32 */
    1 row in set (0.00 sec)
    
    Понижение версии таблицы создало использование хеширования ключа значения по умолчанию, используемого в MySQL 5.5 и позже, позволяя его использование в MySQL 5.1, кроме как в случае использования ALGORITHM=1, чтобы вынудить разделение таблицы быть восстановленным, используя хеширующие ключ функции MySQL 5.1. Рекомендуется, чтобы Вы не делали этого кроме тех случаев, когда необходимо для совместимости с MySQL 5.1, так как улучшенная функция хеширования KEY, используемая по умолчанию в MySQL 5.5 и позже, обеспечивает затруднительные положения для многих проблем, найденных в более старом исполнении.

    Таблица, обновленная посредством ALTER TABLE ... PARTITION BY ALGORITHM=2 [LINEAR] KEY ... больше не может использоваться MySQL 5.1. Такая таблица должна была бы быть удалена с ALTER TABLE ... PARTITION BY ALGORITHM=1 [LINEAR] KEY ... прежде, чем это могло использоваться снова MySQL 5.1.

    Таблица, которая следует из использования ALTER TABLE ... PARTITION BY должна следовать тем же самым правилам, как создаваемая с CREATE TABLE ... PARTITION BY. Это включает правила, управляющие отношениями между любыми уникальными ключами (включая любой первичный ключ), который таблица могла бы иметь, и столбец или столбцы, используемые в выражении разделения, как обсуждено в разделе 20.6.1. Правила CREATE TABLE ... PARTITION BY для того, чтобы определить число разделов, также относятся к ALTER TABLE ... PARTITION BY.

    partition_definition для ALTER TABLE ADD PARTITION поддерживает те же самые опции как параметр с тем же самым названием в CREATE TABLE (см. раздел 14.1.15). Предположим, что Вы создали разделенную таблицу как показано здесь:

    CREATE TABLE t1 (id INT, year_col INT)
           PARTITION BY RANGE (year_col) (
                     PARTITION p0 VALUES LESS THAN (1991),
                     PARTITION p1 VALUES LESS THAN (1995),
                     PARTITION p2 VALUES LESS THAN (1999));
    
    Вы можете добавить новый раздел p3 к этой таблице для того, чтобы сохранить значения меньше 2002:
    ALTER TABLE t1 ADD PARTITION (PARTITION p3 VALUES LESS THAN (2002));
    
    ADD PARTITION может также использоваться с TABLESPACE, чтобы добавить новый раздел к существующему общему табличному пространству, к табличному пространству file-per-table или к системному табличному пространству.
    ALTER TABLE t1 ADD PARTITION (PARTITION p4 VALUES LESS THAN (2015)
          TABLESPACE = `ts1`);
    ALTER TABLE t1 ADD PARTITION (PARTITION p4 VALUES LESS THAN (2015)
          TABLESPACE = `innodb_file_per_table`);
    ALTER TABLE t1 ADD PARTITION (PARTITION p4 VALUES LESS THAN (2015)
          TABLESPACE = `innodb_system`);
    

    Если опция TABLESPACE = tablespace_name не определена, ALTER TABLE ... ADD PARTITION добавляет раздел к табличному пространству по умолчанию таблицы, которое может быть определено на табличном уровне во время CREATE TABLE или ALTER TABLE.

    DROP PARTITION может использоваться, чтобы удалить один или больше разделов RANGE или LIST. Этот запрос не может использоваться с HASH или KEY, вместо этого используйте COALESCE PARTITION. Любые данные, которые хранились в удаленном разделе, названном в partition_names потеряны. Например, учитывая таблицу t1 определенную ранее, Вы можете удалить разделы p0 и p1:

    ALTER TABLE t1 DROP PARTITION p0, p1;
    
    ADD PARTITION и DROP PARTITION в настоящее время не поддерживают IF [NOT] EXISTS.

    DISCARD PARTITION ... TABLESPACE и IMPORT PARTITION ... TABLESPACE расширяют мобильную особенность табличного пространства на табличные разделы. Каждый раздел InnoDB имеет свой собственный файл табличного пространства (.idb). Мобильная особенность облегчает копирование табличных пространств с рабочего случая сервера MySQL на другой рабочий случай или выполнение восстановления на том же самом случае. Обе опции берут список разделенных запятой значений одного или более имен разделов. Например:

    ALTER TABLE t1 DISCARD PARTITION p2, p3 TABLESPACE;
    ALTER TABLE t1 IMPORT PARTITION p2, p3 TABLESPACE;
    
    При запуске DISCARD PARTITION ... TABLESPACE и IMPORT PARTITION ... TABLESPACE на подразделенных таблицах позволены имена разделения и подразделения. Когда имя разделения определено, подразделение того разделения включено.

    Мобильная особенность также поддерживает копирование или восстановление разделенных таблиц InnoDB (все разделение сразу). Для дополнительной информации см. раздел 16.7.6.

    Переименование разделенной таблицы поддержано. Вы можете переименовать отдельное разделение, косвенно используя ALTER TABLE ... REORGANIZE PARTITION, но эта работа делает копию данных.

    Возможно удалить строки из выбранного разделения, используя TRUNCATE PARTITION. Эта опция берет список разделенных запятой значений одного или более имен разделов. Рассмотрите таблицу t1:

    CREATE TABLE t1 (id INT, year_col INT)
           PARTITION BY RANGE (year_col)
                     (PARTITION p0 VALUES LESS THAN (1991),
                      PARTITION p1 VALUES LESS THAN (1995),
                      PARTITION p2 VALUES LESS THAN (1999),
                      PARTITION p3 VALUES LESS THAN (2003),
                      PARTITION p4 VALUES LESS THAN (2007));
    
    Чтобы удалить все строки из раздела p0, Вы можете использовать:
    ALTER TABLE t1 TRUNCATE PARTITION p0;
    
    Это имеет тот же самый эффект, как этот DELETE:
    DELETE FROM t1 WHERE year_col < 1991;
    
    Усекая много разделов, разделение не должно быть непрерывным: это может очень упростить операции на разделенных таблицах, которые иначе потребовали бы очень сложный WHERE при применении DELETE. Например, этот запрос удаляет все строки из разделов p1 и p3:
    ALTER TABLE t1 TRUNCATE PARTITION p1, p3;
    
    Аналогичный DELETE выглядит так:
    DELETE FROM t1 WHERE (year_col >= 1991 AND year_col < 1995)
                   OR (year_col >= 2003 AND year_col < 2007);
    
    Вы можете использовать ключевое слово ALL вместо списка имен разделов, в этом случае запрос действует на все разделение в таблице.

    TRUNCATE PARTITION просто удаляет строки, это не изменяет определение таблицы или любого ее раздела.

    Вы можете проверить, что строки были удалены, проверяя INFORMATION_SCHEMA.PARTITIONS, используя такой запрос, как этот:

    SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS
           WHERE TABLE_NAME = 't1';
    
    COALESCE PARTITION может использоваться с таблицей, которая разделена HASH или KEY, чтобы сократить количество разделов number. Предположите, что Вы составили таблицу t2:
    CREATE TABLE t2 (name VARCHAR (30), started DATE)
           PARTITION BY HASH(YEAR(started)) PARTITIONS 6;
    
    Вы можете сократить количество разделов t2 с 6 до 4:
    ALTER TABLE t2 COALESCE PARTITION 2;
    
    Данные в последних разделах number слиты в остающиеся разделы. В этом случае разделы 4 и 5 будут слиты в первые 4 раздела (0, 1, 2 и 3).

    Чтобы изменить некоторые, но не все разделы, Вы можете использовать REORGANIZE PARTITION. Этот запрос может использоваться несколькими способами:

    • Слить ряд разделов в единственный раздел. Это может быть сделано, называя несколько разделов в списке partition_names и заданием единственного определения для partition_definition.

    • Разделять существующее разделение на несколько. Вы можете достигнуть этого, называя единственный раздел в partition_names и несколько partition_definitions.
    • Изменить диапазоны для подмножества разделения, определенного, используя VALUES LESS THAN или значение для подмножества разделов, определенного, используя VALUES IN.
    • Перемещать раздел от одного табличного пространства до другого. Для примера см. здесь .

    Для разделения, которое явно не назвали, MySQL автоматически обеспечивает имена по умолчанию p0, p1, p2 и т.д. Это верно и относительно подразделов.

    Для более подробной информации и примеров ALTER TABLE ... REORGANIZE PARTITION см. раздел 20.3.1.

  • Возможно обменять табличное разделение или подразделение с таблицей, используя ALTER TABLE ... EXCHANGE PARTITION, то есть, чтобы переместить любые существующие строки в разделение или подразделение к неразделенной таблице, и любые существующие строки в неразделенной таблице к табличному разделению или подразделению.

    См. раздел 20.3.3 .

  • Несколько дополнительных опций обеспечивают функциональность обслуживания и ремонта разделения, аналогичную осуществленному для неразделенных таблиц через CHECK TABLE и REPAIR TABLE (которые также поддержаны для разделенных таблиц, см. раздел 14.7.2). Они включают ANALYZE PARTITION, CHECK PARTITION, OPTIMIZE PARTITION, REBUILD PARTITION и REPAIR PARTITION. Каждая из этих опций берет partition_names, состоящий из одного или более названий разделов, отделенных запятыми. Разделение должно уже существовать в целевой таблице. Вы можете также использовать ALL вместо partition_names, когда запрос действует на все разделение в таблице. Для получения дополнительной информации и примеров см. раздел 20.3.4.

    InnoDB в настоящее время не поддерживает оптимизацию по разделам, ALTER TABLE ... OPTIMIZE PARTITION пересоздает и анализирует всю таблицу (Bug #11751825, Bug #42822). Чтобы работать вокруг этой проблемы, используйте ALTER TABLE ... REBUILD PARTITION и ALTER TABLE ... ANALYZE PARTITION.

    ANALYZE PARTITION, CHECK PARTITION, OPTIMIZE PARTITION и REPAIR PARTITION не поддержаны для таблиц, которые не разделены.

  • REMOVE PARTITIONING позволяет Вам удалить раздел таблицы, не затрагивая таблицу или ее данные. Эта опция может быть объединена с другими ALTER TABLE, например, добавить, удалить или переименовать столбцы или индексы.
  • Используйте ENGINE с ALTER TABLE, чтобы сменить механизм хранения, используемый таблицей, не затрагивая разделение. Целевой механизм хранения должен обеспечить свой собственный обработчик разделения. Только InnoDB и NDB имеют родные обработчики разделения, NDB в настоящее время не поддерживается в MySQL 8.0.

ALTER TABLE может содержать PARTITION BY или REMOVE PARTITIONING в дополнении к другим изменениям технических требований, но PARTITION BY или REMOVE PARTITIONING должен быть определен последний после любых других технических требований.

ADD PARTITION, DROP PARTITION, COALESCE PARTITION, REORGANIZE PARTITION, ANALYZE PARTITION, CHECK PARTITION и REPAIR PARTITION не могут быть объединены с другими изменениями технических требований в ALTER TABLE. Для получения дополнительной информации см. раздел 14.1.7.1.

Только единственный случай любой из следующих опций может использоваться в данном ALTER TABLE: PARTITION BY, ADD PARTITION, DROP PARTITION, TRUNCATE PARTITION, EXCHANGE PARTITION, REORGANIZE PARTITION или COALESCE PARTITION, ANALYZE PARTITION, CHECK PARTITION, OPTIMIZE PARTITION, REBUILD PARTITION, REMOVE PARTITIONING.

Например, следующие два запроса недопустимы:

ALTER TABLE t1 ANALYZE PARTITION p1, ANALYZE PARTITION p2;
ALTER TABLE t1 ANALYZE PARTITION p1, CHECK PARTITION p2;
В первом случае Вы можете проанализировать разделы p1 и p2 табьлицы t1 одновременно, используя единственный запрос ANALYZE PARTITION, который перечисляет оба раздела, что будет проанализировано так:
ALTER TABLE t1 ANALYZE PARTITION p1, p2;
Во втором случае невозможно сделать ANALYZE и CHECK на разных разделах той же самой таблицы одновременно. Вместо этого Вы должны сделать два отдельных запроса:
ALTER TABLE t1 ANALYZE PARTITION p1;
ALTER TABLE t1 CHECK PARTITION p2;
REBUILD в настоящее время не поддерживаются для подразделения. REBUILD явно отвергнуто с подразделением, и ALTER TABLE выдаст ошибку.

CHECK PARTITION и REPAIR PARTITION терпят неудачу, когда разделение, которое будет проверено или восстановлено, содержит любые ошибки дубликата ключа.

См. раздел 20.3.4.

14.1.7.2. ALTER TABLE и произведенные столбцы

Действия ALTER TABLE, разрешенные для произведенных столбцов: ADD, MODIFY и CHANGE.

  • Могут быть добавлены произведенные столбцы.

  • Тип данных и выражение произведенных столбцов могут быть изменены.
  • Произведенные столбцы могут быть переименованы или удалены, если никакой другой столбец не обращается к ним.
  • Виртуальные произведенные столбцы не могут быть изменены к сохраненным произведенным столбцам, или наоборот. Чтобы работать вокруг этого, удалите столбец, затем добавьте это с новым определением.
  • Непроизведенные столбцы могут быть изменены к сохраненному, но не виртуальным произведенным столбцам.
  • Сохраненные, но не произведенные виртуальные столбцы могут быть изменены к непроизведенным столбцам. Произведенные сохраненные значения становятся значениями непроизведенного столбца.
  • ADD COLUMN не оперативная работа для сохраненных столбцов (обходится без использования временной таблицы), потому что выражение должно быть оценено сервером. Для сохраненных столбцов индексирующие изменения сделаны на месте, изменения выражения не сделаны на месте. Изменения комментариев столбца сделаны на месте.
  • ADD COLUMN и DROP COLUMN оперативные операции для виртуальных столбцов. Однако, добавление или удаление виртуального столбца не может быть выполнено в комбинации с другим ALTER TABLE.
  • InnoDB допускает вторичные индексы на произведенных виртуальных столбцах. Добавление или удаление вторичного индекса на произведенном виртуальном столбце это оперативная работа. Для получения дополнительной информации см. раздел 14.1.15.6.
  • Когда произведенный столбец VIRTUAL добавлен к таблице или изменен, он не обеспечен данными, вычисляемыми произведенным выражением столбца, неизвестно, не будут ли они вне диапазона для столбца. Это может привести к непоследовательным возвращаемым данным и неожиданным сбоям запросов. Чтобы решить, происходит ли проверка допустимости для таких столбцов, ALTER TABLE поддерживает опции WITHOUT VALIDATION и WITH VALIDATION:

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

    • С WITH VALIDATION ALTER TABLE копирует таблицу. Если ошибка происходят, запрос терпит неудачу. Поскольку табличная копия выполнена, запрос занимает больше времени.

    WITHOUT VALIDATION и WITH VALIDATION разрешаются только с ADD COLUMN, CHANGE COLUMN и MODIFY COLUMN. Иначе происходит ошибка ER_WRONG_USAGE.

  • Если оценка выражения вызывает усечение или обеспечивает неправильный ввод функции, ALTER TABLE заканчивается с ошибкой, и работа DDL отклонена.
  • ALTER TABLE, который изменяет значение по умолчанию столбца col_name, также изменяет значение произведенного выражения столбца, которое обращается к использованию столбца col_name, что может изменить значение произведенного выражения столбца, которое обращается к использованию столбца DEFAULT(col_name ). Поэтому ALTER TABLE, который изменяет определение столбца, вызывает пересоздание таблицы, если какое-либо произведенное выражение столбца использует DEFAULT().

14.1.7.3. Примеры ALTER TABLE

Начните с таблицы t1. Она создается как показано здесь:

CREATE TABLE t1 (a INTEGER,b CHAR(10));
Переименуем ее из t1 в t2:
ALTER TABLE t1 RENAME t2;
Изменить столбец a с INTEGER на TINYINT NOT NULL (имя то же самое) и изменить столбец b с CHAR(10) на CHAR(20) с переименованием этого с b на c:
ALTER TABLE t2 MODIFY a TINYINT NOT NULL, CHANGE b c CHAR(20);
Добавить новый столбец TIMESTAMP d:
ALTER TABLE t2 ADD d TIMESTAMP;
Добавить индексирование на столбце d и индекс UNIQUE на a:
ALTER TABLE t2 ADD INDEX (d), ADD UNIQUE (a);
Удалить столбец c:
ALTER TABLE t2 DROP COLUMN c;
Добавить новый столбец AUTO_INCREMENT целого числа c:
ALTER TABLE t2 ADD c INT UNSIGNED NOT NULL AUTO_INCREMENT,
      ADD PRIMARY KEY (c);
Мы индексировали c (как PRIMARY KEY), потому что столбцы AUTO_INCREMENT должны быть индексированы, и мы объявляем c как NOT NULL, потому что столбцы первичного ключа не могут быть NULL.

Когда Вы добавляете AUTO_INCREMENT, значения столбцов заполнены порядковыми номерами автоматически. Для таблиц MyISAM Вы можете установить первый порядковый номер, выполняя SET INSERT_ID=value до ALTER TABLE или используя опцию таблицы AUTO_INCREMENT=value. См. раздел 6.1.5.

С MyISAM если Вы не изменяете столбец AUTO_INCREMENT, порядковый номер не затронут. Если Вы удаляете AUTO_INCREMENT и затем добавляете другой столбец AUTO_INCREMENT, числа повторно упорядочены, начиная с 1.

При использовании репликации, добавление столбца AUTO_INCREMENT к таблице не может произвести то же самое упорядочивание строк на ведомом устройстве и ведущем устройстве. Это происходит, потому что порядок, в котором пронумерованы строки, зависит от определенного механизма хранения, используемого для таблицы и порядка, в который были вставлены строки. Если важно иметь тот же самый порядок на ведущее устройство и ведомое устройство, строки должны быть упорядочены прежде, чем назначить число AUTO_INCREMENT. Допустим, что Вы хотите добавить AUTO_INCREMENT к таблице t1, следующие запросы производят новую таблицу t2, идентичную t1, но со столбцом AUTO_INCREMENT:

CREATE TABLE t2 (id INT AUTO_INCREMENT PRIMARY KEY)
SELECT * FROM t1 ORDER BY col1, col2;
Это предполагает, что таблица t1 имеет столбцы col1 и col2.

Этот набор запросов также произведет новую таблицу t2, идентичную t1, с добавлением столбца AUTO_INCREMENT:

CREATE TABLE t2 LIKE t1;
ALTER TABLE t2 ADD id INT AUTO_INCREMENT PRIMARY KEY;
INSERT INTO t2 SELECT * FROM t1 ORDER BY col1, col2;

Гарантировать то же самое упорядочивание на ведущем устройстве и на ведомом устройстве всех столбцов t1 можно, указанием в ORDER BY.

Независимо от метода, используемого, чтобы создать и заполнить копию, имеющую столбец AUTO_INCREMENT, заключительный шаг должен удалить оригинальную таблицу и затем переименовать копию:

DROP TABLE t1;
ALTER TABLE t2 RENAME t1;

14.1.8. ALTER VIEW

ALTER
[ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
[DEFINER = { user | CURRENT_USER }]
[SQL SECURITY { DEFINER | INVOKER }]
VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION]
Этот запрос изменяет определение представления, которое должно существовать. Синтаксис подобен CREATE VIEW, эффект тот же самый, как для CREATE OR REPLACE VIEW. См. раздел 14.1.18. Это запрос требует привилегий CREATE VIEW и DROP для представления и некоторой привилегии для каждого столбца, упомянутого в SELECT. ALTER VIEW разрешен только определителю или пользователям с привилегией SUPER.

14.1.9. CREATE DATABASE

CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name
[create_specification] ...

create_specification:
[DEFAULT] CHARACTER SET [=] charset_name
  | [DEFAULT] COLLATE [=] collation_name
CREATE DATABASE создает базу данных с именем. Чтобы использовать этот запрос, Вы нуждаетесь в привилегии CREATE для базы данных. CREATE SCHEMA это синоним для CREATE DATABASE .

Ошибка происходит, если база данных существует, и Вы не определяли IF NOT EXISTS.

В MySQL 8.0 CREATE DATABASE не разрешен в пределах сеанса, у которого есть активный LOCK TABLES.

create_specification определяют характеристики базы данных. Характеристики базы данных сохранены в словаре данных. CHARACTER SET определяет набор символов базы данных по умолчанию. COLLATE определяет сопоставление базы данных по умолчанию. Раздел 11.1 обсуждает имена сопоставления и набора символов.

База данных в MySQL осуществлена как каталог, содержащий файлы, которые соответствуют таблицам в базе данных. Поскольку нет никаких таблиц в базе данных, когда это первоначально создается, CREATE DATABASE создает только каталог в соответствии с каталогом данных MySQL. Правила для допустимых имен базы данных даны в разделе 10.2. Если имя базы данных содержит специальные символы, название каталога базы данных содержит закодированные версии тех символов как описано в разделе 10.2.3.

Создание каталога базы данных, вручную создавая каталог в соответствии с каталогом данных (например, с помощью mkdir) временно не поддержано в MySQL 8.0.0.

Вы можете также использовать mysqladmin, чтобы создать базы данных. См. раздел 5.5.2.

14.1.10. CREATE EVENT

CREATE
[DEFINER = { user | CURRENT_USER }]
EVENT
[IF NOT EXISTS]
event_name
ON SCHEDULE schedule
[ON COMPLETION [NOT] PRESERVE]
[ENABLE | DISABLE | DISABLE ON SLAVE]
[COMMENT 'comment']
DO event_body;

schedule:
AT timestamp [+ INTERVAL interval] ...
  | EVERY interval
[STARTS timestamp [+ INTERVAL interval] ...]
[ENDS timestamp [+ INTERVAL interval] ...]

interval:
quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
  WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
  DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}
Этот запрос создает и намечает новое событие. Оно не будет работать, если Планировщик Событий не будет включен. Для информации о проверке состояния Планировщика Событий и включении в случае необходимости см. раздел 21.4.2.

CREATE EVENT требует привилегию EVENT для схемы, в которой должно быть создано событие. Это могло бы также потребовать привилегию SUPER , в зависимости от значения DEFINER, как описано позже в этом разделе.

Минимальные требования для допустимого CREATE EVENT:

  • Ключевые слова CREATE EVENT с именем, которое уникально идентифицирует событие в схеме базы данных.

  • ON SCHEDULE, который определяет, когда и как часто случай выполняется.
  • DO, который содержит запрос SQL, который будет выполнен.

Это пример минимального CREATE EVENT :

CREATE EVENT myevent ON SCHEDULE
       AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
       DO UPDATE myschema.mytable SET mycol = mycol + 1;
Предыдущий запрос создает событие myevent. Это выполняется однажды в один час после его создания, выполняя запрос SQL, который постепенно увеличивает значение столбца mycol в таблице myschema.mytable на 1.

event_name должен быть допустимым идентификатором MySQL с максимальной длиной 64 символа. Имена событий не являются чувствительными к регистру, таким образом, у Вас не может быть двух событий, названных myevent и MyEvent в той же самой схеме. Вообще, правила, управляющие именами событий, являются теми же самыми, как для названий сохраненных подпрограмм. См. раздел 10.2.

Событие связано со схемой. Если никакая схема не обозначена как часть event_name, значение по умолчанию (текущая схема) принято. Чтобы создать событие в определенной схеме, квалифицируйте имя события с использованием имени схемы schema_name.event_name .

DEFINER определяет учетную запись MySQL, которая будет использоваться, проверяя привилегии доступа во время выполнения событий. Если user дано, это должна быть учетная запись MySQL, определенная как 'user_name'@'host_name ', CURRENT_USER или CURRENT_USER(). Значение по умолчанию DEFINER: пользователь, который выполняет CREATE EVENT. Это то же самое, как определение DEFINER = CURRENT_USER.

Если Вы определяете DEFINER, эти правила определяют допустимые пользовательские значения DEFINER:

  • Если Вы не имеете привилегии SUPER, единственное разрешенное значение user Ваша собственная учетная запись, определенная буквально или при использовании CURRENT_USER. Вы не можете установить определение в некоторую другую учетную запись.

  • Если Вы имеете привилегию SUPER , Вы можете определить любое синтаксически допустимое имя учетной записи. Если учетная запись не существует, предупреждение произведено.
  • Хотя возможно создать событие без DEFINER, ошибка происходит во время выполнения событий, если учетная запись не существует.

См. раздел 21.6.

В пределах события CURRENT_USER() возвращает учетную запись для проверки привилегии во время выполнения события, то есть DEFINER. См. раздел 7.3.12.

IF NOT EXISTS для CREATE EVENT имеет тот же смысл, как для CREATE TABLE: если событие уже существует в той же самой схеме, никакие меры не предприняты и никакой ошибки нет. (днако, предупреждение будет произведено в таких случаях.

ON SCHEDULE определяет когда, как часто, и как долго event_body определен для повторений событий. Этот пункт принимает одну из двух форм:

  • AT timestamp используется для одноразового случая. Это определяет, что событие выполняется только один раз в дату и время, заданные timestamp, что должно включать дату и время или должно быть выражением, которое решается к значению datetime. Вы можете использовать значение любого типа DATETIME или TIMESTAMP с этой целью. Если дата в прошлом, происходит предупреждение, как показано здесь:

    mysql> SELECT NOW();
    +---------------------+
    | NOW()               |
    +---------------------+
    | 2006-02-10 23:59:01 |
    +---------------------+
    1 row in set (0.04 sec)
    
    mysql> CREATE EVENT e_totals
        ->        ON SCHEDULE AT '2006-02-10 23:59:00'
        ->        DO INSERT INTO test.totals VALUES (NOW());
    Query OK, 0 rows affected, 1 warning (0.00 sec)
    
    mysql> SHOW WARNINGS\G
    *************************** 1. row ***************************
      Level: Note
       Code: 1588
    Message: Event execution time is in the past and ON COMPLETION NOT
             PRESERVE is set. The event was dropped
             immediately after creation.
    
    CREATE EVENT, которые являются самостоятельно неправильными, терпят неудачу с ошибкой.

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

    Создать событие, которое происходит в некоторый момент в будущем относительно текущей даты и времени, скажем, спустя три недели, можно, если использовать дополнительный параметр + INTERVAL interval . interval состоит из двух частей, количества и единицы времени, и следует тем же самым правилам синтаксиса, которые управляют интервалами, используемыми в функции DATE_ADD() (см. раздел 13.7. Ключевые слова модулей такие же, за исключением того, что Вы не можете использовать модули, вовлекающие микросекунды, определяя событие. С некоторыми типами интервала могут использоваться сложные единицы измерения времени. Например, две минуты и десять секунд может быть выражено как + INTERVAL '2:10' MINUTE_SECOND.

    Вы можете также объединить интервалы. Например, AT CURRENT_TIMESTAMP + INTERVAL 3 WEEK + INTERVAL 2 DAY задает через три недели и два дня. Каждая часть такого пункта должна начинаться с + INTERVAL.

  • Чтобы повторить действия в равном интервале, используйте EVERY. Ключевое слово EVERY сопровождается interval, как описано в предыдущем обсуждении параметра AT. + INTERVAL не используется с EVERY. Например, EVERY 6 WEEK значит каждые шесть недель.

    Хотя + INTERVAL не разрешены в EVERY, Вы можете использовать те же самые сложные единицы измерения времени, разрешенные в + INTERVAL.

    EVERY может содержать дополнительный параметр STARTS. STARTS сопровождается timestamp, которое указывает, когда действие должно начать повторяться, и может также использовать + INTERVAL interval, чтобы определить количество времени с текущего момента. Например, EVERY 3 MONTH STARTS CURRENT_TIMESTAMP + INTERVAL 1 WEEK значит каждые три месяца, начиная через одну неделю с текущего момента . Точно так же Вы можете выразить каждые две недели, начиная через шесть часов и пятнадцать минут с текущего момента как EVERY 2 WEEK STARTS CURRENT_TIMESTAMP + INTERVAL '6:15' HOUR_MINUTE. Не определение STARTS аналогично STARTS CURRENT_TIMESTAMP, то есть, действие, определенное для события, начинает повторяться непосредственно после создания.

    EVERY может содержать дополнительное ключевое слово ENDS. ENDS сопровождается timestamp, которое говорит MySQL, когда событие должно прекратить повторяться. Вы можете также использовать + INTERVAL interval с ENDS, например, EVERY 12 HOUR STARTS CURRENT_TIMESTAMP + INTERVAL 30 MINUTE ENDS CURRENT_TIMESTAMP + INTERVAL 4 WEEK значит каждые двенадцать часов, начиная через тридцать минут с этого времени, и заканчивая через четыре недели с этого времени. Не использование ENDS значит, что событие продолжает запускаться неопределенное число раз.

    ENDS поддерживает тот же самый синтаксис для сложных единиц измерения времени, как STARTS.

    Вы можете использовать STARTS, ENDS, оба или ни один в EVERY.

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

ON SCHEDULE может использовать выражения, вовлекающие встроенные функции MySQL и пользовательские переменные, чтобы получить любое из значений timestamp или interval , которые это содержит. Вы не можете использовать сохраненные функции или определяемые пользователем функции в таких выражениях, и при этом Вы не можете использовать табличные ссылки, однако, Вы можете использовать SELECT FROM DUAL. Это верно для CREATE EVENT и ALTER EVENT. Ссылки на сохраненные функции, определяемые пользователем функции и таблицы в таких случаях определенно не разрешены и терпят неудачу с ошибкой (Bug #22830).

Времена в ON SCHEDULE интерпретируются, используя значение time_zone текущего сеанса. Это становится часовым поясом событий, то есть, часовой пояс, который используется для планирования события, является текущим в пределах события при выполнении. Эти времена преобразованы в UTC и сохранены наряду с часовым поясом событий в таблице mysql.event. Это позволяет выполнению событий продолжиться как определено, независимо от любых последующих изменений часового пояса сервера или эффектов летнего времени. Для дополнительной информации о представлении времен событий см. раздел 21.4.4. См. также разделы 14.7.5.18 и 22.7.

Обычно как только событие истекло, оно немедленно удалено. Вы можете переопределить это поведение, определяя ON COMPLETION PRESERVE. Использование ON COMPLETION NOT PRESERVE просто делает поведение по умолчанию явным.

Вы можете создать событие, но препятствовать тому, чтобы это было активно, использованием ключевого слова DISABLE. Альтернативно, Вы можете использовать ENABLE, чтобы сделать явным состояние значения по умолчанию, которое является активным. Это является самым полезным в соединении с ALTER EVENT (см. раздел 14.1.2).

Третье значение может также появиться вместо ENABLE или DISABLE: DISABLE ON SLAVE установлен для состояния события на ведомом устройстве, чтобы указать, что событие создавалось на ведущем устройстве и копировалось к ведомому устройству, но не запущено на ведомом устройстве. См. раздел 19.4.1.12.

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

DO определяет действие, которое выполняет событие, и состоит из запросов SQL. Почти любой допустимый запрос MySQL, который может использоваться в сохраненной подпрограмме, может также использоваться в качестве действия для запланированного события, см. раздел C.1. Например, следующее событие e_hourly удаляет все строки из таблицы sessions однажды в час, где эта таблица является частью схемы site_activity:

CREATE EVENT e_hourly ON SCHEDULE
       EVERY 1 HOUR COMMENT 'Clears out sessions table each hour.'
       DO DELETE FROM site_activity.sessions;
MySQL хранит sql_mode, когда событие создано или изменено, и всегда запускает событие с этой установкой в силе, независимо от текущего режима SQL сервера, когда событие начинает выполняться.

CREATE EVENT, который содержит ALTER EVENT в DO, кажется, преуспевает, однако, когда сервер пытается запустить получающееся запланированное событие, выполнение терпит неудачу с ошибкой.

Такие запросы, как SELECT или SHOW, которые просто возвращают набор результатов, не имеют никакого эффекта, когда используются в событии: вывод от них не посылают MySQL Monitor, и при этом он не сохранен нигде. Однако, Вы можете использовать такие запросы, как SELECT ... INTO и INSERT INTO ... SELECT, которые сохраняют результат. См. следующий пример в этом разделе для последнего случая.

Схема, которой принадлежит событие, является схемой по умолчанию для табличных ссылок в DO. Любые ссылки на таблицы в других схемах должны быть квалифицированы с надлежащим именем схемы.

Как с сохраненными подпрограммами, Вы можете использовать синтаксис составного запроса DO с ключевыми словами BEGIN и END:

delimiter |

CREATE EVENT e_daily
ON SCHEDULE
   EVERY 1 DAY
COMMENT 'Saves total number of sessions then clears the table each day'
DO BEGIN
  INSERT INTO site_activity.totals (time, total)
  SELECT CURRENT_TIMESTAMP, COUNT(*) FROM site_activity.sessions;
  DELETE FROM site_activity.sessions;
END |

delimiter ;
Этот пример использует команду delimiter, чтобы изменить разделитель запроса. См. раздел 21.1.

Более сложные составные запросы, такие как используемые в сохраненных подпрограммах, возможны в событии. Этот пример использует местные переменные, обработчик ошибок и конструкцию управления потоками:

delimiter |

CREATE EVENT e
ON SCHEDULE
   EVERY 5 SECOND
DO BEGIN
   DECLARE v INTEGER;
   DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
   SET v = 0;
   WHILE v < 5 DO
     INSERT INTO t1 VALUES (0);
     UPDATE t2 SET s1 = s1 + 1;
     SET v = v + 1;
  END WHILE;
END |

delimiter ;
Нет никакого способа передать параметры непосредственно к или от событий, однако, возможно вызвать сохраненную подпрограмму с параметрами в пределах события:
CREATE EVENT e_call_myproc
ON SCHEDULE
   AT CURRENT_TIMESTAMP + INTERVAL 1 DAY
DO CALL myproc(5, 27);
Если определитель имеет привилегию SUPER, событие может читать и писать глобальные переменные. Поскольку предоставление этой привилегии влечет за собой потенциал для злоупотребления, экстремальная забота должна быть проявлена при этом.

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

14.1.11. CREATE FUNCTION

CREATE FUNCTION используется, чтобы создать сохраненные функции и определяемые пользователем функции (UDF):

  • Для информации о создании сохраненных функций см. раздел 14.1.13.

  • Для информации о создании определяемых пользователем функций см. раздел 14.7.3.1.

14.1.12. CREATE INDEX

CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
[index_type]
ON tbl_name (index_col_name,...)
[index_option]
[algorithm_option | lock_option] ...

index_col_name:
col_name [(length)] [ASC | DESC]

index_type:
USING {BTREE | HASH}

index_option:
KEY_BLOCK_SIZE [=] value
  | index_type
  | WITH PARSER parser_name
  | COMMENT 'string'
  | {VISIBLE | INVISIBLE}

algorithm_option:
ALGORITHM [=] {DEFAULT|INPLACE|COPY}

lock_option:
LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}
CREATE INDEX отображен на ALTER TABLE, чтобы создать индекс. См. раздел 14.1.7. CREATE INDEX не может использоваться, чтобы создать PRIMARY KEY, используйте ALTER TABLE. См. раздел 9.3.1.

Обычно Вы создаете все индексы на таблице в то время, когда таблица составлена с CREATE TABLE. См. раздел 14.1.15. Это особенно важно для InnoDB, где первичный ключ определяет физическое расположение строк в файле с данными. CREATE INDEX позволяет добавить индекс к существующим таблицам.

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

Для строковых столбцов может быть создан индекс, который использует только ведущую часть значений столбцов, используя col_name(length), чтобы определить длину префикса:

  • Префиксы могут быть определены для столбцов CHAR, VARCHAR, BINARY и VARBINARY.

  • Префиксы должны быть определены для BLOB и TEXT.
  • Пределы префиксов измерены в байтах, тогда как длина префикса в CREATE TABLE, ALTER TABLE и CREATE INDEX интерпретируется как число символов для недвоичных строковых типов (CHAR, VARCHAR, TEXT) и число байтов для двоичных строковых типов (BINARY, VARBINARY, BLOB). Примите это во внимание, определяя длину префикса для недвоичного строкового столбца, который использует многобайтовый набор символов.
  • Для пространственных столбцов префиксы не могут быть даны, как описано позже в этом разделе.

Запрос, показанный здесь, создает индекс с использованием первых 10 символов столбца name (принимая, что name имеет недвоичной строковый тип):

CREATE INDEX part_of_name ON customer (name(10));
Если имена в столбце обычно отличаются по первым 10 символам, это не должно быть намного медленнее, чем индекс, создаваемый из всего name. Кроме того, использование приставок столбца для индекса может сделать индексный файл намного меньшим, что может сохранить много дискового пространства и может также убыстрить INSERT.

Поддержка префиксов и длины (где поддержано) зависят от механизма хранения. Например, приставка может составить до 767 байтов для InnoDB, которые используют формат строки REDUNDANT или COMPACT. Предел длины поднят до 3072 байтов для таблиц InnoDB, которые используют формат строки DYNAMIC или COMPRESSED . Для MyISAM предел префикса составляет 1000 байтов.

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

FULLTEXT поддержаны только для InnoDB и MyISAM и могут включать только столбцы CHAR, VARCHAR и TEXT. Индексация всегда происходит по всему столбцу. Префиксы столбца не поддержаны, любая длина префикса проигнорирована, если определена. См. раздел 13.9.

MyISAM, InnoDB, NDB и ARCHIVE поддерживают пространственные столбцы, например, POINT и GEOMETRY. См. раздел 12.5. Однако, поддержка пространственной индексации столбца изменяется среди механизмов. Пространственный и непространственный индексы доступны, согласно следующим правилам.

Пространственный индекс (создаваемый использованием SPATIAL INDEX) имееет эти характеристики:

  • Доступный только для InnoDB и MyISAM. Определение SPATIAL INDEX для другого механизма хранения приводит к ошибке.

  • Индексированные столбцы должны быть NOT NULL.
  • Длины префикса столбца запрещены. Полная ширина каждого столбца индексирована.

Характеристики непространственных индексов (создаваемых с INDEX, UNIQUE или PRIMARY KEY):

  • Разрешены для любого механизма хранения, который поддерживает пространственные столбцы, кроме ARCHIVE.

  • Столбцы могут быть NULL, если индексирование не является первичным ключом.
  • Для каждого пространственного столбца в не-SPATIAL индексе, кроме столбцов POINT, длина префикса столбца должна быть определена. Это же самое требование касается индексирования столбцов BLOB . Длина префикса дана в байтах.
  • Индексный тип для не-SPATIAL индекса зависит от механизма хранения. В настоящее время используется B-tree.
  • Вы можете добавить индексирование на столбце, который может иметь NULL, только для InnoDB, MyISAM и MEMORY.
  • Вы можете добавить индексирование на BLOB или TEXT только для InnoDB и MyISAM.
  • Когда включен innodb_stats_persistent, выполняется ANALYZE TABLE для таблицы InnoDB после создания индекса на этой таблице.

InnoDB допускает вторичные индексы на виртуальных столбцах. Для получения дополнительной информации см. раздел 14.1.15.6.

index_col_name может закончиться ASC или DESC. Эти ключевые слова разрешены для будущих расширений для того, чтобы определить, что возрастание или убывание индекса хранится. В настоящее время они разобраны, но проигнорированы, индексные значения всегда сохранены в порядке возрастания.

После списка столбцов индекса могут быть даны опции. Значение index_option может быть любым следующим:

  • KEY_BLOCK_SIZE [=] value

    Для MyISAM KEY_BLOCK_SIZE произвольно определяет размер в байтах, чтобы использовать для ключевых блоков индекса. Значение обработано как подсказка, иной размер может использоваться в случае необходимости. KEY_BLOCK_SIZE, определенное для индивидуального определения индекса, переопределяет KEY_BLOCK_SIZE на уровне таблицы.

    KEY_BLOCK_SIZE не поддержан на уровне индексов для таблиц InnoDB. См. раздел 14.1.15.

  • index_type

    Некоторые механизмы хранения разрешают Вам определять тип индекса, создавая индекс. Таблица 14.1 показывает допустимые значения типа, поддержанные различными механизмами хранения. Где указано несколько типов, первый это значение по умолчанию, когда не дан спецификатор типа. Механизмы хранения, не перечисленные в таблице, не поддерживают index_type.

    Таблица 14.1. Типы индексов в механизмах хранения

    Механизм хранения Допустимые типы
    InnoDB BTREE
    MyISAM BTREE
    MEMORY /HEAPHASH, BTREE
    NDBHASH, BTREE

    Пример:

    CREATE TABLE lookup (id INT) ENGINE = MEMORY;
    CREATE INDEX id_index ON lookup (id) USING BTREE;
    
    index_type не может использоваться для FULLTEXT INDEX или SPATIAL INDEX.

    Если Вы определяете тип индекса, который не допустим для данного механизма хранения, но доступен другой тип, который механизм может использовать, не затрагивая результаты запроса, механизм использует доступный тип. Анализатор признает RTREE как имя типа, но в настоящее время это не может быть определено ни для какого механизма хранения.

    Использование опции index_type перед ON tbl_name устарело, поддержка использования опции в этой позиции будет удалена в будущем выпуске MySQL. Если index_type дана в ранней и в более поздней позиции, заключительная опция применяется.

    TYPE type_name синоним для USING type_name. Но USING привилегированная форма.

    Для механизмов хранения, которые поддерживают index_type, таблица 14.2 показывает некоторые характеристики индексов.

    Таблица 14.2. Характеристики индексов

    Механизм хранения Индексный типКласс индексаХранит NULL?Разрешены многократные NULL? Тип просмотра IS NULL Тип просмотра IS NOT NULL
    InnoDB BTREEPrimary key НетНетНет данныхНет данных
    UniqueДаДаIndex Index
    KeyДаДаIndex Index
    НеприменимоFULLTEXT ДаДаTableTable
    НеприменимоSPATIAL НетНетНет данныхНет данных
    MyISAM BTREEPrimary key НетНетНет данныхНет данных
    UniqueДаДаIndex Index
    KeyДаДаIndex Index
    НеприменимоFULLTEXTДа ДаTableTable
    НеприменимоSPATIALНет НетНет данныхНет данных
    MEMORY HASHPrimary key НетНетНет данныхНет данных
    UniqueДаДаIndex Index
    KeyДаДаIndex Index
    BTREE PrimaryНетНетНет данных Нет данных
    UniqueДаДаIndex Index
    KeyДаДаIndex Index
  • WITH PARSER parser_name

    Эта опция может использоваться только с FULLTEXT. Это связывает плагин анализатора с индексированием, если полнотекстовая индексация и поиск операций нуждаются в специальной обработке. InnoDB и MyISAM поддерживают полнотекстовые плагины анализатора. См. раздел 26.2.4.4.

  • COMMENT 'string'

    Индексное определение может включать дополнительный комментарий до 1024 символов.

    MERGE_THRESHOLD указывает, как индексные страницы могут быть сконфигурированы для индивидуального индекса использованием index_option и COMMENT в CREATE INDEX:

    CREATE TABLE t1 (id INT);
    CREATE INDEX id_index ON t1 (id) COMMENT 'MERGE_THRESHOLD=40';
    
    Если процент заполнения для индексной страницы падает ниже MERGE_THRESHOLD, когда строка удалена или когда строка сокращена работой обновления, InnoDB пытается слить индексную страницу с соседней индексной страницей. Значение по умолчанию MERGE_THRESHOLD 50.

    MERGE_THRESHOLD может также быть определен на уровне индекса и таблицы через CREATE TABLE и ALTER TABLE, см. раздел 16.6.11.

  • VISIBLE, INVISIBLE

    Изменяет невидимость, индексы видимы по умолчанию. Невидимый индекс не используется оптимизатором. Модификация невидимости индекса относится к первичным ключам (явным или неявным). С MySQL 8.0.1 эта особенность нейтральна для механизма хранения (поддержана для любого механизма). В MySQL 8.0.0 это применяется только к InnoDB, см. раздел 9.3.10.

ALGORITHM и LOCK могут быть даны, чтобы влиять на табличный метод копирования и уровень параллелизма для чтения и записи таблицы в то время, как индексы изменяются. У них есть то же самое значение, что в ALTER TABLE. См. раздел 14.1.7

14.1.13. CREATE PROCEDURE и CREATE FUNCTION

CREATE
[DEFINER = { user | CURRENT_USER }]
PROCEDURE sp_name ([proc_parameter[,...]])
[characteristic ...] routine_body

CREATE
[DEFINER = { user | CURRENT_USER }]
FUNCTION sp_name ([func_parameter[,...]])
RETURNS type
[characteristic ...] routine_body

proc_parameter:
[ IN | OUT | INOUT ] param_name type

func_parameter:
param_name type

type:
Any valid MySQL data type

characteristic:
COMMENT 'string'
  | LANGUAGE SQL
  | [NOT] DETERMINISTIC
  | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }

routine_body:
Valid SQL routine statement
Эти запросы создают сохраненные подпрограммы. По умолчанию подпрограмма связана с базой данных значения по умолчанию. Чтобы связать подпрограмму явно с данной базой данных, определите имя как db_name.sp_name, когда Вы создаете это.

CREATE FUNCTION также используется в MySQL, чтобы поддержать UDF (определяемые пользователем функции). См. раздел 26.4. UDF может быть расценен как внешняя сохраненная функция. Сохраненные функции совместно используют свое пространство имен с UDF. См. раздел 10.2.4.

Чтобы вызвать хранимую процедуру, используйте CALL (см. раздел 14.2.1). Чтобы вызвать сохраненную функцию, обратитесь к ней в выражении. Функция возвращает значение во время оценки выражения.

CREATE PROCEDURE и CREATE FUNCTION требуют привилегию CREATE ROUTINE . Они могли бы также потребовать привилегию SUPER, в зависимости от значения DEFINER, как описано позже в этом разделе. Если двоичное журналирование включено, CREATE FUNCTION может потребовать привилегию SUPER, см. раздел 21.7.

По умолчанию MySQL автоматически предоставляет привилегии ALTER ROUTINE и EXECUTE создателю подпрограммы. Это поведение может быть изменено, отключая automatic_sp_privileges. См. раздел 21.2.2.

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

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

Режим SQL IGNORE_SPACE относится к встроенным функциям, но не к сохраненным подпрограммам. Всегда допустимо иметь пробелы после имени сохраненной подпрограммы, независимо от IGNORE_SPACE значения.

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

Каждый параметр IN это параметр по умолчанию. Чтобы определить иное для параметра, используйте ключевое слово OUT или INOUT перед названием параметра.

Определение параметра как IN, OUT или INOUT допустимо только для PROCEDURE. Для FUNCTION параметры всегда расцениваются как IN.

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

Для каждого OUT или INOUT передайте определяемую пользователем переменную в CALL, которое вызывает процедуру так, чтобы Вы могли получить ее значение, когда процедура возвращается. Если Вы вызываете процедуру изнутри другой хранимой процедуры или функции, Вы можете также передать параметр или местную переменную как IN или INOUT.

На параметры нельзя сослаться в запросах, подготовленных в пределах подпрограммы, см. раздел C.1 .

Следующий пример показывает простую хранимую процедуру, которая использует OUT:

mysql> delimiter //

mysql> CREATE PROCEDURE simpleproc (OUT param1 INT)
    -> BEGIN
    ->   SELECT COUNT(*) INTO param1 FROM t;
    -> END//
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter ;

mysql> CALL simpleproc(@a);
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @a;
+----+
| @a |
+----+
| 3  |
+----+
1 row in set (0.00 sec)
Пример использует команду delimiter, чтобы изменить разделитель запросов с ; на // в то время, как процедура определяется. Это позволяет разделитель ;, используемый в теле процедуры, который пройдет к серверу вместо того, чтобы интерпретироваться mysql. См. раздел 21.1.

RETURNS может быть определен только для FUNCTION, для которой это принудительно. Это указывает на тип возврата функции, и функциональное тело должно содержать команду RETURN value. Если RETURN возвращает значение иного типа, значение приведено к надлежащему типу. Например, если функция определяет ENUM или SET в RETURNS, но RETURN возвращает целое число, значение, возвращенное из функции, является строкой для передачи члена ENUM или SET.

Следующая функция в качестве примера берет параметр, выполняет работу, используя функцию SQL, и возвращает результат. В этом случае не нужно использовать delimiter, потому что функциональное определение не содержит внутренний ;:

mysql> CREATE FUNCTION hello (s CHAR(20))
mysql> RETURNS CHAR(50) DETERMINISTIC
    -> RETURN CONCAT('Hello, ',s,'!');
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT hello('world');
+----------------+
| hello('world') |
+----------------+
| Hello, world!  |
+----------------+
1 row in set (0.00 sec)
Типы параметра и функциональные типы возвращения используют любой допустимый тип данных. COLLATE может использоваться, если предшествующий признак CHARACTER SET.

routine_body состоит из допустимых запросов SQL. Это может быть простым запросом, например, SELECT или INSERT, или составным запросом с BEGIN и END. Составные запросы могут содержать декларации, циклы и другие проверки утверждения структуры. Синтаксис для этих запросов описан в разделе 14.6.

MySQL разрешает подпрограммам содержать запросы DDL, такие как CREATE и DROP. MySQL также разрешает хранимым процедурам (но не сохраненным функциям) содержать операционные запросы SQL, такие как COMMIT. Сохраненные функции, возможно, не содержат запросы, которые явно или неявно закрывают транзакцию. Поддержка этих запросов не требуется стандартом SQL, который заявляет, что каждый поставщик системы управления базами данных может решить, разрешить ли их.

Запросы, которые возвращают набор результатов, могут использоваться в пределах хранимой процедуры, но не в пределах сохраненной функции. Этот запрет включает SELECT, которые не имеют INTO var_list, и другие запросы, например, SHOW, EXPLAIN и CHECK TABLE. Для запросов, которые могут возвратить набор результатов, происходит ошибка Not allowed to return a result set from a function (ER_SP_NO_RETSET). Для запросов, которые могут во времени выполнения возвратить набор результатов, происходит ошибка PROCEDURE %s can't return a result set in the given context ( ER_SP_BADSELECT).

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

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

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

COMMENT расширение MySQL, и может использоваться, чтобы описать сохраненную подпрограмму. Эта информация выведена на экран SHOW CREATE PROCEDURE и SHOW CREATE FUNCTION .

LANGUAGEуказывает на язык, на котором написана подпрограмма. Сервер игнорирует эту характеристику, только подпрограммы SQL поддержаны.

Подпрограмму считают deterministic, если это всегда приводит к тому же самому результату для тех же самых входных параметров, и not deterministic иначе. Если ни один из параметров DETERMINISTIC или NOT DETERMINISTIC не задн в определении, значение по умолчанию NOT DETERMINISTIC. Чтобы объявить, что функция детерминирована, Вы должны определить DETERMINISTIC явно.

Оценка природы подпрограммы основана на honesty создателя: MySQL не проверяет, что подпрограмма, объявленная DETERMINISTIC, свободна от запросов, которые приводят к недетерминированным результатам. Однако, DETERMINISTIC подпрограмма могла бы затронуть результаты. Объявление недетерминированной подпрограммы как NONDETERMINISTIC может привести к неожиданным результатам, заставляя оптимизатор сделать неправильный выбор плана выполнения. Объявление детерминированной подпрограммы как NONDETERMINISTIC могло бы уменьшить работу, заставляя доступную оптимизацию не использоваться.

Если двоичное журналирование включено, DETERMINISTIC влияет на обработку определений подпрограмм MySQL. См. раздел 21.7.

Подпрограмма, которая содержит NOW() (возможно, синонимы) или RAND() недетерминирована, но это может быть безопасно для репликации. Для NOW() двоичной журнал включает timestamp и копирует правильно. RAND() также копирует правильно, пока вызывается только единственный раз во время выполнения подпрограммы. Вы можете рассмотреть timestamp и случайное число как неявные вводы, которые идентичны на ведущем и ведомом устройствах.

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

  • CONTAINS SQL указывает, что подпрограмма не содержит запросы, которые читают или пишут данные. Это значение по умолчанию, если ни одна из этих характеристик не дана явно. Примеры таких запросов SET @x = 1 или DO RELEASE_LOCK('abc'), которые выполняются, но данные не читают и не пишут.

  • NO SQL указывает, что подпрограмма не содержит запросов SQL.
  • READS SQL DATA указывает, что подпрограмма содержит запросы, которые читают данные (например, SELECT ), но не запросы, которые пишут данные.
  • MODIFIES SQL DATA указывает, что подпрограмма содержит запросы, которые могут писать данные (например, INSERT или DELETE).

SQL SECURITY может быть DEFINER или INVOKER, чтобы определить контекст безопасности, то есть, выполняет ли подпрограмма использование привилегий учетной записи, названной в подпрограмме DEFINER или пользователя, который вызывает. У этой учетной записи должно быть разрешение получить доступ к базе данных, с которой связана подпрограмма. Значение по умолчанию DEFINER. Пользователь, который вызывает подпрограмму, должен иметь привилегию EXECUTE для этого.

DEFINER определяет учетную запись MySQL, которая будет использоваться, проверяя привилегии доступа во время выполнения для подпрограмм, которые имеют SQL SECURITY DEFINER.

Если значение user дано для DEFINER, это должна быть учетная запись MySQL, определенная как 'user_name'@'host_name' , CURRENT_USER или CURRENT_USER() . По умолчанию DEFINER это пользователь, который выполняет CREATE PROCEDURE или CREATE FUNCTION. Это то же самое, как определение DEFINER = CURRENT_USER явно.

Если Вы определяете DEFINER, эти правила определяют допустимые пользовательские значения DEFINER:

  • Если Вы не имеете привилегии SUPER, единственное разрешенное значение user Ваша собственная учетная запись, определенная буквально или при использовании CURRENT_USER. Вы не можете установить definer в некоторую другую учетную запись.

  • Если Вы имеете привилегию SUPER , Вы можете определить любое синтаксически допустимое имя учетной записи. Если учетная запись не существует, предупреждение произведено.
  • Хотя возможно создать подпрограмму с несуществующим DEFINER, ошибка происходит во время выполнения, если SQL SECURITY = DEFINER, но учетная запись не существует.

См. раздел 21.6.

В пределах сохраненной подпрограммы, которая определена с SQL SECURITY DEFINER, CURRENT_USER возвращает значение DEFINER. Для информации об аудите пользователей в пределах сохраненных подпрограмм см. раздел 7.3.12.

Рассмотрите следующую процедуру, которая выводит на экран количество учетных записей MySQL, перечисленных в mysql.user:

CREATE DEFINER = 'admin'@'localhost' PROCEDURE account_count()
BEGIN
  SELECT 'Number of accounts:', COUNT(*) FROM mysql.user;
END;
Процедуре назначают DEFINER = 'admin'@'localhost', независимо от того, какой пользователь определяет это. Это выполняется с привилегиями той учетной записи, независимо от того, какой пользователь вызывает это (потому что характеристика безопасности по умолчанию DEFINER). Процедура преуспевает или терпит неудачу в зависимости от того, имеет ли вызывающий привилегию EXECUTE для нее, и имеет ли 'admin'@'localhost' привилегию SELECT на таблице mysql.user.

Теперь предположите, что процедура определена с SQL SECURITY INVOKER:

CREATE DEFINER = 'admin'@'localhost' PROCEDURE account_count()
SQL SECURITY INVOKER
BEGIN
  SELECT 'Number of accounts:', COUNT(*) FROM mysql.user;
END;
У процедуры все еще есть DEFINER = 'admin'@'localhost', но в этом случае, это выполняется с привилегиями пользователя вызова. Таким образом, процедура преуспевает или терпит неудачу в зависимости от того, имеет ли вызывающий привилегию EXECUTE для нее и привилегию SELECT для таблицы mysql.user.

Сервер обрабатывает тип данных параметра, местной переменной, создаваемой DECLARE, или функциональное возвращаемое значение следующим образом:

  • Назначения проверены на несоответствия типа данных и переполнение. Преобразование и проблемы переполнения приводят к предупреждениям или ошибкам в строгом режиме SQL.

  • Только скалярные значения могут быть назначены. Например, такой запрос, как SET x = (SELECT 1, 2) не годится.
  • Для символьных типов данных, если есть CHARACTER SET в декларации, указанный набор символов и его сопоставление по умолчанию используются. Если указан COLLATE, то используется указанное сопоставление, а не сопоставление по умолчанию.

    Если не указаны CHARACTER SET и COLLATE, используются набор символов базы данных и сопоставление в действительности во время создания подпрограммы. Чтобы избежать использования набор символов базы данных и сопоставления сервера, обеспечивают явные параметры CHARACTER SET и COLLATE для символьных параметров данных.

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

    Набор символов базы данных и сопоставление даны значениями character_set_database и collation_database . См. раздел 11.1.3.3.

14.1.14. CREATE SERVER

CREATE SERVER server_name
FOREIGN DATA WRAPPER wrapper_name
OPTIONS (option [, option] ...)

option:
  { HOST character-literal
  | DATABASE character-literal
  | USER character-literal
  | PASSWORD character-literal
  | SOCKET character-literal
  | OWNER character-literal
  | PORT numeric-literal }
Это запрос создает определение сервера для использования с механизмом хранения FEDERATED. CREATE SERVER создает новую строку в таблице servers базы данных mysql. Этот запрос требует привилегии SUPER.

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

wrapper_name должен быть mysql, может быть заключен в кавычки с единственными кавычками. Другие значения для wrapper_name в настоящее время не поддерживаются.

Для каждой option Вы должны определить символьный или числовой литерал. Символьные литералы UTF-8 поддерживают максимальную длину 64 символа и значение по умолчанию пустая строка. Строковые литералы являются тихо усеченными к 64 символам. Числовые должны быть числом между 0 и 9999, по умолчанию 0.

OWNER в настоящее время не применяется и не имеет никакого эффекта на собственность или работу соединения сервера, которое создается.

CREATE SERVER создает запись в таблице mysql.servers, которая может позже использоваться с CREATE TABLE, создавая таблицу FEDERATED. Опции, которые Вы определяете, будут использоваться, чтобы заполнить столбцы в mysql.servers. Столбцы таблицы: Server_name, Host, Db, Username, Password, Port и Socket.

Например:

CREATE SERVER s FOREIGN DATA WRAPPER mysql
       OPTIONS (USER 'Remote', HOST '192.168.1.106', DATABASE 'test');
Убедитесь, что определили все опции, необходимые, чтобы установить соединение с сервером. Имя пользователя, имя хоста и имя базы данных принудительны. Другие опции, такие как пароль, могли бы требоваться также.

Данные в таблице могут использоваться, создавая соединение с таблицей FEDERATED:

CREATE TABLE t (s1 INT) ENGINE=FEDERATED CONNECTION='s';
См. раздел 17.8.

CREATE SERVER автоматически закрывает транзакцию.

В MySQL 8.0 CREATE SERVER не записан в двоичный журнал, независимо от формата журналирования, который используется.

14.1.15. CREATE TABLE

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
(create_definition,...)
[table_options]
[partition_options]

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
[(create_definition,...)]
[table_options]
[partition_options]
[IGNORE | REPLACE]
[AS] query_expression

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
{ LIKE old_tbl_name | (LIKE old_tbl_name) }

create_definition:
col_name column_definition
  | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...)
  [index_option] ...
  | {INDEX|KEY} [index_name] [index_type] (index_col_name,...)
  [index_option] ...
  | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY]
  [index_name] [index_type] (index_col_name,...)
  [index_option] ...
  | {FULLTEXT|SPATIAL} [INDEX|KEY] [index_name] (index_col_name,...)
  [index_option] ...
  | [CONSTRAINT [symbol]] FOREIGN KEY
  [index_name] (index_col_name,...) reference_definition
  | CHECK (expr)

column_definition:
data_type [NOT NULL | NULL] [DEFAULT default_value]
  [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY]
  [COMMENT 'string']
  [COLUMN_FORMAT {FIXED|DYNAMIC|DEFAULT}]
  [reference_definition]
  | data_type [GENERATED ALWAYS] AS (expression)
  [VIRTUAL | STORED] [UNIQUE [KEY]] [COMMENT comment]
  [NOT NULL | NULL] [[PRIMARY] KEY]

data_type:
BIT[(length)]
  | TINYINT[(length)] [UNSIGNED] [ZEROFILL]
  | SMALLINT[(length)] [UNSIGNED] [ZEROFILL]
  | MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL]
  | INT[(length)] [UNSIGNED] [ZEROFILL]
  | INTEGER[(length)] [UNSIGNED] [ZEROFILL]
  | BIGINT[(length)] [UNSIGNED] [ZEROFILL]
  | REAL[(length,decimals)] [UNSIGNED] [ZEROFILL]
  | DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL]
  | FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL]
  | DECIMAL[(length[,decimals])] [UNSIGNED] [ZEROFILL]
  | NUMERIC[(length[,decimals])] [UNSIGNED] [ZEROFILL]
  | DATE
  | TIME[(fsp)]
  | TIMESTAMP[(fsp)]
  | DATETIME[(fsp)]
  | YEAR
  | CHAR[(length)] [BINARY]
  [CHARACTER SET charset_name] [COLLATE collation_name]
  | VARCHAR(length) [BINARY]
  [CHARACTER SET charset_name] [COLLATE collation_name]
  | BINARY[(length)]
  | VARBINARY(length)
  | TINYBLOB
  | BLOB
  | MEDIUMBLOB
  | LONGBLOB
  | TINYTEXT [BINARY]
  [CHARACTER SET charset_name] [COLLATE collation_name]
  | TEXT [BINARY]
  [CHARACTER SET charset_name] [COLLATE collation_name]
  | MEDIUMTEXT [BINARY]
  [CHARACTER SET charset_name] [COLLATE collation_name]
  | LONGTEXT [BINARY]
  [CHARACTER SET charset_name] [COLLATE collation_name]
  | ENUM(value1,value2,value3,...)
  [CHARACTER SET charset_name] [COLLATE collation_name]
  | SET(value1,value2,value3,...)
  [CHARACTER SET charset_name] [COLLATE collation_name]
  | JSON
  | spatial_type

index_col_name:
col_name [(length)] [ASC | DESC]

index_type:
USING {BTREE | HASH}

index_option:
KEY_BLOCK_SIZE [=] value
  | index_type
  | WITH PARSER parser_name
  | COMMENT 'string'
  | {VISIBLE | INVISIBLE}

reference_definition:
REFERENCES tbl_name (index_col_name,...)
  [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
  [ON DELETE reference_option]
  [ON UPDATE reference_option]

reference_option:
RESTRICT | CASCADE | SET NULL | NO ACTION

table_options:
table_option [[,] table_option] ...

table_option:
ENGINE [=] engine_name
  | AUTO_INCREMENT [=] value
  | AVG_ROW_LENGTH [=] value
  | [DEFAULT] CHARACTER SET [=] charset_name
  | CHECKSUM [=] {0 | 1}
  | [DEFAULT] COLLATE [=] collation_name
  | COMMENT [=] 'string'
  | COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'}
  | CONNECTION [=] 'connect_string'
  | DATA DIRECTORY [=] 'absolute path to directory'
  | DELAY_KEY_WRITE [=] {0 | 1}
  | ENCRYPTION [=] {'Y' | 'N'}
  | INDEX DIRECTORY [=] 'absolute path to directory'
  | INSERT_METHOD [=] { NO | FIRST | LAST }
  | KEY_BLOCK_SIZE [=] value
  | MAX_ROWS [=] value
  | MIN_ROWS [=] value
  | PACK_KEYS [=] {0 | 1 | DEFAULT}
  | PASSWORD [=] 'string'
  | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT}
  | STATS_AUTO_RECALC [=] {DEFAULT|0|1}
  | STATS_PERSISTENT [=] {DEFAULT|0|1}
  | STATS_SAMPLE_PAGES [=] value
  | TABLESPACE tablespace_name
  | UNION [=] (tbl_name[,tbl_name]...)

partition_options:
PARTITION BY
{ [LINEAR] HASH(expr)
| [LINEAR] KEY [ALGORITHM={1|2}] (column_list)
| RANGE{(expr) | COLUMNS(column_list)}
| LIST{(expr) | COLUMNS(column_list)} }
[PARTITIONS num]
[SUBPARTITION BY
{ [LINEAR] HASH(expr)
| [LINEAR] KEY [ALGORITHM={1|2}] (column_list) }
  [SUBPARTITIONS num]
]
[(partition_definition [, partition_definition] ...)]

partition_definition:
PARTITION partition_name [VALUES
{LESS THAN {(expr | value_list) | MAXVALUE}
| IN (value_list)}]
[[STORAGE] ENGINE [=] engine_name]
[COMMENT [=] 'comment_text' ]
[DATA DIRECTORY [=] 'data_dir']
[INDEX DIRECTORY [=] 'index_dir']
[MAX_ROWS [=] max_number_of_rows]
[MIN_ROWS [=] min_number_of_rows]
[TABLESPACE [=] tablespace_name]
[(subpartition_definition [, subpartition_definition] ...)]

subpartition_definition:
SUBPARTITION logical_name
[[STORAGE] ENGINE [=] engine_name]
[COMMENT [=] 'comment_text' ]
[DATA DIRECTORY [=] 'data_dir']
[INDEX DIRECTORY [=] 'index_dir']
[MAX_ROWS [=] max_number_of_rows]
[MIN_ROWS [=] min_number_of_rows]
[TABLESPACE [=] tablespace_name]

query_expression:
SELECT ...   (Some valid select or union statement)
CREATE TABLE составляет таблицу с именем. Вы должны иметь привилегию CREATE для таблицы.

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

Имя таблицы может быть определено как db_name.tbl_name, чтобы составлять таблицу в определенной базе данных. Это работает независимо от того, есть ли база данных по умолчанию, предполагая, что база данных существует. Если Вы используете заключенные в кавычки идентификаторы, то заключите в кавычки имена базы данных и имена таблиц отдельно. Например, `mydb`.`mytbl` не `mydb.mytbl`.

Клонирование или копирование таблицы

CREATE TABLE ... LIKE составляет пустую таблицу, основанную на определении другой таблицы, включая любые параметры столбца и индексы, определенные в оригинальной таблице:

CREATE TABLE new_tbl LIKE orig_tbl;
См. раздел 14.1.15.1.

Чтобы составить одну таблицу от другой, добавьте SELECT в конце CREATE TABLE:

CREATE TABLE new_tbl SELECT * FROM orig_tbl;
См. раздел 14.1.15.2.

Временные таблицы

Вы можете использовать ключевое слово TEMPORARY, составляя таблицу. Таблица TEMPORARY видима только текущему сеансу и удалена автоматически, когда сеанс закрыт. Это означает, что два различных сеанса могут использовать то же самое временное имя таблицы, не находясь в противоречии друг с другом или с существующими не-TEMPORARY таблицами. Существующая таблица скрыта, пока временная таблица не удалена. Чтобы составить временные таблицы, Вы должны иметь привилегию CREATE TEMPORARY TABLES.

InnoDB не поддерживает сжатые временные таблицы. Когда innodb_strict_mode включен (значение по умолчанию), CREATE TEMPORARY TABLE возвращает ошибку, если ROW_FORMAT=COMPRESSED или указан KEY_BLOCK_SIZE. Если innodb_strict_mode отключен, предупреждения выпущены, и временная таблица составлена, используя несжатый формат строки. Временные таблицы InnoDB составлены в совместно используемом временном табличном пространстве ibtmp1. innodb_file_per-table не затрагивает создание временных таблиц InnoDB.

CREATE TABLE автоматически не закрывает текущую активную транзакцию, если Вы используете ключевое слово TEMPORARY.

Таблицы TEMPORARY имеют очень свободные отношения с базами данных (схемами). Удаление базы данных автоматически не удаляет таблицы TEMPORARY в пределах той базы данных. Кроме того, Вы можете создать таблицу TEMPORARY в несуществующей базе данных, если Вы квалифицируете имя таблицы с именем базы данных в CREATE TABLE. В этом случае все последующие ссылки на таблицу должны быть квалифицированы с именем базы данных.

Существующая таблица с тем же самым именем

Ключевые слова IF NOT EXISTS не дают ошибке произойти, если таблица существует. Однако, нет никакой проверки, что у существующей таблицы есть структура, идентичная обозначенной в CREATE TABLE.

Физическое представление

Для таблицы InnoDB в табличном пространстве file-per-table или общем табличном пространстве табличных данные и связанные индексы сохранены в файле ibd в каталоге базы данных. Когда таблица InnoDB составлена в системном табличном пространстве, табличные данные и индексы сохранены в файлах ibdata*, которые представляют системное табличное пространство. innodb_file_per_table управляет, составлены ли таблицы в табличных пространствах file-per-table или системном табличном пространстве по умолчанию. Опция TABLESPACE может использоваться, чтобы поместить таблицу в табличное пространство file-per-table, общее табличное пространство или системное табличное пространство, независимо от innodb_file_per_table .

Для MyISAM механизм хранения создает файлы с данными и индексные файлы. Таким образом, для каждой таблицы MyISAM tbl_name есть два дисковых файла.

ФайлНазначение
tbl_name.MYD Данные
tbl_name.MYI Индексы

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

Типы данных и признаки для столбцов

data_type представляет тип данных в определении столбца. spatial_type представляет пространственный тип данных. Показанный синтаксис типа данных является только образцом. Для полного описания синтаксиса, доступного для определения типов данных столбца, так же как и для информации о свойствах каждого типа см. главу 12 и раздел 12.5. Тип данных JSON также поддержан для столбцов таблицы, см. раздел 12.6.

Некоторые признаки не относятся ко всем типам данных. AUTO_INCREMENT применяется только к целому числу и типам с плавающей запятой. DEFAULT не относится к типам BLOB, TEXT, GEOMETRY и JSON.

  • Если NULL или NOT NULL не определен, столбец обработан как если бы был определен NULL.

  • У целого числа или столбца с плавающей запятой может быть дополнительный признак AUTO_INCREMENT. Когда Вы вставляете значение NULL (рекомендуемый) или 0 в индексированный столбец AUTO_INCREMENT, столбец установлен в следующее значение последовательности. Как правило, это value+1 , где value самое большое значение для столбца в настоящее время в таблице. Последовательности AUTO_INCREMENT начинаются с 1.

    Чтобы получить значение AUTO_INCREMENT после вставки строки, используйте LAST_INSERT_ID() или mysql_insert_id() C API. См. разделы 13.14 и 25.8.7.38.

    Если включен режим SQL NO_AUTO_VALUE_ON_ZERO, Вы можете сохранить 0 в столбец AUTO_INCREMENT именно как 0, не производя новое значение последовательности. См. раздел 6.1.8.

    Может быть только один столбец AUTO_INCREMENT на таблицу, это должно быть индексировано, и у этого не может быть значения DEFAULT. AUTO_INCREMENT работает должным образом, только если он содержит только положительные значения. Вставка отрицательного числа расценена как вставка очень большого положительного числа. Это сделано, чтобы избежать проблем точности, когда числа переходят с положительных на отрицательне и также гарантировать, что Вы случайно не дойдете до 0 в AUTO_INCREMENT.

    Для MyISAM Вы можете определить вторичный столбец AUTO_INCREMENT в ключе из нескольких столбцов. См. раздел 4.6.9.

    Чтобы сделать MySQL совместимым с некоторыми приложениями ODBC, Вы можете найти AUTO_INCREMENT для последней вставленной строки следующим запросом:

    SELECT * FROM tbl_name WHERE auto_col IS NULL
    
    Этот метод требует, чтобы sql_auto_is_null не был 0. См. раздел 6.1.5.

    Для информации о InnoDB и AUTO_INCREMENT см. раздел 16.8.5. Для информации о AUTO_INCREMENT и репликации MySQL см. раздел 19.4.1.1 .

  • Символьные типы данных (CHAR, VARCHAR, TEXT) могут включать атрибуты CHARACTER SET и COLLATE, чтобы определить набор символов и сопоставление для столбца. Для деталей см. раздел 11.1. CHARSET синоним для CHARACTER SET:
    CREATE TABLE t (c CHAR(20) CHARACTER SET utf8 COLLATE utf8_bin);
    
    MySQL 8.0 интерпретирует технические требования длины в символьных определениях столбца в символах. Длины для BINARY и VARBINARY в байтах.
  • DEFAULT определяет значение по умолчанию для столбца. С одним исключением значение по умолчанию должно быть константой, это не может быть функция или выражение. Это означает, например, что Вы не можете установить значение по умолчанию для столбца даты, чтобы быть значением функции, такой как NOW() или CURRENT_DATE. Исключение: Вы можете определить CURRENT_TIMESTAMP как значение по умолчанию для TIMESTAMP или DATETIME . См. раздел 12.3.5.

    Если определение столбца включает неявное значение DEFAULT, MySQL определяет значение по умолчанию как описано в раздел 12.7.

    BLOB, TEXT и JSON нельзя назначить значение по умолчанию.

    Если режим SQL NO_ZERO_DATE или NO_ZERO_IN_DATE включен, и значение даты по умолчанию не правильно, согласно тому режиму, CREATE TABLE производит предупреждение, если строгий режим SQL не включен, и ошибку, если строгий режим включен. Например, с включенным NO_ZERO_IN_DATE c1 DATE DEFAULT '2010-00-00' производит предупреждение.

  • Комментарий для столбца может быть определен опцией COMMENT до 1024 символов в длину. Комментарий выведен на экран SHOW CREATE TABLE и SHOW FULL COLUMNS.
  • COLUMN_FORMAT используется MySQL Cluster, чтобы определить формат хранения столбца. Эта опция в настоящее время не имеет никакого эффекта на столбцы таблиц, используя механизмы хранения, кроме NDB. В MySQL 8.0 и выше COLUMN_FORMAT тихо проигнорирован.
  • KEY синоним для INDEX. Ключевой признак PRIMARY KEY может также быть определен как только KEY дано в определении столбца. Это было осуществлено для совместимости с другими системами базы данных.
  • Индекс UNIQUE создает ограничение, таким образом, что все значения в индексировании должны быть отличными. Ошибка происходит, если Вы пытаетесь добавить новую строку со значением ключа, которое соответствует существующей строке. Для всех механизмов UNIQUE разрешает многократные значения NULL для столбцов, которые могут содержать NULL.
  • PRIMARY KEY уникальный индекс, где все ключевые столбцы должны быть определены как NOT NULL. Если они явно не объявлены как NOT NULL, MySQL объявляет их так неявно (и тихо). У таблицы может быть только один PRIMARY KEY. Имя PRIMARY KEY всегда PRIMARY, который таким образом не может использоваться как имя любого другого индекса.

    Если у Вас нет PRIMARY KEY и приложение просит PRIMARY KEY в Ваших таблицах, MySQL возвращает первый индекс UNIQUE, который не имеет столбцов NULL, как PRIMARY KEY.

    В InnoDB сохраните PRIMARY KEY коротким, чтобы минимизировать хранение для вторичного индекса. Каждая запись вторичного индекса содержит копию столбцов первичного ключа для соответствующей строки. См. раздел 16.8.8.

  • В составленной таблице PRIMARY KEY помещен сначала, сопровождается всеми UNIQUE и затем групповые индексы. Это помогает оптимизатору MySQL расположить по приоритетам, которые индексы использовать, а также более быстро обнаружить дублированный ключ UNIQUE.
  • PRIMARY KEY может быть многостолбцовым. Однако, Вы не можете создать многостолбцовый индекс с использованием PRIMARY KEY в спецификации столбца. Выполнение этого только помечает единственный столбец как основной. Вы должны использовать отдельный параметр PRIMARY KEY(index_col_name, ...).
  • Если PRIMARY KEY или UNIQUE состоит только из одного столбца, у которого есть тип целого числа, Вы можете также обратиться к столбцу как к _rowid в SELECT.
  • В MySQL имя PRIMARY KEY PRIMARY. Для других индексов, если Вы не назначаете имя, индексу назначают имя первого индексированного столбца с дополнительным суффиксом (_2, _3, ...), чтобы сделать это уникальным. Вы можете видеть названия для таблицы, используя SHOW INDEX FROM tbl_name. См. раздел 14.7.5.22.
  • Некоторые механизмы хранения разрешают Вам определять тип индекса, создавая индексирование. Синтаксис для index_type: USING type_name.

    Например:

    CREATE TABLE lookup (id INT, INDEX USING BTREE (id)) ENGINE = MEMORY;
    
    Привилегированная позиция для USING после списка столбцов индекса. Это может быть дано перед списком столбца, но поддержка использования опции в той позиции устарела и будет удалена в будущем выпуске MySQL.

    index_option определяют дополнительные опции для индекса. USING одна такая опция. WITH PARSER может использоваться только с FULLTEXT. Это связывает плагин анализатора с индексированием, если полнотекстовая индексация и поиск операций нуждаются в специальной обработке. InnoDB и MyISAM поддерживают полнотекстовые плагины анализатора. Если у Вас есть таблица MyISAM со связанным полнотекстовым плагином анализатора, Вы можете преобразовать таблицу в InnoDB через ALTER TABLE.

  • В MySQL 8.0 только InnoDB, MyISAM и MEMORY поддерживают индекс на столбцах, которые могут иметь значения NULL. В других случаях Вы должны объявить индексированные столбцы как NOT NULL или будет ошибка.
  • Для CHAR, VARCHAR, BINARY и VARBINARY может быть создан индекс, который использует только начальную часть значений столбцов, используя col_name( length), чтобы определить длину префикса. BLOB и TEXT также могут быть индексированы, но длина префикса должна быть задана явно. Длины префикса даны в символах для недвоичных строковых типов и в байтах для двоичных строковых типов. Таким образом, индексная запись состоит из первых length символов каждого значения столбца для CHAR, VARCHAR и TEXT или первых length байт каждого значения столбца для BINARY, VARBINARY и BLOB. Индексация только префиксов значений столбцов может сделать индексный файл намного меньшим. Для дополнительной информации о префиксах см. раздел 14.1.12.

    Только InnoDB и MyISAM имеют поддержку индексов BLOB и TEXT:

    CREATE TABLE test (blob_col BLOB, INDEX(blob_col(10)));
    
    Префиксы могут составить до 767 байтов для таблиц InnoDB, которые используют формат строки REDUNDANT или COMPACT. Предел длины поднят до 3072 байтов для таблиц InnoDB, которые используют формат строки DYNAMIC или COMPRESSED . Для MyISAM предел префикса составляет 1000 байт.

    Пределы префиксов измерены в байтах, тогда как длина префикса в CREATE TABLE, ALTER TABLE и CREATE INDEX интерпретируется как число символов для недвоичных строковых типов (CHAR, VARCHAR, TEXT) и число байтов для двоичных строковых типов (BINARY, VARBINARY, BLOB). Примите это во внимание, определяя длину префикса для недвоичного строкового столбца, который использует многобайтовый набор символов.

  • index_col_name может закончиться ASC или DESC. Эти ключевые слова разрешены для будущих расширений для того, чтобы определить хранение значения по возрастанию или убыванию. В настоящее время они разобраны, но проигнорированы, индексные значения всегда сохранены в порядке возрастания.
  • Когда Вы используете ORDER BY или GROUP BY на столбце в SELECT, сервер сортирует значения, используя только начальное число байтов, обозначенное max_sort_length.
  • Вы можете создать особенный индекс FULLTEXT, который используется для полнотекстовых поисков. Только InnoDB и MyISAM имеют поддержку FULLTEXT. Они могут быть созданы только из столбцов CHAR, VARCHAR и TEXT. Индексация всегда происходит по всему столбцу, префиксы столбца не поддержаны, любая длина префикса проигнорирована, если определена. См. раздел 13.9. WITH PARSER может быть определен как index_option, чтобы связать плагин анализатора с индексированием, если полнотекстовая индексация и поиск операций нуждаются в специальной обработке. Этот пункт допустим только для FULLTEXT. InnoDB и MyISAM поддерживают полнотекстовые плагины анализатора. См. раздел 26.2.4.4.
  • Вы можете создать индекс SPATIAL на пространственных типах данных. Пространственные типы поддержаны только для InnoDB и MyISAM, и индексированные столбцы должны быть объявлены как NOT NULL. См. раздел 12.5.
  • Произведенные сохраненные столбцы могут быть индексированы. InnoDB поддерживает вторичные индексы на произведенных виртуальных столбцах. См. раздел 14.1.15.6.
  • Столбцы JSON не могут быть индексированы. Вы можете создать индекс на произведенном столбце, который извлекает скалярное значение из JSON. См. раздел 14.1.15.6.
  • В MySQL 8.0 определение индекса может включать дополнительный комментарий до 1024 символов.
  • InnoDB поддерживают проверку ограничений внешнего ключа. Столбцы таблицы, на которую ссылаются, нужно всегда явно называть. ON DELETE и ON UPDATE действуют на внешних ключах. Для более подробной информации и примеров см. раздел 14.1.15.3.

    Для других механизмов хранения MySQL Server разбирает и игнорирует FOREIGN KEY и REFERENCES в CREATE TABLE. Параметр CHECK разобран, но проигнорирован всеми механизмами хранения. См. раздел 1.8.2.3.

    Для пользователей, знакомых с ANSI/ISO SQL Standard, отметьте, что никакой механизм хранения, включая InnoDB, не признает или проводит в жизнь MATCH, используемый в определениях ограничения целостности. Использование явного MATCH не будет иметь указанного эффекта, и также вызывает ON DELETE и ON UPDATE, которые будут проигнорированы. По этим причинам, определять MATCH не надо.

    MATCH в SQL управляет тем, как значения NULL в соединенном (многократные столбцы) внешнем ключе обработаны, сравниваясь с первичным ключом. InnoDB по существу осуществляет семантику, определенную MATCH SIMPLE, которая разрешают внешнему ключу быть всему или частично NULL. В этом случае строке дочерней таблицы, содержащей такой внешний ключ, разрешают быть вставленной и не соответствовать строке в родительской таблице, на которую ссылаются. Возможно осуществить другую семантику, используя триггеры.

    Дополнительно, MySQL требует, чтобы столбцы, на которые ссылаются, были индексированы для работы. Однако, InnoDB не проводит в жизнь требования что столбцы, на которые ссылаются, должны быть объявлены UNIQUE или NOT NULL. Обработка ссылок внешнего ключа на групповые ключи или ключи, которые содержат NULL, не четко определены для таких операций, как UPDATE или DELETE CASCADE. Вам советуют использовать внешние ключи, которые ссылаются только на ключи, которые являются UNIQUE (или PRIMARY) и NOT NULL сразу.

    MySQL разбирает, но игнорирует inline REFERENCES specifications (как определено в стандарте SQL), где ссылки определены как часть спецификации столбца. MySQL принимает REFERENCES только когда определено, как часть отдельной специфиувции FOREIGN KEY.

    Разделенные таблицы, использующие InnoDB, не поддерживают внешние ключи. См. раздел 20.6.

  • Есть жесткий предел 4096 столбцов на таблицу, но эффективный максимум может быть меньше для данной таблицы и зависит от факторов, обсужденных в разделе C.10.4.

Механизмы хранения

Опция ENGINE определяет механизм хранения для таблицы, используя одно из имен, показанных в следующей таблице. Имя механизма может быть взято в кавычки. Заключенное в кавычки имя 'DEFAULT' признано, но проигнорировано.

Механизм хранения Описание
InnoDB Транзакционно-безопасные таблицы с блокировкой строки и внешними ключами. Механизм хранения значения по умолчанию для новых таблиц. См. главу 16.
MyISAM Двоичной механизм хранения, который прежде всего используется для рабочих нагрузок, главным образом, чтения или только для чтения. См. раздел 17.2.
MEMORYДанные для этого механизма хранятся только в памяти. См. раздел 17.3.
CSVТаблицы, которые хранят строки в отделенном запятыми формате значений. См. раздел 17.4.
ARCHIVE Механизм хранения архивирования. См. раздел 17.5.
EXAMPLE Механизм в качестве примера. См. раздел 17.9.
FEDERATED Механизм хранения, который получает доступ к удаленным таблицам. См. раздел 17.8.
HEAPСиноним для MEMORY.
MERGEНабор таблиц MyISAM, используемых в качестве одной таблицы. Также известен как MRG_MyISAM. См. раздел 17.7.

По умолчанию, если определен механизм хранения, который не доступен, запрос терпит неудачу с ошибкой. Вы можете переопределить это поведение, удаляя режим SQL NO_ENGINE_SUBSTITUTION (см. раздел 6.1.8), чтобы MySQL позволил замену указанного механизма механизмом хранения по умолчанию вместо этого. Обычно в таких случаях это InnoDB, который является значением по умолчанию для default_storage_engine. Когда NO_ENGINE_SUBSTITUTION выключен, предупреждение происходит, если спецификация механизма хранения не соблюдается.

Оптимизация работы

Другие табличные опции используются, чтобы оптимизировать поведение таблицы. В большинстве случаев Вы не должны определить ни одну из них. Эти опции относятся ко всем механизмам хранения, если иное не обозначено. Опции, которые не относятся к данному механизму хранения, могут быть приняты как часть табличного определения. Такие опции тогда применяются, если Вы позже используете ALTER TABLE, чтобы преобразовать таблицу, чтобы использовать различный механизм хранения.

  • AUTO_INCREMENT

    Начальное AUTO_INCREMENT значение для таблицы. В MySQL 8.0 это работает на таблицах MyISAM, MEMORY, InnoDB и ARCHIVE. Установить первое значение для механизмов, которые не поддерживают AUTO_INCREMENT, вставьте строку со значением меньше, чем требуемое значение после составления таблицы, и затем удалите фиктивную строку.

    Для механизмов, которые поддерживают AUTO_INCREMENT в CREATE TABLE, Вы можете также использовать ALTER TABLE tbl_name AUTO_INCREMENT = N, чтобы сбрасывать AUTO_INCREMENT. Значение не может в настоящее время устанавливаться ниже, чем максимальное значение в столбце.

  • AVG_ROW_LENGTH

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

    Когда Вы создаете MyISAM, MySQL использует MAX_ROWS и AVG_ROW_LENGTH, чтобы решить, насколько большая будет таблица. Если Вы не определяете ни одну опцию, максимальный размер для MyISAM по умолчанию 256 TB. Если Ваша операционная система не поддерживает большие файлы, табличные размеры ограничены пределом размера файла. Если Вы хотите подавить размеры указателя, чтобы сделать индексирование меньше и быстрее и Вы действительно не нуждаетесь в больших файлах, Вы можете уменьшить размер указателя по умолчанию, устанавливая myisam_data_pointer_size. См. раздел 6.1.5. Если Вы хотите, чтобы все Ваши таблицы были в состоянии вырасти выше значения по умолчанию и готовы, что Ваши таблицы немного медленнее и больше, чем необходимо, Вы можете увеличить размер указателя по умолчанию, устанавливая эту переменную. Установка значения 7 увеличит размер таблицы до 65536 TB.

  • [DEFAULT] CHARACTER SET

    Определите набор символов значения по умолчанию для таблицы. CHARSET синоним CHARACTER SET. Если имя набора символов DEFAULT, набор символов базы данных используется.

  • CHECKSUM

    Установите это в 1, если Вы хотите, чтобы MySQL поддержал живую контрольную сумму для всех строк (то есть, контрольная сумма, которую MySQL обновляет автоматически, поскольку таблица изменяется). Это делает таблицу немного медленнее, чтобы обновить, но также и облегчает поиск поврежденных таблиц. Запрос CHECKSUM TABLE сообщает о контрольной сумме (только MyISAM).

  • [DEFAULT] COLLATE

    Определите сопоставление по умолчанию для таблицы.

  • COMMENT

    Комментарий для таблицы до 2048 символов.

    Установка InnoDB MERGE_THRESHOLD с табличными комментариями. MERGE_THRESHOLD для индексных страниц может быть сконфигурирован для индексов таблицы InnoDB через параметр COMMENT в CREATE TABLE:

    CREATE TABLE t1 (id INT, KEY id_index (id)) COMMENT='MERGE_THRESHOLD=45';
    
    Если процент заполнения страницы для индексной страницы падает ниже MERGE_THRESHOLD, когда строка удалена или сокращена работой обновления, InnoDB пытается слить индексную страницу с соседней индексной страницей. Значение по умолчанию 50.

    MERGE_THRESHOLD может также быть определен для индексов таблиц InnoDB через ALTER TABLE (опция COMMENT). MERGE_THRESHOLD может быть определен для индивидуального индекса через использование CREATE INDEX или опции COMMENT в CREATE TABLE или ALTER TABLE. См. раздел 16.6.11.

  • COMPRESSION

    Алгоритм сжатия, используемый для сжатия уровня страницы таблиц InnoDB. Поддержанные значения включают Zlib, LZ4 и None. Атрибут COMPRESSION был начат с прозрачной особенности сжатия страницы. Сжатие страницы поддержано только с InnoDB, которые находятся в табличных пространствах file-per-table и доступны только на Linux и Windows, которые поддерживают редкие файлы и hole punching. См. раздел 16.9.2.

  • CONNECTION

    Строка подключения для таблицы FEDERATED.

    Более старые версии MySQL использовали опцию COMMENT для строки подключения.

  • DATA DIRECTORY, INDEX DIRECTORY

    Для InnoDB DATA DIRECTORY='directory ' позволяет Вам создавать табличные пространства file-per-table вне каталога данных MySQL. В пределах каталога, который Вы определяете, MySQL создает подкаталог, соответствующий имени базы данных, а в его этого файл .ibd для таблицы. Опция innodb_file_per_table должна быть включена для работы DATA DIRECTORY с InnoDB. Полный путь к каталогу должен быть определен. См. раздел 16.7.5.

    Создавая таблицы MyISAM, Вы можете использовать DATA DIRECTORY='directory', INDEX DIRECTORY='directory' или обе. Они определяют, куда поместить файлы MyISAM. В отличие от таблицы InnoDB, MySQL не создает подкаталоги, которые соответствуют имени базы данных, создавая таблицу MyISAM с DATA DIRECTORY или INDEX DIRECTORY. Файлы создаются в каталоге, который определен.

    Опции табличного уровня DATA DIRECTORY и INDEX DIRECTORY проигнорированы для разделенных таблиц (Bug #32091).

    Эти опции работают только, когда Вы не используете --skip-symbolic-links. У Вашей операционной системы должен также быть безопасный для потоков вызов realpath(). См. раздел 9.12.2.2.

    Если MyISAM составлена без DATA DIRECTORY, фпйл .MYD создается в каталоге базы данных. По умолчанию, если MyISAM находит существующий файл .MYD в этом случае, он перезаписывает его. То же самое относится к файлам .MYI для таблиц, составленных без INDEX DIRECTORY. Чтобы подавить это поведение, запустите сервер с --keep_files_on_create, тогда MyISAM не будет перезаписывать существующие файлы и возвращает ошибку вместо этого.

    Если MyISAM составлена с опцией DATA DIRECTORY или INDEX DIRECTORY и существующий файл .MYD или .MYI найден, MyISAM всегда возвращает ошибку. Это не будет перезаписывать файл в указанном каталоге.

    Вы не можете использовать пути, которые содержат каталог данных MySQL с DATA DIRECTORY или INDEX DIRECTORY. Это включает разделенные таблицы и отдельное табличное разделение (см. Bug #32167).

  • DELAY_KEY_WRITE

    Установите это в 1, если Вы хотите задержать ключевые обновления для таблицы, пока таблица не закрыта. См. описание delay_key_write в разделе 6.1.5 (только MyISAM).

  • ENCRYPTION

    Установите опцию ENCRYPTION в 'Y', чтобы включить шифрованию данных на уровне страницы для таблиц InnoDB в табличном пространстве file-per-table. Значения опции не являются чувствительными к регистру. ENCRYPTION была введена с особенностью шифрования табличного пространства InnoDB, см. раздел 16.7.10. Плагин keyring_file должен быть загружен для использования опции ENCRYPTION.

  • INSERT_METHOD

    Если Вы хотите вставить данные в таблицу MERGE, Вы должны определить с INSERT_METHOD таблицу, в которую должна быть вставлена строка. INSERT_METHOD опция, полезная для таблиц MERGE. Используйте значение FIRST или LAST, чтобы вставить в первую или последнюю таблицу, или значение NO, чтобы не вставлять вообще. См. раздел 17.7.

  • KEY_BLOCK_SIZE

    Для MyISAM KEY_BLOCK_SIZE произвольно определяет размер в байтах, чтобы использовать для индексных ключевых блоков. Значение обработано как подсказка, иной размер может использоваться в случае необходимости. KEY_BLOCK_SIZE определенное для индивидуального индекса, переопределяет значение на уровне таблицы.

    Для InnoDB KEY_BLOCK_SIZE произвольно определяет размер страницы (в килобайтах), чтобы использовать для сжатых таблиц. Значение обработано как подсказка, иной размер может использоваться в случае необходимости. KEY_BLOCK_SIZE может быть только меньше или равно innodb_page_size . Значение 0 представляет сжатый размер страницы по умолчанию, который является половиной innodb_page_size. В зависимости от innodb_page_size , возможные значения KEY_BLOCK_SIZE включают 0, 1, 2, 4, 8 и 16. См. раздел 16.9.1.

    Oracle рекомендует включить innodb_strict_mode, определяя KEY_BLOCK_SIZE для InnoDB. Когжда innodb_strict_mode включен, определение недопустимого KEY_BLOCK_SIZE возвращает ошибку. Если innodb_strict_mode выключен, недопустимое значение KEY_BLOCK_SIZE вернет предупреждение, а опция KEY_BLOCK_SIZE проигнорирована.

    InnoDB поддерживает KEY_BLOCK_SIZE только на табличном уровне.

    KEY_BLOCK_SIZE не поддержан с 32k и 64k innodb_page_size . Табличное сжатие не поддерживает эти размеры страниц.

    С MySQL 8.0.0 InnoDB не поддерживает KEY_BLOCK_SIZE, составляя временные таблицы.

  • MAX_ROWS

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

    Максимум MAX_ROWS 4294967295, большие значения являются усеченными к этому пределу.

  • MIN_ROWS

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

  • PACK_KEYS

    PACK_KEYS вступает в силу только с MyISAM. Установите эту опцию в 1, если Вы хотите иметь меньший индекс. Это обычно делает обновления медленнее и читает быстрее. Установка опции к 0 отключает всю упаковку ключей. Установка этого к DEFAULT говорит механизму хранения упаковывать только большие столбцы CHAR, VARCHAR, BINARY или VARBINARY.

    Если Вы не используете PACK_KEYS, значение по умолчанию должно упаковать строки, но не числа. Если Вы используете PACK_KEYS=1, числа упакованы также.

    При упаковке двоичных числовых ключей MySQL использует сжатие префиксов:

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

    • Указатель на строку сохранен в порядке "старший байт сначала" непосредственно после ключа, чтобы улучшить сжатие.

    Это означает, что, если у Вас есть много равных ключей на двух последовательных строках, все последующие ключи обычно берут только два байта (включая указатель на строку). Сравните это с обычным случаем, где следующие ключи берут по storage_size_for_key + pointer_size (где размер указателя обычно 4). Наоборот, Вы извлекаете существенную пользу из сжатия, только если у Вас есть много чисел, которые являются теми же самыми. Если все ключи полностью отличаются, Вы используете один байт на ключ больше, если ключ не может иметь NULL. В этом случае упакованная длина ключа сохранена в том же самом байте, который используется, чтобы отметить, что ключ NULL.

  • PASSWORD

    Не используется.

  • ROW_FORMAT

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

    Для InnoDB:

    • Формат строки по умолчанию определен innodb_default_row_format, у которого есть настройка по умолчанию DYNAMIC. Формат строки по умолчанию используется, когда опция ROW_FORMAT не определена или когда используется ROW_FORMAT=DEFAULT.

      Если ROW_FORMAT не определена или ROW_FORMAT=DEFAULT, операции, которые пересоздают таблицу, также тихо изменяют формат строки таблицы к значению по умолчанию, определенному innodb_default_row_format. См. раздел 16.10.2.

    • Для более эффективного хранения типов данных, особенно BLOB, лучше DYNAMIC. См. раздел 16.10.3.
    • Чтобы включить сжатие для InnoDB, определите ROW_FORMAT=COMPRESSED. Опция ROW_FORMAT=COMPRESSED не поддержана, составляя временные таблицы. См. раздел 16.9.
    • Формат строки, используемый в более старых версиях MySQL, можно все еще требовать, определяя формат REDUNDANT.
    • Когда Вы определяете ROW_FORMAT не по умолчанию, рассмотрите также включение innodb_strict_mode.
    • ROW_FORMAT=FIXED не поддержан. Если ROW_FORMAT=FIXED определен в то время, как innodb_strict_mode выключен, InnoDB выпускает предупреждение и предполагает ROW_FORMAT=COMPACT. Если ROW_FORMAT=FIXED определен в то время, как innodb_strict_mode включен, InnoDB возвращает ошибку.
    • См. раздел 16.10.

    Для MyISAM значение опции может быть FIXED или DYNAMIC для формата строки статической или переменной длины. myisampack устанавливает тип в COMPRESSED. См. раздел 17.2.3.

    Выполняя CREATE TABLE, если Вы определяете формат строки, который не поддержан механизмом хранения, который используется для таблицы, таблица создается, используя формат строки по умолчанию для механизма хранения. Информация в этом столбце ответа SHOW TABLE STATUS показывает фактический используемый формат строки. Это может отличаться от значения в столбце Create_options, поскольку оригинал CREATE TABLE определения сохранен во время создания.

  • STATS_AUTO_RECALC

    Определяет, вычислить ли повторно автоматически постоянную статистику для InnoDB. DEFAULT заставляет постоянную установку статистики для таблицы быть определенной опцией innodb_stats_auto_recalc. Значение 1 указывает, что статистика повторно вычислена, когда 10% данных в таблице изменились. Значение 0 предотвращает автоматический пересчет для этой таблицы, с этой установкой используйте ANALYZE TABLE, чтобы повторно вычислить статистику после создания существенных изменений таблицы. Для получения дополнительной информации о постоянной статистике см. раздел 16.6.10.1.

  • STATS_PERSISTENT

    Определяет, включить ли постоянную статистику для InnoDB. DEFAULT заставляет постоянную статистику для таблицы быть определенной опцией innodb_stats_persistent. Значение 1 включает постоянную статистику для таблицы, в то время как значение 0 выключает. После включения постоянной статистике через CREATE TABLE или ALTER TABLE скомандуйте ANALYZE TABLE, чтобы вычислить статистику после загрузки представительных данных в таблицу. Для получения дополнительной информации о постоянной статистике см. раздел 16.6.10.1.

  • STATS_SAMPLE_PAGES

    Число индексных страниц, оценивая количество элементов и другую статистику для индексированного столбца, такую как вычисленная ANALYZE TABLE. См. раздел 16.6.10.1.

  • TABLESPACE

    TABLESPACE может использоваться, чтобы составить таблицу в существующем общем табличном пространстве, табличном пространстве file-per-table или системном табличном пространстве.

    CREATE TABLE tbl_name ...
           TABLESPACE [=] tablespace_name
    
    См. раздел 16.7.9.

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

    TABLESPACE может использоваться, чтобы назначить табличное разделение или подразделение к общему табличному пространству, отдельному табличному пространству file-per-table или системному табличному пространству. Все разделение должно принадлежать тому же самому механизму хранения.

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

    mysql> CREATE TABLE t1 (a INT NOT NULL, PRIMARY KEY (a))
        ->        ENGINE=InnoDB TABLESPACE ts1
        ->        PARTITION BY RANGE (a) PARTITIONS 3 (
        ->        PARTITION P1 VALUES LESS THAN (2),
        ->        PARTITION P2 VALUES LESS THAN (4) TABLESPACE ts2,
        ->        PARTITION P3 VALUES LESS THAN (6) TABLESPACE ts3);
    
    См. раздел 16.7.9.

    Чтобы составить таблицу в системном табличном пространстве, определите innodb_system как имя табличного пространства.

    CREATE TABLE tbl_name ... TABLESPACE [=] innodb_system
    
    Используя TABLESPACE [=] innodb_system, Вы можете поместить таблицу любого несжатого формата строки в системном табличном пространстве, независимо от innodb_file_per_table. Например, Вы можете добавить таблицу с ROW_FORMAT=DYNAMIC к системному табличному пространству, используя TABLESPACE [=] innodb_system.

    Чтобы составить таблицу в табличном пространстве file-per-table, определите innodb_file_per_table как имя табличного пространства.

    CREATE TABLE tbl_name ... TABLESPACE [=] innodb_file_per_table
    

    Если включена innodb_file_per_table, Вы не должны определять TABLESPACE=innodb_file_per_table при создании табличного пространства file-per-table. Таблицы InnoDB составлены в табличных пространствах file-per-table по умолчанию, когда включена опция innodb_file_per_table.

    DATA DIRECTORY допустим с CREATE TABLE ... TABLESPACE=innodb_file_per_table, но иное не поддержано для использования в комбинации с опцией TABLESPACE.

    TABLESPACE поддержана с ALTER TABLE и ALTER TABLE ... REORGANIZE PARTITION , которые могут использоваться, чтобы переместить таблицы и разделение от одного табличного пространства в другое, соответственно. Для получения дополнительной информации см. раздел 16.7.9.

  • UNION

    UNION используется, когда Вы хотите получить доступ к набору идентичных таблиц MyISAM как к одной. Это работает только с MERGE. См. раздел 17.7.

    Вы должны иметь привилегии SELECT, UPDATE и DELETE для таблиц, которые Вы отображаете на MERGE.

    Прежде, все используемые таблицы должны были быть в той же самой базе данных, где MERGE. Это ограничение больше не применяется.

Составление разделенных таблиц

partition_options может использоваться, чтобы управлять разделением таблицы, составленной с CREATE TABLE.

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

Если используется, partition_options начинается с PARTITION BY. Этот пункт содержит функцию, которая используется, чтобы определить разделение, функция возвращает целочисленное значение в пределах от 1 до num, где num число разделов. Максимальное количество определяемых пользователем разделов, которые может содержать таблица, 1024, число подразделов рассматривается позже и включено в этот максимум. Выбор, который доступен для этой функции в MySQL 8.0, показывают в следующем списке:

  • HASH(expr): Хеширует один или более столбцов, чтобы создать ключ для размещения и расположения строк. expr это выражение, использующее один или более столбцов таблицы. Это может быть любым допустимым выражением MySQL (включая функции MySQL), которое приводит к единственному целочисленному значению. Например, эти два допустимы для CREATE TABLE PARTITION BY HASH:

    CREATE TABLE t1 (col1 INT, col2 CHAR(5)) PARTITION BY HASH(col1);
    CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATETIME)
           PARTITION BY HASH (YEAR(col3));
    
    Вы не можете использовать также VALUES LESS THAN или VALUES IN с PARTITION BY HASH.

    PARTITION BY HASH использует остаток от expr разделенный на число разделов (то есть, модуль). Для примеров и дополнительной информации см. раздел 20.2.4.

    LINEAR влечет за собой несколько различный алгоритм. В этом случае номер раздела, в котором сохранена строка, вычислен как результат одной или более логических операций AND. См. раздел 20.2.4.1.

  • KEY(column_list): Это подобно HASH, за исключением того, что MySQL поставляет хеширующую функцию, чтобы гарантировать даже распределение данных. column_list просто список из 1 или более столбцов таблицы (максимум: 16). Этот пример показывает простую таблицу, разделенную ключом, с 4 разделами:
    CREATE TABLE tk (col1 INT, col2 CHAR(5), col3 DATE)
           PARTITION BY KEY(col3)
           PARTITIONS 4;
    
    Для таблиц, которые разделены ключом, Вы можете использовать линейное разделение при использовании LINEAR. Это имеет тот же самый эффект, как с таблицами, которые разделены HASH. Таким образом, номер раздела найден, используя оператор & (см. разделы 20.2.4.1 и 20.2.5). Этот пример использует линейное разделение ключом, чтобы распределить данные между 5 разделами:
    CREATE TABLE tk (col1 INT, col2 CHAR(5), col3 DATE)
           PARTITION BY LINEAR KEY(col3)
           PARTITIONS 5;
    
    Опция ALGORITHM={1|2} поддержана с [SUB]PARTITION BY [LINEAR] KEY. ALGORITHM=1 заставляет сервер использовать те же самые хеширующие ключ функции, как в 5.1, ALGORITHM=2 значит, что сервер использует хеширующие ключ функции, осуществленные и используемые по умолчанию для нового варианта KEY в MySQL 5.5 и позже. Разделенные таблицы, составленные с хеширующими ключ функциями, используемыми в MySQL 5.5 и позже, не могут использоваться MySQL 5.1. Неопределение опции имеет тот же самый эффект, как использование ALGORITHM=2. Эта опция предназначена для использования в основном, обновляя таблицы, разделенные [LINEAR] KEY между MySQL 5.1 и более поздними версиями MySQL, или для того, чтобы составить таблицы, разделенные KEY или LINEAR KEY в MySQL 5.5 или более позднем сервере, который может использоваться на MySQL 5.1. См. раздел 14.1.7.1.

    mysqldump в MySQL 5.7 (и позже) пишет эту опцию в комментарии версии:

    CREATE TABLE t1 (a INT)
    /*!50100 PARTITION BY KEY */ /*!50611 ALGORITHM = 1 */ /*!50100 ()
      PARTITIONS 3 */
    
    Это заставляет MySQL 5.6.10 и более ранние серверы игнорировать опцию, которая иначе вызвала бы синтаксическую ошибку в тех версиях. Если Вы планируете загрузить дамп, сделанный на MySQL 5.7, где Вы используете таблицы, которые разделены или подразделены KEY в MySQL 5.6 до 5.6.11, см. Changes Affecting Upgrades to MySQL 5.6. Информация, найденная там, также применяется, если Вы загружаете дамп, содержащий разделенные или подразделенные KEY таблицы, сделанные в MySQL 5.7-5.6.11 или позже в MySQL 5.5.30 или более ранний сервер.

    В MySQL 5.6.11 и позже ALGORITHM=1 показан когда необходимо в выводе SHOW CREATE TABLE использование версионного комментария в той же самой манере, как в mysqldump. ALGORITHM=2 всегда опускается из вывода SHOW CREATE TABLE , даже если эта опция была определена, составляя оригинальную таблицу.

    Вы не можете использовать также VALUES LESS THAN или VALUES IN с PARTITION BY KEY.

  • RANGE(expr): В этом случае expr показывает диапазон значений, используя ряд операторов VALUES LESS THAN. Используя разделение диапазона, Вы должны определить по крайней мере одно использование разделения VALUES LESS THAN. Вы не можете использовать VALUES IN с разделением диапазона.

    Для таблиц, разделенных RANGE, VALUES LESS THAN должен использоваться или с целым числом или с выражением, которое приводит к единственному целочисленному значению. В MySQL 8.0 Вы можете преодолеть это ограничение в таблице, которая определена, используя PARTITION BY RANGE COLUMNS, как описано позже в этом разделе.

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

    Номер разделаДиапазон лет
    01990 и раньше
    11991-1994
    21995-1998
    31999-2002
    42003-2005
    52006 и позже

    Таблица, осуществляющая такую схему разделения, может быть создана CREATE TABLE:

    CREATE TABLE t1 (year_col INT, some_data INT)
           PARTITION BY RANGE (year_col) (PARTITION p0 VALUES LESS THAN (1991),
                     PARTITION p1 VALUES LESS THAN (1995),
                     PARTITION p2 VALUES LESS THAN (1999),
                     PARTITION p3 VALUES LESS THAN (2002),
                     PARTITION p4 VALUES LESS THAN (2006),
                     PARTITION p5 VALUES LESS THAN MAXVALUE);
    
    PARTITION ... VALUES LESS THAN ... работают последовательным способом. VALUES LESS THAN MAXVALUE, чтобы определить левые значения, которые больше, чем максимальное значение, определенное иначе.

    VALUES LESS THAN работают последовательно в манере, подобной case в switch ... case блоке (как в языках C, Java и PHP). Таким образом, пункты должны быть расположены таким способом, которым верхний предел определил в каждом последовательном VALUES LESS THAN значение больше, чем из предыдущего, со ссылкой MAXVALUE на последнее из всех в списке.

  • RANGE COLUMNS(column_list): Эта разновидность RANGE облегчает сокращение разделения для запросов, используя условия диапазона на многих столбцах (то есть, имея такие условия, как WHERE a = 1 AND b < 10 или WHERE a = 1 AND b = 10 AND c < 10). Это позволяет Вам определить диапазоны значения при использовании списка столбцов в COLUMNS и ряд значений столбцов в каждом PARTITION ... VALUES LESS THAN (value_list) . В самом простом случае этот набор состоит из единственного столбца. Максимальное количество столбцов, на которые можно сослаться в column_list и value_list 16.

    column_list используемый в COLUMNS может содержать только названия столбцов, каждый столбец в списке должен быть одним из следующих типов данных MySQL: типы целого числа, строковые и типы времени или даты. Использование столбцов BLOB, TEXT, SET, ENUM, BIT или пространственных типов не разрешено, столбцы, которые используют типы числа с плавающей запятой, также не разрешены. Вы также не можете использовать функции или арифметические выражения в COLUMNS.

    VALUES LESS THAN , используемый в определении разделения, должен определить литеральное значение для каждого столбца, который появляется в COLUMNS(), то есть, список значений для каждого VALUES LESS THAN должен содержать то же самое число значений, сколько есть столбцов, перечисленных в COLUMNS. Попытка использовать больше или меньше значений в VALUES LESS THAN, чем есть в COLUMNS заставляет запрос терпеть неудачу с ошибкой Inconsistency in usage of column lists for partitioning.... Вы не можете использовать NULL для любого значения, появляющегося в VALUES LESS THAN. Возможно использовать MAXVALUE не раз для любого столбца, кроме первого, как показано в этом примере:

    CREATE TABLE rc (a INT NOT NULL, b INT NOT NULL)
    PARTITION BY RANGE COLUMNS(a,b) (PARTITION p0 VALUES LESS THAN (10,5),
              PARTITION p1 VALUES LESS THAN (20, 10),
              PARTITION p2 VALUES LESS THAN (MAXVALUE, 15),
              PARTITION p3 VALUES LESS THAN (MAXVALUE, MAXVALUE));
    
    Каждое значение в списке значения VALUES LESS THAN должно соответствовать типу соответствующего столбца точно: никакое преобразование не сделано. Например, Вы не можете использовать строку '1' для значения, которое соответствует столбцу, который использует тип целого числа (Вы должны использовать цифру 1), и при этом Вы не можете использовать цифру 1 для значения, которое соответствует столбцу, который использует строковый тип (в таком случае, Вы должны использовать заключенную в кавычки строку '1').

  • LIST(expr): Это полезно, назначая разделение, основанное на столбце таблицы с ограниченным набором возможных значений, например, статус или код страны. В таком случае все строки, имеющие отношение к определенному статусу или стране, могут быть назначены на единственный раздел или раздел может быть сохранен для определенного набора статусов или стран. Это подобно RANGE, за исключением того, что только VALUES IN может использоваться, чтобы определить допустимые значения для каждого раздела.

    VALUES IN используется со списком значений, которые будут соответствующими. Например, Вы могли создать схему разделения, такую как следующее:

    CREATE TABLE client_firms (id INT, name VARCHAR(35))
           PARTITION BY LIST (id) (PARTITION r0 VALUES IN (1, 5, 9, 13, 17, 21),
                     PARTITION r1 VALUES IN (2, 6, 10, 14, 18, 22),
                     PARTITION r2 VALUES IN (3, 7, 11, 15, 19, 23),
                     PARTITION r3 VALUES IN (4, 8, 12, 16, 20, 24));
    
    Используя разделение списка, Вы должны определить по крайней мере одно использование VALUES IN. Вы не можете использовать VALUES LESS THAN с PARTITION BY LIST.

    Для таблиц, разделенных LIST список значений, используемый с VALUES IN, должен состоять только из целочисленных значений. В MySQL 8.0 Вы можете преодолеть это ограничение использованием LIST COLUMNS, который описан позже в этом разделе.

  • LIST COLUMNS(column_list): Это разновидность LIST облегчает сокращение разделения для запросов, используя условия сравнения на многих столбцах (то есть, имея условия вроде WHERE a = 5 AND b = 5 или WHERE a = 1 AND b = 10 AND c = 5). Это позволяет Вам определить значения во многих столбцах при использовании списка столбцов в COLUMNS и ряд значений столбцов в каждом PARTITION ... VALUES IN (value_list).

    Правила относительно типов данных для списка столбца, используемого в LIST COLUMNS(column_list) и списке значений в VALUES IN(value_list) те же самые, как для списка столбцов, используемого в RANGE COLUMNS(column_list) и списке значений в VALUES LESS THAN(value_list), соответственно, за исключением того, что в VALUES IN MAXVALUE не разрешен, и Вы можете использовать NULL.

    Есть одно важное различие между списком значений, используемых для VALUES IN с PARTITION BY LIST COLUMNS в противоположность тому, когда это используется с PARTITION BY LIST. В PARTITION BY LIST COLUMNS каждый элемент в VALUES IN должен быть рядом значений столбцов, число значений в каждом наборе должно быть тем же самым, как число столбцов, используемых в COLUMNS, типы данных этих значений должны соответствовать таковым из столбцов (и в том же самом порядке). В самом простом случае набор состоит из единственного столбца. Максимальное количество столбцов, которые могут использоваться в column_list и в элементах, составляющих value_list 16.

    Таблица определена следующим CREATE TABLE обеспечивает пример табличного использования LIST COLUMNS:

    CREATE TABLE lc (a INT NULL, b INT NULL)
           PARTITION BY LIST COLUMNS(a,b)
             (PARTITION p0 VALUES IN((0,0), (NULL,NULL)),
              PARTITION p1 VALUES IN( (0,1), (0,2), (0,3), (1,1), (1,2)),
              PARTITION p2 VALUES IN( (1,0), (2,0), (2,1), (3,0), (3,1)),
              PARTITION p3 VALUES IN( (1,3), (2,2), (2,3), (3,2), (3,3)));
    
  • Число разделов может произвольно быть определено с PARTITIONS num, где num число разделов. Если этот пункт и любой PARTITION используются, num должно быть равным общему количеству разделов, которое объявлено, используя PARTITION.

    Используете ли Вы PARTITIONS в составлении таблицы, которая разделена RANGE или LIST, Вы должны все еще включить по крайней мере один PARTITION VALUES в табличном определении (см. ниже).

  • Раздел может быть произвольно разделен на много подразделов. Это может быть обозначено при использовании дополнительного SUBPARTITION BY. Подраздел может быть сделан HASH или KEY. Любой из них может быть LINEAR. Они работают таким же образом, как ранее описано для эквивалентных типов разделов. Это не относится к подразделам LIST или RANGE.

    Число подразделов может быть обозначено, используя SUBPARTITIONS с целочисленным значением.

  • Строгая проверка значения, используемого в PARTITIONS или SUBPARTITIONS применена, и это значение должно придерживаться следующих правил:

    • Значение должно быть положительным целым числом, отличным от нуля.

    • Никакие начальные нули не разрешены.
    • Значение должно быть целым числом и не может быть выражением. Например, PARTITIONS 0.2E+01 не разрешен, даже при том, что 0.2E+01 это 2 (Bug #15890).

Выражение (expr) в PARTITION BY не может отнестись ни к каким столбцам не в составленной таблице, такие ссылки определенно не разрешены и заставляют запрос терпеть неудачу с ошибкой (Bug #29444).

Каждое разделение может быть индивидуально определено, используя partition_definition. Отдельные части, составляющие этот пункт, следующие:

  • PARTITION partition_name: Это определяет логическое имя для разделения.

  • VALUES: Для разделения диапазона каждое разделение должно включать VALUES LESS THAN, для разделения списка Вы должны определить VALUES IN для каждого раздела. Это используется, чтобы определить, какие строки должны быть сохранены в этом разделе. См. обсуждения разделения типов в главе 20.
  • COMMENT может использоваться, чтобы определить строку, которая описывает раздел. Пример:
    COMMENT = 'Data for the years previous to 1999'
    
    Максимальная длина для комментария 1024 символа.
  • DATA DIRECTORY и INDEX DIRECTORY может использоваться, чтобы указать на каталог, где данные и индекс для этого раздела должны быть сохранены, соответственно. Оба data_dir и index_dir должны быть абсолютными системными путями. Пример:
    CREATE TABLE th (id INT, name VARCHAR(30), adate DATE)
           PARTITION BY LIST(YEAR(adate))
                     (PARTITION p1999 VALUES IN (1995, 1999, 2003)
                      DATA DIRECTORY = '/var/appdata/95/data'
                      INDEX DIRECTORY = '/var/appdata/95/idx',
                      PARTITION p2000 VALUES IN (1996, 2000, 2004)
                      DATA DIRECTORY = '/var/appdata/96/data'
                      INDEX DIRECTORY = '/var/appdata/96/idx',
                      PARTITION p2001 VALUES IN (1997, 2001, 2005)
                      DATA DIRECTORY = '/var/appdata/97/data'
                      INDEX DIRECTORY = '/var/appdata/97/idx',
                      PARTITION p2002 VALUES IN (1998, 2002, 2006)
                      DATA DIRECTORY = '/var/appdata/98/data'
                      INDEX DIRECTORY = '/var/appdata/98/idx');
    
    DATA DIRECTORY и INDEX DIRECTORY ведут себя таким же образом, как в CREATE TABLE table_option для таблиц MyISAM.

    Один каталог данных и индекса может быть определен на раздел. Если оставлено не указанным, данные и индекс сохранены по умолчанию в каталоге базы данных таблицы.

    DATA DIRECTORY и INDEX DIRECTORY проигнорированы для того, чтобы составить разделенные таблицы, если работает NO_DIR_IN_CREATE.

  • MAX_ROWS и MIN_ROWS может использоваться, чтобы определить, соответственно, максимальное и минимальное число строк, которые будут сохранены в разделе. Значения для max_number_of_rows и min_number_of_rows должны быть положительные целые числа. Как с опциями на уровне таблицы с теми же самыми именами, они действуют только как подсказки серверу и не являются жесткими пределами.
  • TABLESPACE может использоваться, чтобы назначить табличное разделение или подразделение InnoDB к общему табличному пространству, отдельному табличному пространству file-per-table или системному табличному пространству. Все разделение должно принадлежать тому же самому механизму хранения. Для получения дополнительной информации см. раздел 16.7.9.
  • MySQL понимает [STORAGE] ENGINE для PARTITION и SUBPARTITION. В настоящее время единственный путь, которым может использоваться эта опция, состоит в том, чтобы установить все разделение или все подразделение к тому же самому механизму хранения, попытка установить различные механизмы хранения для разделения или подразделения в той же самой таблице даст ошибку ERROR 1469 (HY000): The mix of handlers in the partitions is not permitted in this version of MySQL.
  • Определение разделения может произвольно содержать один или больше subpartition_definition. Каждый из них состоит минимум из SUBPARTITION name, где name идентификатор для подразделения. За исключением замены PARTITION на SUBPARTITION, синтаксис для определения подразделения идентичен синтаксису для определения разделения.

    Подразделение должно быть сделано HASH или KEY и может быть сделано только на RANGE или LIST. См. раздел 20.2.6.

Разделение произведенными столбцами разрешено. Например:

CREATE TABLE t1 (s1 INT, s2 INT AS (EXP(s1)) STORED)
       PARTITION BY LIST (s2) (PARTITION p1 VALUES IN (1));
Разделение рассматривает произведенный столбец как регулярный столбец, который является обходным решениям для ограничений на функции, которые не разрешены для того, чтобы разделить (см. раздел 20.6.3). Предыдущий пример демонстрирует этот метод: EXP() не может использоваться непосредственно в PARTITION BY, но произведенный столбец определил использование EXP().

яРазделение может быть изменено, слито, добавлено к таблицам и исключено из таблиц. Для основной информации о запросах MySQL, чтобы выполнить эти задачи, см. раздел 14.1.7. Подробности в разделе 20.3.

Оригинал CREATE TABLE, включая все технические требования и табличные опции сохранено MySQL, когда таблица составлена. Это сделано, чтобы, если Вы изменяете сопоставления или другие настройки, используя ALTER TABLE, оригинальные табличные определенные опции были сохранены. Это позволяет Вам изменять табличные типы даже при том, что форматы строки, поддержанные этими двумя механизмами, могут отличаться.

Поскольку текст оригинального запроса сохранен, но из-за способа, которым могут быть тихо реконфигурированы определенные значения и опции (хотя бы ROW_FORMAT), активное табличное определение (доступно через DESCRIBE или SHOW TABLE STATUS) и табличная строка создания (доступна через SHOW CREATE TABLE) сообщат различные значения.

14.1.15.1. CREATE TABLE ... LIKE

CREATE TABLE ... LIKE применяется, чтобы составить пустую таблицу, основанную на определении другой таблицы, включая любой столбец, префикс и индекс, определенные в оригинальной таблице:

CREATE TABLE new_tbl LIKE orig_tbl;
Копия создается, используя ту же самую версию табличного формата хранения, как оригинальная таблица. Привилегия SELECT требуется на оригинальной таблице.

LIKE работает только для базовых таблиц, не для представлений.

Вы не можете выполнить CREATE TABLE или CREATE TABLE ... LIKE в то время, как есть запрос LOCK TABLES.

CREATE TABLE ... LIKE осуществляет те же самые проверки, как CREATE TABLE. Это означает, что, если текущий режим SQL отличается от режима в действительности, когда оригинальная таблица была составлена, табличное определение можно было бы считать недопустимым для нового режима, и запрос потерпит неудачу.

Для CREATE TABLE ... LIKE целевая таблица сохраняет произведенную информацию о столбце от оригинальной таблицы.

CREATE TABLE ... LIKE не сохраняет табличные опции DATA DIRECTORY или INDEX DIRECTORY, которые были определены для оригинальной таблицы, или любые определения внешнего ключа.

Если оригинальная таблица TEMPORARY, CREATE TABLE ... LIKE не сохраняет TEMPORARY. Чтобы создать целевую таблицу TEMPORARY, надо использовать CREATE TEMPORARY TABLE ... LIKE.

14.1.15.2. CREATE TABLE ... SELECT

Вы можете составить одну таблицу от другой, добавляя SELECT в конец the CREATE TABLE:

CREATE TABLE new_tbl [AS] SELECT * FROM orig_tbl;
MySQL создает новые столбцы для всех элементов в SELECT:
mysql> CREATE TABLE test (a INT NOT NULL AUTO_INCREMENT,
    ->        PRIMARY KEY (a), KEY(b))
    ->        ENGINE=MyISAM SELECT b,c FROM test2;
Это создает MyISAM с тремя столбцами, a, b и c. ENGINE часть CREATE TABLE и не должно использоваться после SELECT, это привело бы к синтаксической ошибке. То же самое истина для других опций CREATE TABLE, например, для CHARSET.

Заметьте, что столбцы из SELECT добавлены к правой стороне таблицы. Возьмите следующий пример:

mysql> SELECT * FROM foo;
+---+
| n |
+---+
| 1 |
+---+

mysql> CREATE TABLE bar (m INT) SELECT n FROM foo;
Query OK, 1 row affected (0.02 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM bar;
+------+---+
| m    | n |
+------+---+
| NULL | 1 |
+------+---+
1 row in set (0.00 sec)
Для каждой строки в таблице foo строка вставлена в bar со значениями из foo и значениями по умолчанию для новых столбцов.

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

Если какие-либо ошибки происходят, копируя данные к таблице, таблица автоматически удалена и не создана.

Вы можете предшествовать SELECT IGNORE или REPLACE, чтобы указать, как обработать строки, которые дублируют уникальные значения ключа. С IGNORE отказываются от строк, которые дублируют существующую строку на уникальном значении ключа. С REPLACE новые строки заменяют строки, у которых есть то же самое уникальное значение ключа. Если IGNORE или REPLACE не определен, будет ошибка дубликата уникального значения ключа.

Поскольку упорядочивание строк в основном SELECT не может всегда определяться, CREATE TABLE ... IGNORE SELECT и CREATE TABLE ... REPLACE SELECT отмечены как опасные для основанной на запросе репликации. С этим изменением такие запросы производят предупреждение в журнале, используя основанный на запросе режим и зарегистрированы, используя основанный на строке формат, используя режим MIXED. См. раздел 19.2.1.1.

CREATE TABLE ... SELECT автоматически не создает индекс. Это сделано преднамеренно, чтобы сделать запрос настолько гибким насколько возможно. Если Вы хотите иметь индексы в составленной таблице, Вы должны определить их перед SELECT:

mysql> CREATE TABLE bar (UNIQUE (n)) SELECT n FROM foo;
Для CREATE TABLE ... SELECT целевая таблица не сохраняет информацию о том, являются ли столбцы, выбранные из исходной таблицы, произведенными столбцами. Часть SELECT не может назначить значения на произведенные столбцы в целевой таблице.

Некоторое преобразование типов данных могло бы произойти. Например, AUTO_INCREMENT не сохранен, и VARCHAR могут стать CHAR. Сохраняются признаки NULL (или NOT NULL) для тех столбцов, у которых они есть, CHARACTER SET, COLLATION, COMMENT и DEFAULT.

Составляя таблицу с CREATE TABLE ... SELECT, удостоверьтесь в псевдонимах любых вызовов функции или выражения в запросе. Если Вы не делаете этого, CREATE мог бы потерпеть неудачу или привести к нежелательным именам столбцов.

CREATE TABLE artists_and_works
  SELECT artist.name, COUNT(work.artist_id) AS number_of_works
  FROM artist LEFT JOIN work ON artist.id = work.artist_id
  GROUP BY artist.id;
Вы можете также явно определить тип данных для столбца в составленной таблице:
CREATE TABLE foo (a TINYINT NOT NULL) SELECT b+1 AS a FROM bar;
Для CREATE TABLE ... SELECT, если задано IF NOT EXISTS и целевая таблица существует, ничто не вставлено в целевую таблицу, и запрос не зарегистрирован.

Чтобы гарантировать, что двоичный журнал может использоваться, чтобы обновить оригинальные таблицы, MySQL не разрешает параллельные вставки во время CREATE TABLE ... SELECT .

Вы не можете использовать FOR UPDATE как часть SELECT в таком запросе, как CREATE TABLE new_table SELECT ... FROM old_table .... Если Вы пытаетесь сделать так, запрос терпит неудачу.

14.1.15.3. Используя ограничения FOREIGN KEY

MySQL поддерживает внешние ключи, которые позволяют Вам перекрестно ссылаться на связанные данные через таблицы, и ограничения внешнего ключа, которые сохраняют эти данные распространения последовательными. Существенный синтаксис для определения ограничения внешнего ключа в CREATE TABLE или ALTER TABLE похож на это:

[CONSTRAINT [symbol]] FOREIGN KEY
[index_name] (index_col_name, ...)
REFERENCES tbl_name (index_col_name,...)
[ON DELETE reference_option]
[ON UPDATE reference_option]

reference_option:
RESTRICT | CASCADE | SET NULL | NO ACTION
index_name представляет ID внешнего ключа. index_name проигнорировано, если уже есть явно определенный индекс на дочерней таблице, которая может поддержать внешний ключ. Иначе MySQL неявно создает индекс внешнего ключа, который называют согласно следующим правилам:

  • Если определено, CONSTRAINT symbol. Иначе FOREIGN KEY index_name.

  • Если CONSTRAINT symbol или FOREIGN KEY index_name не определен, имя индекса внешнего ключа произведено, используя название столбца внешнего ключа ссылки.

Определения внешних ключей подвергаются следующим условиям:

  • Отношения внешнего ключа вовлекают родительскую таблицу, которая содержит центральные значения данных, и дочернюю таблицу с идентичными значениями, указывающими на родителя. FOREIGN KEY определен в дочерней таблице. Родительские и дочерние таблицы должны использовать тот же самый механизм хранения. Они не должны быть TEMPORARY.

    В MySQL 8.0 создание ограничения внешнего ключа требует привилегию REFERENCES для родительской таблицы.

  • У соответствующих столбцов во внешнем ключе и ключе, на который ссылаются, должны быть подобные типы данных. Размер и знак типов целого числа должны быть теми же самыми. Длина строковых типов не должна быть той же самой. Для недвоичных (символьных) строковых столбцов набор символов и сопоставление должны быть теми же самыми.
  • При включенном foreign_key_checks, что является настройкой по умолчанию, преобразование набора символов не разрешено на таблицах, которые включают столбец строки символов, используемый в ограничение внешнего ключа. Обходное решение описано в разделе 14.1.7.
  • MySQL требует, индекс на внешних ключах и ключах, на которые ссылаются, чтобы проверки внешнего ключа могли быть быстрыми и не требовали сканирования таблицы. В таблице ссылки должно быть индексирование, где столбцы внешнего ключа перечислены как первые столбцы в том же самом порядке. Такой индекс создается на таблице ссылки автоматически, если он не существует. Это индекс может быть тихо удален позже, если Вы создаете другой индекс, который может использоваться, чтобы провести в жизнь ограничение внешнего ключа. index_name, если дано, используется как описано ранее.
  • InnoDB разрешает внешнему ключу ссылаться на любой столбец или группу столбцов. Однако, в таблице, на которую ссылаются, должен быть индекс, где столбцы, на которые ссылаются, перечислены как первые столбцы в том же самом порядке.
  • Префиксы индекса на столбцах внешнего ключа не поддержаны. Одно последствие этого: BLOB и TEXT не могут быть включены во внешний ключ, потому что индекс на тех столбцах, должен всегда включать длину префикса.
  • Если дано CONSTRAINT symbol, symbol, если используется, должно быть уникальным в базе данных. Дубликат symbol приведет к ошибке: ERROR 1022 (2300): Can't write; duplicate key in table '#sql- 464_1'. Если пункт не дан, или symbol не включен после CONSTRAINT, название ограничения создается автоматически.
  • InnoDB в настоящее время не поддерживает внешние ключи для таблиц с определяемым пользователем разделением. Это включает родительские и дочерние таблицы.

Справочные действия

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

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

Когда UPDATE или DELETE затрагивает значение ключа в родительской таблице, у которой есть соответствие строк в дочерней таблице, результат зависит от действия, определенного, используя ON UPDATE и ON DELETE в FOREIGN KEY. MySQL поддерживает пять опций относительно действия, перечисленных здесь:

  • CASCADE: Удалит или обновит строку из родительской таблицы и автоматически удалит или обновит соответствующие строки в дочерней таблице. ON DELETE CASCADE и ON UPDATE CASCADE поддержаны. Между двумя таблицами не определяйте несколько ON UPDATE CASCADE, которые действуют на тот же самый столбец в родительской или в дочерней таблице.

    Каскадные действия внешнего ключа не активируют триггеры.

  • SET NULL: Удалит или обновит строку из родительской таблицы и установит столбец внешнего ключа или столбцы в дочерней таблице к NULL. ON DELETE SET NULL и ON UPDATE SET NULL поддержаны.

    Если Вы определяете SET NULL, удостоверьтесь, что Вы не объявили столбцы в дочерней таблице как NOT NULL.

  • RESTRICT: Отклоняет работу удаления или обновления для родительской таблицы. Определение RESTRICT (или NO ACTION ) то же самое, как исключение ON DELETE или ON UPDATE.
  • NO ACTION: Ключевое слово от стандартного SQL. В MySQL эквивалент RESTRICT. MySQL Server отклоняет работу удаления или обновления для родительской таблицы, если есть связанное значение внешнего ключа в таблице, на которую ссылаются. Некоторые системы базы данных задерживают проверки, и NO ACTION это задержанная проверка. В MySQL ограничения внешнего ключа немедленно проверены, таким образом, NO ACTION то же самое, как RESTRICT.
  • SET DEFAULT: Это действие признано анализатором MySQL, но InnoDB отклоняет табличные определения, содержащие ON DELETE SET DEFAULT или ON UPDATE SET DEFAULT.

Для ON DELETE или ON UPDATE действие значения по умолчанию всегда RESTRICT.

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

Ограничение внешнего ключа на произведенный сохраненный столбец не может использовать ON UPDATE CASCADE, ON DELETE SET NULL, ON UPDATE SET NULL, ON DELETE SET DEFAULT или ON UPDATE SET DEFAULT.

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

Для InnoDB ограничения, связанные с внешними ключами и произведенными столбцами, см. в разделе 16.8.6.

Примеры пунктов внешнего ключа

Вот простой пример, который имеет отношение таблиц parent и child через внешний ключ единственного столбца:

CREATE TABLE parent (id INT NOT NULL,
                     PRIMARY KEY (id)) ENGINE=INNODB;
CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id),
                    FOREIGN KEY (parent_id) REFERENCES parent(id)
                    ON DELETE CASCADE) ENGINE=INNODB;
Более сложный пример, в котором у таблицы product_order есть внешние ключи для двух других таблиц. Один внешний ключ ссылается на индекс из двух столбцов в таблице product. Второй ссылается на индекс из единственного столбца в customer:
CREATE TABLE product (category INT NOT NULL, id INT NOT NULL,
                      price DECIMAL, PRIMARY KEY(category, id))
                      ENGINE=INNODB;

CREATE TABLE customer (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB;
CREATE TABLE product_order (no INT NOT NULL AUTO_INCREMENT,
                            product_category INT NOT NULL,
                            product_id INT NOT NULL,
                            customer_id INT NOT NULL, PRIMARY KEY(no),
                            INDEX (product_category, product_id),
                            INDEX (customer_id),
                            FOREIGN KEY (product_category, product_id)
                            REFERENCES product(category, id)
                            ON UPDATE CASCADE ON DELETE RESTRICT,
                            FOREIGN KEY (customer_id)
                            REFERENCES customer(id)) ENGINE=INNODB;
Добавление внешних ключей

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

ALTER TABLE tbl_name
ADD [CONSTRAINT [symbol]] FOREIGN KEY
[index_name] (index_col_name, ...)
REFERENCES tbl_name (index_col_name,...)
[ON DELETE reference_option]
[ON UPDATE reference_option]
Внешний ключ может быть сам ссылочным (обращающийся к той же самой таблице). Когда Вы добавляете ограничение внешнего ключа к таблице через ALTER TABLE, не забудьте создать необходимый индекс сначала.

Удаление внешних ключей

Вы можете также использовать ALTER TABLE, чтобы удалить внешние ключи, используя синтаксис, показанный здесь:

ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;
Если FOREIGN KEY включал имя CONSTRAINT, когда Вы создали внешний ключ, Вы можете обратиться к тому имени, чтобы удалить внешний ключ. Иначе значение fk_symbol произведено внутренне, когда внешний ключ создается. Чтобы узнать символьное значение, когда Вы хотите удалить внешний ключ, используйте SHOW CREATE TABLE:
mysql> SHOW CREATE TABLE ibtest11c\G
*************************** 1. row ***************************
   Table: ibtest11c
Create Table: CREATE TABLE `ibtest11c` (
  `A` int(11) NOT NULL auto_increment,
  `D` int(11) NOT NULL default '0',
  `B` varchar(200) NOT NULL default '',
  `C` varchar(175) default NULL,
  PRIMARY KEY  (`A`,`D`,`B`),
  KEY `B` (`B`,`C`),
  KEY `C` (`C`),
  CONSTRAINT `0_38775` FOREIGN KEY (`A`, `D`)
REFERENCES `ibtest11a` (`A`, `D`)
ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `0_38776` FOREIGN KEY (`B`, `C`)
REFERENCES `ibtest11a` (`B`, `C`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB CHARSET=latin1
1 row in set (0.01 sec)

mysql> ALTER TABLE ibtest11c DROP FOREIGN KEY `0_38775`;
Добавление и удаление внешнего ключа в том же самом ALTER TABLE поддержано для ALTER TABLE ... ALGORITHM=INPLACE , но не поддержано для ALTER TABLE ... ALGORITHM=COPY .

В MySQL 8.0 сервер запрещает изменения столбцов внешнего ключа с потенциалом потери справочной целостности. Обходное решение должно использовать ALTER TABLE ... DROP FOREIGN KEY прежде, чем изменить определение столбца и ALTER TABLE ... ADD FOREIGN KEY позже.

Внешние ключи и другие запросы MySQL

Таблица и идентификаторы столбца в FOREIGN KEY ... REFERENCES ... могут быть заключены в кавычки в пределах обратных кавычек (`). Альтернативно, двойные кавычки (") может использоваться, если включен режим SQL ANSI_QUOTES. Установка lower_case_table_names также принята во внимание.

Вы можете рассмотреть определения внешнего ключа дочерней таблицы как часть вывода SHOW CREATE TABLE :

SHOW CREATE TABLE tbl_name;
Вы можете также получить информацию о внешних ключах, запрашивая таблицу INFORMATION_SCHEMA.KEY_COLUMN_USAGE.

Вы можете считать информацию о внешних ключах, используемую таблицами InnoDB в INNODB_SYS_FOREIGN и INNODB_SYS_FOREIGN_COLS в базе данных INFORMATION_SCHEMA.

mysqldump производит правильные определения таблиц в файле дампа, включая внешние ключи для дочерних таблиц.

Чтобы облегчить перезагрузку файла дампа для таблиц, у которых есть отношения внешнего ключа, mysqldump автоматически, включает запрос в вывод дампа, чтобы установить foreign_key_checks в 0. Это избегает проблем с таблицами, имеющими необходимость быть перезагруженными в особом порядке, когда дамп перезагружен. Также возможно установить эту переменную вручную:

mysql> SET foreign_key_checks = 0;
mysql> SOURCE dump_file_name;
mysql> SET foreign_key_checks = 1;
Это позволяет Вам импортировать таблицы в любом порядке, если файл дампа содержит таблицы, которые правильно не упорядочены для внешних ключей. Это также ускоряет работу импорта. Установка foreign_key_checks в 0 может также быть полезна для игнорирования ограничений внешнего ключа во время LOAD DATA и ALTER TABLE. Однако, даже если foreign_key_checks = 0, MySQL не разрешает создание ограничения внешнего ключа, где столбец ссылается на несоответствующий тип столбца. Кроме того, если у таблицы есть ограничения внешнего ключа, ALTER TABLE не может использоваться, чтобы изменить таблицу, чтобы использовать другой механизм хранения. Чтобы изменить механизм хранения, Вы должны сначала удалить любые ограничения внешнего ключа.

Вы не можете использовать DROP TABLE для таблицы, на которую ссылается ограничение FOREIGN KEY , если Вы не делаете SET foreign_key_checks = 0. Когда Вы удаляете таблицу, любые ограничения, которые были определены в запросе, используемом, чтобы составить эту таблицу, также удалены.

Если Вы обновляете таблицу, которая была удалена, у нее должно быть определение, которое соответствует ограничениям внешнего ключа, ссылающимся на нее. У этого должны быть правильные имена столбцов и типы, и таблица должна иметь индекс на ключах, на которые ссылаются, как заявлено ранее. Если эти условия не удовлетворены, MySQL возвращает Error 1005 и Error 150 в сообщении об ошибке, что означает, что ограничение внешнего ключа не было правильно сформировано. Точно так же, если ALTER TABLE терпит неудачу из-за Error 150, это означает, что определение внешнего ключа было неправильно сформировано для измененной таблицы.

Для таблиц InnoDB Вы можете получить подробное объяснение ошибки внешнего ключа в MySQL Server, просмотрев вывод SHOW ENGINE INNODB STATUS.

Для пользователей, знакомых с ANSI/ISO SQL Standard, отметьте, что никакой механизм хранения, включая InnoDB, не признает или проводит в жизнь MATCH в определениях ограничения справочной целостности. Использование явного MATCH не будет иметь указанного эффекта, и также вызывает ON DELETE и ON UPDATE, которые будут проигнорированы. По этим причинам определть MATCH не надо.

MATCH в стандарте SQL управляет, как NULL обработаны в сложном (из нескольких столбцов) внешнем ключе, сравниваясь с первичным ключом. MySQL по существу осуществляет семантику, определенную MATCH SIMPLE, которые разрешают внешнему ключу быть всему или частично NULL. В этом случае (дочерняя таблица) строке, содержащей такой внешний ключ, разрешают быть вставленной и не соответствовать строке в (родительской) таблице, на которую ссылаются. Возможно осуществить другую семантику, используя триггеры.

Дополнительно, MySQL требует, чтобы столбцы, на которые ссылаются, были индексированы по исполнительным причинам. Однако, система не проводит в жизнь требование, что столбцы, на которые ссылаются, UNIQUE или объявлены NOT NULL. Обработка ссылок внешнего ключа на групповые ключи или ключи, которые содержат NULL не четко определены для таких операций, как UPDATE или DELETE CASCADE . Вам советуют использовать внешние ключи, которые ссылаются только на UNIQUE (включая PRIMARY) и ключи NOT NULL.

Кроме того, MySQL разбирает, но игнорирует inline REFERENCES (как определено в SQL), где ссылки определены как часть спецификации столбца. MySQL принимает REFERENCES только когда определено как часть отдельного FOREIGN KEY. Для механизмов хранения, которые не поддерживают внешние ключи (MyISAM , например), MySQL Server разбирает и игнорирует технические требования внешнего ключа.

14.1.15.4. В некоторых случаях, MySQL тихо изменяет технические требования столбца от данных в CREATE TABLE или ALTER TABLE. Они могли бы быть изменениями типа данных, признаков, связанных с типом данных или спецификации индекса.

Все изменения подвергаются внутреннему пределу размера строки 65535 байтов, которые могут заставить некоторые попытки изменений типа данных терпеть неудачу. См. раздел C.10.4 .

  • Столбцы, которые являются частью PRIMARY KEY сделаны NOT NULL, даже если так не объявлены.

  • Конечные пробелы автоматически удалены из ENUM и SET, когда таблица составлена.
  • MySQL отображает определенные типы данных от других поставщиков баз данных SQL к типам MySQL. См. раздел 12.10.
  • Если Вы включаете USING, чтобы определить тип индекса, который не разрешен для данного механизма хранения, но есть другой доступный тип индекса, который механизм может использовать, не затрагивая результаты запроса, механизм использует доступный тип.
  • Если строгий режим SQL не включен, VARCHAR со спецификацией длины больше 65535 преобразован в TEXT, а VARBINARY со спецификацией длины больше 65535 преобразован в BLOB. Иначе ошибка происходит в любом из этих случаев.
  • Определение CHARACTER SET binary для символьного типа данных заставляет столбец создаваться как соответствующий тип двоичных данных: CHAR станет BINARY, VARCHAR станет VARBINARY, TEXT станет BLOB. ENUM и SET это не происходит: они создаются как объявлено. Предположите, что Вы определяете таблицу, используя это определение:
    CREATE TABLE t (c1 VARCHAR(10) CHARACTER SET binary,
                    c2 TEXT CHARACTER SET binary,
                    c3 ENUM('a','b','c') CHARACTER SET binary);
    
    У получающейся таблицы есть это определение:
    CREATE TABLE t (c1 VARBINARY(10), c2 BLOB,
                    c3 ENUM('a','b','c') CHARACTER SET binary);
    

Чтобы видеть, использовал ли MySQL тип данных кроме того, который Вы определили, используйте DESCRIBE или SHOW CREATE TABLE после создания или изменения таблицы.

Определенные другие изменения типа данных могут произойти, если Вы сжимаете таблицу, используя myisampack. См. раздел 17.2.3.3.

14.1.15.5. CREATE TABLE и произведенные столбцы

CREATE TABLE поддерживает спецификацию произведенных столбцов. Значения произведенного столбца вычислены от выражения, включенного в определение столбца.

Следующий простой пример показывает таблицу, которая хранит длины сторон прямоугольных треугольников в столбцах sidea и sideb и вычисляет длину гипотенузы в sidec (квадратный корень сумм квадратов других сторон):

CREATE TABLE triangle (sidea DOUBLE, sideb DOUBLE,
       sidec DOUBLE AS (SQRT(sidea * sidea + sideb * sideb)));
INSERT INTO triangle (sidea, sideb) VALUES(1,1),(3,4),(6,8);
Выбор из таблицы приводит к этому результату:
mysql> SELECT * FROM triangle;
+-------+-------+--------------------+
| sidea | sideb | sidec              |
+-------+-------+--------------------+
| 1     | 1     | 1.4142135623730951 |
| 3     | 4     | 5                  |
| 6     | 8     | 10                 |
+-------+-------+--------------------+
Любое приложение, которое использует таблицу triangle имеет доступ к значениям гипотенузы, не имея необходимость определять выражение, которое вычисляет их.

У произведенных определений столбца есть этот синтаксис:

col_name data_type
   [GENERATED ALWAYS] AS (expression)
   [VIRTUAL | STORED] [UNIQUE [KEY]] [COMMENT comment]
   [[NOT] NULL] [[PRIMARY] KEY]
AS (expression) указывает, что столбец произведен и определяет выражение, используемое, чтобы вычислить значения столбцов. AS можно предшествовать GENERATED ALWAYS, чтобы сделать произведенную природу столбца более явной. Конструкции, которые разрешены или запрещены в выражении, обсуждены позже.

VIRTUAL или STORED указывает, как сохранены значения столбцов, у которого есть значения для использования столбца:

  • VIRTUAL: Значения столбцов не сохранены, но оценены, когда строки считаны, немедленно после любого триггера BEFORE. Виртуальный столбец не занимает места в памяти.

    InnoDB допускает вторичные индексы на на виртуальных столбцах. См. раздел 14.1.15.6.

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

Значение по умолчанию VIRTUAL, если никакое ключевое слово не определено.

Разрешено смешивать столбцы VIRTUAL и STORED в пределах таблицы.

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

Произведенные выражения столбца должны придерживаться следующих правил. Ошибка происходит, если выражение содержит отвергнутые конструкции.

  • Литералы, детерминированные встроенные функции и операторы разрешены. Функция детерминирована, если, учитывая те же самые данные в таблицах, многократные вызовы приводят к тому же самому результату, независимо от соединенного пользователя. Примеры функций, которые подходят под это определение: CONNECTION_ID(), CURRENT_USER(), NOW().

  • Подзапросы, параметры, переменные, сохранненные и определяемые пользователем функции не разрешены.
  • Произведенное определение столбца может отнестись к другим произведенным столбцам, но только тем, которые происходят ранее в табличном определении. Произведенное определение столбца может отнестись к (непроизведенному) столбцу в таблице, происходит ли его определение ранее или позже.
  • AUTO_INCREMENT не может использоваться в произведенном определении столбца.
  • AUTO_INCREMENT не может использоваться в качестве основного в произведенном определении столбца.
  • Если оценка выражения вызывает усечение или обеспечивает неправильный ввод функции, CREATE TABLE заканчивается с ошибкой, и работа DDL отклонена.

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

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

Для CREATE TABLE ... LIKE целевая таблица сохраняет произведенную информацию о столбце от оригинальной таблицы.

Для CREATE TABLE ... SELECT целевая таблица не сохраняет информацию о том, являются ли столбцы в выборке произведенными столбцами. Часть SELECT может назначить значения на произведенные столбцы в целевой таблице.

Разделение произведенными столбцами разрешено.

Ограничение внешнего ключа на произведенный сохраненный столбец не может использовать ON UPDATE CASCADE, ON DELETE SET NULL, ON UPDATE SET NULL, ON DELETE SET DEFAULT или ON UPDATE SET DEFAULT.

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

Для InnoDB ограничения, связанные с внешними ключами и произведенными столбцами, см. в разделе 16.8.6.

Триггеры не могут использовать NEW.col_name или OLD.col_name, чтобы обратиться к произведенным столбцам.

Для INSERT, REPLACE и UPDATE, если произведенный столбец вставлен, заменил или обновил явно, единственное разрешенное значение DEFAULT.

Произведенный столбец в представлении считают обновляемым, потому что возможно назначить ему значение. Однако, если такой столбец обновлен явно, единственное разрешенное значение DEFAULT.

У произведенных столбцов есть несколько случаев использования:

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

  • Сохраненные произведенные столбцы могут использоваться в качестве осуществленного кэша для сложных условий, которые являются дорогостоящими, чтобы вычислить на лету.
  • Произведенные столбцы могут моделировать функциональный индекс: Используйте сохраненный столбец, чтобы определить функциональное выражение и индекс. Это может быть полезно для работы со столбцами типов, которые не могут быть индексированы непосредственно, например, JSON, см. раздел 14.1.15.6.

    Недостаток такого подхода: значения сохранены дважды, однажды как значение произведенного столбца и однажды в индексировании.

  • Если произведенный столбец индексирован, оптимизатор признает выражения запроса, которые соответствуют определению столбца, и использует индекс от столбца как соответствующий во время выполнения запроса, даже если запрос не обращается к столбцу непосредственно по имени. Для деталей см. раздел 9.3.9.

Предположите, что таблица t1 содержит столбцы first_name и last_name, и приложения часто создает полное имя, используя выражение:

SELECT CONCAT(first_name,' ',last_name) AS full_name FROM t1;
Один способ избежать выписывать выражение состоит в том, чтобы создать представление v1 на t1, которое упрощает приложения, позволяя им выбрать full_name непосредственно, не используя выражение:
CREATE VIEW v1 AS
       SELECT *, CONCAT(first_name,' ',last_name) AS full_name FROM t1;
       SELECT full_name FROM v1;
Произведенный столбец также позволяет приложениям выбрать full_name непосредственно, без потребности определить представление:
CREATE TABLE t1 (first_name VARCHAR(10), last_name VARCHAR(10),
                 full_name VARCHAR(255) AS
                 (CONCAT(first_name, ' ', last_name)));
SELECT full_name FROM t1;

14.1.15.6. Вторичный индекс и произведенные виртуальные столбцы

InnoDB поддерживает вторичный индекс на виртуальных произведенных столбцах. Другой тип индекса не поддержан.

Вторичный индекс может быть создан на одном или более виртуальных столбцах или на комбинации виртуальных столбцов и непроизведенных виртуальных столбцов. Вторичный индекс на виртуальных столбцах может быть определен как UNIQUE.

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

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

Значения индексированного виртуального столбца MVCC-зарегистрированы, чтобы избежать ненужного перевычисления произведенных значений столбцов во время отката или во время работы чистки. Длина данных зарегистрированных значений ограничена ключевым пределом 767 байтов для COMPACT и REDUNDANT или 3072 байтами для DYNAMIC и COMPRESSED.

Добавление или удаление вторичного индекса на виртуальном столбце это оперативная работа.

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

Использование произведенного виртуального столбца индекса, чтобы косвенно индексировать столбцы JSON

Как отмечено выше, JSON не могут быть индексированы непосредственно. Чтобы создать индексирование, которое ссылается на такой столбец косвенно, Вы можете определить произведенный столбец, который извлекает информацию, которая должна быть индексирована, затем создать индексирование на произведенном столбце, как показано в этом примере:

mysql> CREATE TABLE jemp (c JSON,
    ->        g INT GENERATED ALWAYS AS (JSON_EXTRACT(c, '$.id')),
    ->        INDEX i (g));
Query OK, 0 rows affected (0.28 sec)

mysql> INSERT INTO jemp (c) VALUES
     >   ('{"id":"1","name": "Fred"}'), ('{"id": "2","name": "Wilma"}'),
     >   ('{"id":"3","name": "Barney"}'), ('{"id": "4","name": "Betty"}');
Query OK, 4 rows affected (0.04 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> SELECT JSON_UNQUOTE(JSON_EXTRACT(c, '$.name')) AS name
     >        FROM jemp WHERE g > 2;
+--------+
| name   |
+--------+
| Barney |
| Betty  |
+--------+
2 rows in set (0.00 sec)

mysql> EXPLAIN SELECT JSON_UNQUOTE(JSON_EXTRACT(c, '$.name')) AS name
     >         FROM jemp WHERE g > 2\G
*************************** 1. row ***************************
   id: 1
  select_type: SIMPLE
table: jemp
   partitions: NULL
 type: range
possible_keys: i
  key: i
  key_len: 5
  ref: NULL
 rows: 2
 filtered: 100.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Note
   Code: 1003
Message: /* select#1 */ select json_unquote(json_extract(`test`.`jemp`.`c`,'$.name'))
AS `name` from `test`.`jemp` where (`test`.`jemp`.`g` > 2)
1 row in set (0.00 sec)

MySQL 8.0 поддерживает две формы для того, чтобы получить доступ к значению путем JSON:

Таким образом, запрос SELECT JSON_UNQUOTE(JSON_EXTRACT(c, '$.name')) FROM jemp может быть переписан в более короткой форме как SELECT JSON_UNQUOTE(c->'$.name') FROM jemp или еще более сжато как SELECT c->>'$.name' FROM jemp.

Когда Вы используете EXPLAIN для SELECT или другого запроса SQL, содержащего одно или более выражений, которые используют -> или ->>, эти выражения преобразованы в их эквивалент с JSON_EXTRACT() и (если нужно) JSON_UNQUOTE(), как показано в выводе SHOW WARNINGS немедленно после EXPLAIN:

mysql> EXPLAIN SELECT c->"$.name"
     >         FROM jemp WHERE g > 2\G ORDER BY c->"$.name"
*************************** 1. row ***************************
   id: 1
  select_type: SIMPLE
table: jemp
   partitions: NULL
 type: range
possible_keys: i
  key: i
  key_len: 5
  ref: NULL
 rows: 2
 filtered: 100.00
Extra: Using where; Using filesort
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Note
   Code: 1003
Message: /* select#1 */ select json_extract(`test`.`jemp`.`c`,'$.name') AS
  `c->"$.name"` from `test`.`jemp` where (`test`.`jemp`.`g` > 2)
  order by json_extract(`test`.`jemp`.`c`,'$.name')
1 row in set (0.00 sec)

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

14.1.16. CREATE TABLESPACE

CREATE TABLESPACE tablespace_name
ADD DATAFILE 'file_name'
[FILE_BLOCK_SIZE = value]
[ENGINE [=] engine_name]
Этот запрос используется, чтобы создать табличное пространство InnoDB. Оно упоминается как общее табличное пространство.

Общее табличное пространство это совместно используемое табличное пространство, подобное системному табличному пространству. Это может содержать многократные таблицы и поддерживает все форматы строки таблицы. Общие табличные пространства могут также быть созданы в местоположении относительно или независимо от каталога данных MySQL.

После создания общего табличного пространства, Вы можете использовать CREATE TABLE tbl_name ... TABLESPACE [=] tablespace_name или ALTER TABLE tbl_name TABLESPACE [=] tablespace_name, чтобы добавить таблицы к табличному пространству.

См. раздел 16.7.9.

CREATE TABLESPACE поддержан с InnoDB с MySQL 5.7.6. В более ранних выпусках CREATE TABLESPACE поддержан только NDB, который является механизмом хранения MySQL Cluster.

Опции

  • ADD DATAFILE: Определяет название файла с данными табличного пространства. Файл с данными должен быть определен CREATE TABLESPACE, имя должно иметь расширение .ibd. Общее табличное пространство поддерживает только единственный файл с данными.

    Поместить файл с данными в местоположение за пределами каталога данных MySQL (DATADIR) можно, включив абсолютный путь к каталогу или путь относительно каталога данных MySQL. Если Вы не определяете путь, общее табличное пространство создается в каталоге данных MySQL.

    Чтобы избежать конфликтов с неявно создаваемыми табличными пространствами file-per-table, создание общего табличного пространства в подкаталоге в соответствии с каталогом данных MySQL не поддержано. Кроме того, создавая общее табличное пространство за пределами каталога данных MySQL, каталог должен существовать до создания табличного пространства.

    file_name, включая (дополнительный) путь, должен быть заключен в кавычки. Имена файла (без расширения .ibd) и имена каталогов должны составить по крайней мере один байт в длину. Нулевые имена файлов и каталогов не поддержаны.

  • FILE_BLOCK_SIZE: Определяет размер блока файла с данными табличного пространства. Если Вы не определяете эту опцию, FILE_BLOCK_SIZE по умолчанию innodb_page_size . FILE_BLOCK_SIZE требуется только, если Вы будете использовать табличное пространство, чтобы сохранить сжатые таблицы InnoDB (ROW_FORMAT=COMPRESSED). В этом случае Вы должны определить FILE_BLOCK_SIZE, создавая табличное пространство.

    Если FILE_BLOCK_SIZE = innodb_page_size , табличное пространство может содержать только таблицы с несжатым форматом строки (COMPACT, REDUNDANT и DYNAMIC). Таблицы с форматом COMPRESSED имеют иной физический размер страницы, чем несжатые таблицы. Поэтому сжатые таблицы не могут сосуществовать в том же самом табличном пространстве, где несжатые таблицы.

    Для общего табличного пространства, чтобы содержать сжатые таблицы должен быть определен FILE_BLOCK_SIZE и оно должно быть допустимым сжатым размером страницы относительно innodb_page_size . Кроме того, физический размер страницы сжатой таблицы (KEY_BLOCK_SIZE) должно быть равным FILE_BLOCK_SIZE/1024. Например, если innodb_page_size=16K , FILE_BLOCK_SIZE=8K, KEY_BLOCK_SIZE должен быть 8. См. раздел 16.7.9 .

  • ENGINE: Определяет механизм хранения, который использует табличное пространство, где engine_name задает название механизма хранения. В настоящее время поддержан только механизм хранения InnoDB. ENGINE = InnoDB должен быть определен как часть CREATE TABLESPACE или InnoDB должен быть определен как механизм хранения по умолчанию ( default_storage_engine=InnoDB).

Примечания

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

  • Создание временных общих табличных пространств не поддержано.
  • Общие табличные пространства не поддерживают временные таблицы.
  • TABLESPACE может использоваться с CREATE TABLE или ALTER TABLE, чтобы назначать табличное разделение или подразделение к a общему табличному пространству, отдельному табличному пространству file-per-table или системному табличному пространству. Все разделение должно принадлежать тому же самому механизму хранения. Для получения дополнительной информации см. раздел 16.7.9.
  • Общие табличные пространства поддерживают добавление таблиц любого формата строки CREATE TABLE ... TABLESPACE. innodb_file_per_table не должен быть включен.
  • innodb_strict_mode не применимо к общим табличным пространствам. Управленческие правила табличного пространства строго проведены в жизнь, независимо от innodb_strict_mode . Если параметры CREATE TABLESPACE являются неправильными или несовместимыми, работа терпит неудачу независимо от innodb_strict_mode . Когда таблица добавлена к общему табличному пространству через CREATE TABLE ... TABLESPACE или ALTER TABLE ... TABLESPACE , innodb_strict_mode проигнорирован, но запрос оценен как будто innodb_strict_mode включен.
  • DROP TABLESPACE удаляет общее табличное пространство. Все таблицы должны быть исключены из общего табличного пространства через DROP TABLE до удаления табличного пространства.
  • Все части таблицы, добавленной к общему табличному пространству, находятся в общем табличном пространстве, включая индекс и страницы BLOB.
  • Подобно системному табличному пространству, усекая или удаляя таблицы, сохраненные в общем табличном пространстве, создается свободное пространство внутренне в общем табличном пространстве файл .ibd, которое может использоваться только для новых данных InnoDB. Пространство не освобождено назад к операционной системе, как это происходит для табличных пространств file-per-table.
  • Общее табличное пространство не связано ни с какой базой данных или схемой.
  • ALTER TABLE ... DISCARD TABLESPACE и ALTER TABLE ...IMPORT TABLESPACE не поддержаны для таблиц, которые принадлежат общему табличному пространству.
  • Сервер использует блокировку метаданных на уровне табличного пространства для DDL, который ссылается на общие табличные пространства. Сервер использует блокировку метаданных на уровне таблицы для DDL, который ссылается на таблицу в табличном пространстве file-per-table.
  • Произведенное или существующее табличное пространство не может быть изменено на общее табличное пространство.
  • Нет никакого конфликта между общими именами табличного пространства и именами табличного пространства. Символ /, который присутствует в именах табличного пространства file-per-table, не разрешен в именах общего табличного пространства.

Примеры

Этот пример демонстрирует создание общего табличного пространства и добавление трех несжатых таблиц различных форматов строки.

mysql> CREATE TABLESPACE `ts1` ADD DATAFILE 'ts1.ibd' Engine=InnoDB;
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE ts1
                 ROW_FORMAT=REDUNDANT;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE t2 (c1 INT PRIMARY KEY) TABLESPACE ts1
                 ROW_FORMAT=COMPACT;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE t3 (c1 INT PRIMARY KEY) TABLESPACE ts1
                 ROW_FORMAT=DYNAMIC;
Query OK, 0 rows affected (0.00 sec)
Этот пример демонстрирует создание общего табличного пространства и добавление сжатой таблицы. Пример принимает значение по умолчанию innodb_page_size 16K. FILE_BLOCK_SIZE = 8192 требует, чтобы у сжатой таблицы был KEY_BLOCK_SIZE = 8.
mysql> CREATE TABLESPACE `ts2` ADD DATAFILE 'ts2.ibd'
                 FILE_BLOCK_SIZE = 8192 Engine=InnoDB;
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE t4 (c1 INT PRIMARY KEY) TABLESPACE ts2
                 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
Query OK, 0 rows affected (0.00 sec)

14.1.17. CREATE TRIGGER

CREATE
[DEFINER = { user | CURRENT_USER }]
TRIGGER trigger_name
trigger_time trigger_event
ON tbl_name FOR EACH ROW
[trigger_order]
trigger_body
trigger_time: { BEFORE | AFTER }
trigger_event: { INSERT | UPDATE | DELETE }
trigger_order: { FOLLOWS | PRECEDES } other_trigger_name
Этот запрос создает новый триггер. Это объект базы данных, который связан с таблицей и активируется, когда особое событие имеет место для таблицы. Триггер становится связанным с таблицей, названной tbl_name, которая должна быть постоянной. Вы не можете связать триггер с таблицей TEMPORARY или представлением.

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

Этот раздел описывает CREATE TRIGGER. Подробности в разделе 21.3.1.

CREATE TRIGGER требует привилегию TRIGGER для таблицы связаланной с триггером. Запрос может также потребовать привилегию SUPER в зависимости от значения DEFINER. Если двоичное журналирование включено, CREATE TRIGGER мог бы потребовать привилегию SUPER, см. раздел 21.7.

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

trigger_time время срабатывания. Это может быть BEFORE или AFTER, чтобы указать, что триггер активируется прежде или после каждой строки, которая будет изменена.

trigger_event указывает на вид работы, которая активирует триггер. Допустимые значения trigger_event:

  • INSERT: триггер активируется всякий раз, когда новая строка вставлена в таблицу, например, через INSERT, LOAD DATA и REPLACE.

  • UPDATE: триггер активируется всякий раз, когда строка изменена, например, через UPDATE.
  • DELETE: триггер активируется всякий раз, когда строка удалена из таблицы, например, через DELETE и REPLACE. DROP TABLE и TRUNCATE TABLE не активируют этот триггер, потому что они не используют DELETE. Удаление разделения не активирует DELETE , а зачит и триггер.

trigger_event не представляет буквальный тип запроса SQL, который активирует триггер, поскольку это представляет тип табличной работы. Например, триггер INSERT активируется не только для INSERT, но и для LOAD DATA, потому что оба запроса вставляют строки в таблицу.

Потенциально запутывающий пример этого INSERT INTO ... ON DUPLICATE KEY UPDATE ...: триггер BEFORE INSERT активируется для каждой строки, сопровождаемой любым триггером AFTER INSERT или триггерами BEFORE UPDATE и AFTER UPDATE в зависимости от того, было ли дублирование ключа для строки.

Каскадные действия внешнего ключа не активируют триггеры.

Возможно определить многократные триггеры для данной таблицы, у которых есть тот же самый случай и время действия. Например, Вы можете иметь два триггера BEFORE UPDATE. По умолчанию, триггеры, у которых есть тот же самый случай и время действия, активируются в порядке, в котором они создавались. Чтобы затронуть порядок, определите trigger_order, который указывает FOLLOWS или PRECEDES и название существующего триггера, у которого также есть тот же самый случай и время действия. С FOLLOWS новый триггер активируется после существующего, с PRECEDES перед существующим триггером.

trigger_body запрос, чтобы выполнить, когда триггер активируется. Чтобы выполнить много запросов, используйте BEGIN ... END. Это также позволяет Вам использовать те же самые запросы, которые разрешены в пределах сохраненных подпрограмм. См. раздел 14.6.1. Некоторые запросы не разрешены в триггерах, см. раздел C.1.

В пределах тела триггера Вы можете обратиться к столбцам в подчиненной таблице (таблица, связанная с триггером) при использовании псевдонимов OLD и NEW. OLD.col_name обращается к столбцу существующей строки прежде, чем это будет обновлено или удалено. NEW.col_name обращается к столбцу новой строки, которая будет вставлена или существующей строки после того, как столбец обновлен.

Триггеры не могут использовать NEW.col_name или OLD.col_name, чтобы обратиться к произведенным столбцам. Для информации о произведенных столбцах см. раздел 14.1.15.5.

MySQL хранит sql_mode когда триггер создается, и всегда выполняет триггер с этой установкой, независимо от текущего режима SQL, когда триггер выполняется .

DEFINER определяет учетную запись MySQL, которая будет использоваться, проверяя привилегии доступа во время активации. Если user задано, это должна быть учетная запись MySQL, определенная как 'user_name'@' host_name', CURRENT_USER или CURRENT_USER(). Значение по умолчанию DEFINER: пользователь, который выполняет CREATE TRIGGER. Это то же самое, как определение DEFINER = CURRENT_USER.

Если Вы определяете DEFINER, эти правила определяют допустимое значение DEFINER:

  • Если Вы не имеете привилегии SUPER, разрешено единственное значение user: Ваша собственная учетная запись, определенная буквально или при использовании CURRENT_USER. Вы не можете установить значение в некоторую другую учетную запись.

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

MySQL берет во внимание DEFINER, проверяя привилегии следующим образом:

  • В ходе CREATE TRIGGER пользователь, который делает запрос, должен иметь привилегию TRIGGER.

  • Во время активации привилегии проверены по DEFINER. У этого пользователя должны быть эти привилегии:

    • TRIGGER для подчиненной таблицы.

    • SELECT для подчиненной таблицы, если ссылки на столбцы таблицы происходят, используя OLD.col_name или NEW.col_name в триггере.
    • UPDATE для подчиненной таблицы, если столбцы таблицы это цели SET NEW.col_name = value в триггере.
    • Независимо от того, что другие привилегии обычно требуются для запросов, выполненных триггером.

См. раздел 21.6.

В пределах тела триггера CURRENT_USER() возвращает учетную запись для проверки привилегии во время активации. Это DEFINER, но не пользователь, действия которого заставили триггер быть активированным. Для информации о пользователе в пределах триггеров см. раздел 7.3.12.

Если Вы используете LOCK TABLES , чтобы заблокировать таблицу, у которой есть триггеры, таблицы, используемые в пределах триггера, также заблокированы, как описано в разделе 14.3.5.2.

См. раздел 21.3.1.

14.1.18. CREATE VIEW

CREATE
[OR REPLACE]
[ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
[DEFINER = { user | CURRENT_USER }]
[SQL SECURITY { DEFINER | INVOKER }]
VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION]
CREATE VIEW создает новое представление или заменяет существующее представление, если указано OR REPLACE. Если представление не существует, CREATE OR REPLACE VIEW то же самое, как CREATE VIEW. Если представление действительно существует, CREATE OR REPLACE VIEW то же самое, как ALTER VIEW.

См. раздел C.5.

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

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

ALGORITHM затрагивает, как MySQL обрабатывает представление. DEFINER и SQL SECURITY определяют контекст безопасности, который будет использоваться, проверяя привилегии доступа во время запроса представления. WITH CHECK OPTION может быть дан, чтобы ограничить вставки или обновления строк в таблицах, на которые ссылается представление. Эти пункты описаны позже в этом разделе.

CREATE VIEW требует привилегии CREATE VIEW для представления, и некоторую привилегию для каждого столбца, выбранного SELECT. Для столбцов, используемых в другом месте в SELECT, Вы должны иметь привилегию SELECT. Если указано OR REPLACE, Вы должны также иметь привилегию DROP для представления. CREATE VIEW мог бы также потребовать привилегию SUPER в зависимости от значения DEFINER, как описано позже в этом разделе.

Когда на представление ссылаются, проверка привилегии происходит как описано позже в этом разделе.

Представление принадлежит базе данных. По умолчанию, новое представление создается в базе данных по умолчанию. Чтобы создать представление явно в данной базе данных, надо использовать db_name.view_name , чтобы квалифицировать имя представления с именем базы данных:

CREATE VIEW test.v AS SELECT * FROM t;
Неквалифицированное имя таблицы или представления в SELECT также интерпретируется относительно базы данных значения по умолчанию. Представление может обратиться к таблицам или представлениям в других базах данных, квалифицируя таблицу или рассмотреть имя с соответствующим именем базы данных.

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

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

У представления должны быть уникальные имена столбцов без дубликатов, точно так же, как у базовой таблицы. По умолчанию названия столбцов, полученных SELECT, используются для имен столбцов представления. Чтобы определить явные названия столбцов представления, определите дополнительно column_list как список отделенных запятыми идентификаторов. Число имен в column_list должно быть то же самое, как число столбцов, полученных SELECT.

Представление может быть создано из многих видов SELECT. Это может сослаться на базовые таблицы или другие представления. Это может использовать соединения, UNION и подзапросы. SELECT даже не обязан обращаться к таблицам вообще:

CREATE VIEW v_today (today) AS SELECT CURRENT_DATE;
Следующий пример определяет представление, которое выбирает два столбца из другой таблицы, так же как выражение, вычисленное от тех столбцов:
mysql> CREATE TABLE t (qty INT, price INT);
mysql> INSERT INTO t VALUES(3, 50);
mysql> CREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;
mysql> SELECT * FROM v;
+-----+-------+-------+
| qty | price | value |
+-----+-------+-------+
| 3   | 50    |   150 |
+-----+-------+-------+
Определение представления подвергается следующим ограничениям:

  • SELECT не может отнестись к системным или определяемым пользователем переменным.

  • В пределах сохраненной программы SELECT не может отнестись к параметрам программы или местным переменным.
  • SELECT не может отнестись к готовым параметрам запроса.
  • Любая таблица или представление, упомянутое в определении, должны существовать. Если после того как представление было создано, таблица или представление удалено, использование результатов приведет к ошибке. Чтобы проверить определение представления на проблемы этого вида, используйте CHECK TABLE.
  • Определение не может отнестись к таблицам TEMPORARY, Вы не можете создать представление TEMPORARY.
  • Вы не можете связать триггер с представлением.
  • Псевдонимы для имен столбцов в SELECT проверены по максимальной длине столбца 64 символов (не максимальной длине псевдонима 256 символов).

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

Для других опций или пунктов в определении эффект не определен. Например, если определение представления включает LIMIT, и Вы выбираете из представления, используя запрос, у которого есть его собственный LIMIT, не определено, какой предел применяется. Этот же самый принцип относится к таким опциям, как ALL, DISTINCT или SQL_SMALL_RESULT, INTO, FOR UPDATE, LOCK IN SHARE MODE и PROCEDURE.

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

mysql> CREATE VIEW v (mycol) AS SELECT 'abc';
Query OK, 0 rows affected (0.01 sec)

mysql> SET sql_mode = '';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT "mycol" FROM v;
+-------+
| mycol |
+-------+
| mycol |
+-------+
1 row in set (0.01 sec)

mysql> SET sql_mode = 'ANSI_QUOTES';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT "mycol" FROM v;
+-------+
| mycol |
+-------+
| abc   |
+-------+
1 row in set (0.00 sec)
DEFINER и SQL SECURITY определяют, который пользователь MySQL использовать, проверяя привилегии доступа на представлении, когда запрос выполнен. Допустимые SQL SECURITY: DEFINER(значение по умолчанию) и INVOKER. Они указывают, что необходимые привилегии должны быть проведены пользователем, который определил или вызвал представление, соответственно.

Если user задано для DEFINER, это должна быть учетная запись MySQL, определенная как 'user_name'@'host_name' , CURRENT_USER или CURRENT_USER(). Значение по умолчанию DEFINER это пользователь, который выполняет CREATE VIEW. Это то же самое, как определение DEFINER = CURRENT_USER.

Если DEFINER задан, эти правила определяют допустимое значение DEFINER:

  • Если Вы не имеете привилегии SUPER, единственное допустимое значение user это Ваша собственная учетная запись, определенная буквально или при использовании CURRENT_USER. Вы не можете установить definer в некоторую другую учетную запись.

  • Если Вы имеете привилегию SUPER , Вы можете определить любое синтаксически допустимое имя учетной записи. Если учетная запись не существует, предупреждение произведено.
  • Хотя возможно создать представление с несуществующим DEFINER, ошибка происходит, когда на представление ссылаются, если SQL SECURITY = DEFINER, но definer нет.

См. раздел 21.6.

В пределах определения представления CURRENT_USER возвращает значение по умолчанию DEFINER. Для представлений, определенных с SQL SECURITY INVOKER, CURRENT_USER возвращает учетку вызывающего представление. См. раздел 7.3.12.

В пределах сохраненной подпрограммы, которая определена с SQL SECURITY DEFINER, CURRENT_USER возвращает DEFINER подпрограммы. Это также затрагивает представление, определенное в пределах такой подпрограммы, если определение представления содержит DEFINER CURRENT_USER.

MySQL проверяет привилегии представления:

  • Во время определения представления создателю представления нужны были привилегии, чтобы использовать высокоуровневые объекты, к которым получает доступ представление. Например, если определение представления ссылается на столбцы таблицы, у создателя должна быть некоторая привилегия для каждого столбца в избранном списке определения и привилегия SELECT для каждого столбца, используемого в другом месте в определении. Если определение относится к сохраненной функции, только привилегии нужные для вызова функцию, могут быть проверены. Привилегии, требуемые в функции, могут быть проверены только когда она выполняется: для различных вызовов могли быть взяты различные пути выполнения в пределах функции.

  • У пользователя, который ссылается на представление, должны быть соответствующие привилегии, чтобы получить доступ (SELECT, INSERT и т.д.).
  • Когда на представление сослались, привилегии для объектов, к которым получает доступ представление, проверены по привилегиям, проводимым DEFINER представления для создателя или обращающегося, смотря по значению SQL SECURITY (DEFINER или INVOKER).
  • Если ссылка на представление вызывает выполнение сохраненной функции, проверка привилегий запросов, выполненных в пределах функции, зависит от SQL SECURITY функции. Если характеристика безопасности DEFINER, функция работает с привилегиями учетки DEFINER. Если характеристика безопасности INVOKER, функция работает с привилегиями, определенными SQL SECURITY представления.

Пример: представление могло бы зависеть от сохраненной функции, а функция могла бы вызвать другие сохраненные подпрограммы. Например, следующее представление вызывает сохраненную функцию f():

CREATE VIEW v AS SELECT * FROM t WHERE t.id = f(t.name);
Предположите, что f() содержит запрос:
IF name IS NULL then
   CALL p1();
ELSE
   CALL p2();
END IF;
Привилегии, требуемые для того, чтобы выполнить запрос в пределах f(), будут проверены, когда выполняется f(). Это могло бы означать, что привилегии необходимы для p1() или p2(), в зависимости от пути выполнения в пределах f(). Те привилегии должны быть проверены во время выполнения, и пользователь, который должен обладать привилегиями, определен SQL SECURITY представления v и функции f().

DEFINER и SQL SECURITY для представлений это расширения к стандартному SQL. В стандартном SQL представления обработаны, используя правила для SQL SECURITY DEFINER. Стандарт говорит, что definer представления, который является тем же самым, как владельцем схемы представления, получает применимые права на представлении (например, SELECT ) и может предоставить их. У MySQL нет никакого понятия владельца схемы, таким образом, MySQL добавляет пункт, чтобы идентифицировать definer. DEFINER расширение, где намерение состоит в том, чтобы иметь то, что имеет стандарт, то есть, постоянный отчет о том, кто определил представление. Это то, почему значение по умолчанию DEFINER учетная запись создателя представления.

ALGORITHM тоже расширение MySQL. Это затрагивает, как MySQL обрабатывает представление. ALGORITHM берет три значения: MERGE, TEMPTABLE или UNDEFINED. См. разделы 21.5.2 и 9.2.1.18.3.

Некоторые представления обновляемые. Таким образом, Вы можете использовать их в запросах UPDATE, DELETE или INSERT, чтобы обновить содержание основной таблицы. Для представления, чтобы быть обновляемым, должны быть непосредственные отношения между строками в представлении и строками в основной таблице. Есть также определенные другие конструкции, которые делают представление необновляемым.

Произведенный столбец в представлении считают обновляемым, потому что возможно назначить на него значение. Однако, если такой столбец обновлен явно, единственное разрешенное значение DEFAULT. См. раздел 14.1.15.5.

WITH CHECK OPTION может быть дан для обновляемого представления, чтобы предотвратить вставки или обновления к строкам кроме тех, для которых WHERE в select_statement истина.

В WITH CHECK OPTION для обновляемого представления ключевые слова LOCAL и CASCADED определяют контекст проверки, когда представление определено с точки зрения другого представления. LOCAL ограничивает CHECK OPTION только к определяемому представлению. CASCADED вызывает проверку на то, чтобы лежать в основе представлений, которые будут оценены также. Когда никакое ключевое слово не дано, значение по умолчанию CASCADED.

См. разделы 21.5.3 и 21.5.4.

14.1.19. DROP DATABASE

DROP {DATABASE | SCHEMA} [IF EXISTS] db_name
DROP DATABASE удаляет все таблицы в базе данных и базу данных. Будьте очень осторожны с этим запросом! Чтобы использовать DROP DATABASE, нужна привилегия DROP на базе данных. DROP SCHEMA синоним для DROP DATABASE.

Когда база данных удалена, пользовательские привилегии на базе данных не удалены автоматически. см. раздел 14.7.1.6.

IF EXISTS используется, чтобы препятствовать ошибке, если база данных не существует.

Если база данных по умолчанию удалена, она сброшена (DATABASE() вернет NULL).

Если Вы используете DROP DATABASE на символически соединенной базе данных, удалены ссылка и оригинальная база данных.

DROP DATABASE возвращает число таблиц, которые были удалены.

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

.BAK.DAT .HSH.MRG
.MYD.MYI .cfg.db
.ibd.ndb

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

Удаление базы данных не удаляет таблицы TEMPORARY, которые были составлены в той базе данных. Таблицы TEMPORARY автоматически удалены, когда сеанс, который создал их, заканчивается.

Вы можете также удалить базы данных с помощью mysqladmin . см. раздел 5.5.2.

14.1.20. DROP EVENT

DROP EVENT [IF EXISTS] event_name
Этот запрос удаляет событие event_name. Оно немедленно прекращает быть активным и удалено полностью из сервера.

Если событие не существует, будет ошибка ERROR 1517 (HY000): Unknown event 'event_name'. Вы можете переопределить это и заставить запрос вместо этого производить предупреждение для несуществующих событий, используя IF EXISTS.

Это запрос требует привилегии EVENT для схемы, к которой принадлежит удаляемое событие.

14.1.21. DROP FUNCTION

DROP FUNCTION используется, чтобы удалить сохраненные функции и определяемые пользователем функции (UDF):

14.1.22. DROP INDEX

DROP INDEX index_name ON tbl_name
[algorithm_option | lock_option] ...

algorithm_option:
ALGORITHM [=] {DEFAULT|INPLACE|COPY}

lock_option:
LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}
DROP INDEX удаляет индекс index_name из таблицы tbl_name. Отображен на ALTER TABLE, чтобы удалить индекс. См. раздел 14.1.7.

Чтобы удалить первичный ключ, имя индекса всегда PRIMARY, которое должно быть определено как заключенный в кавычки идентификатор, потому что PRIMARY спецслово:

DROP INDEX `PRIMARY` ON t;
ALGORITHM и LOCK могут быть указаны. Они влияют на табличный метод копирования и уровень параллелизма для чтения и записи таблицы в то время, как индекс изменяется. У них есть то же самое значение, что ALTER TABLE. См. раздел 14.1.7.

14.1.23. DROP PROCEDURE и DROP FUNCTION

DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name
Этот запрос используется, чтобы удалить хранимую процедуру или функцию. Таким образом, указанная подпрограмма удалена из сервера. Вы должны иметь привилегию ALTER ROUTINE для подпрограммы. Если включена automatic_sp_privileges , эта привилегия и EXECUTE предоставлены автоматически создателю, когда подпрограмма создана и удалены у создателя, когда подпрограмма удалена. См. раздел 21.2.2.

IF EXISTS расширение MySQL. Это препятствует ошибке, если процедура или функция не существуют. Предупреждение произведено, которое может быть рассмотрено с SHOW WARNINGS .

DROP FUNCTION также используется, чтобы удалить определяемые пользователем функции (см. раздел 14.7.3.2).

14.1.24. DROP SERVER

DROP SERVER [ IF EXISTS ] server_name
Удаляет определение сервера для названного сервера server_name. The Соответствующая строка в mysql.servers удалена. Это запрос требует привилегию SUPER.

Удаление сервера для таблицы не затрагивает таблицы FEDERATED, которые использовали эту информацию о соединении, когда они создавались. См. раздел 14.1.14 .

DROP SERVER не закрывает транзакцию.

DROP SERVER не записан в двоичный журнал, независимо от формата журналирования, который используется.

14.1.25. DROP TABLE

DROP [TEMPORARY] TABLE [IF EXISTS]
tbl_name [, tbl_name] ...
[RESTRICT | CASCADE]
DROP TABLE удаляет одну или более таблиц. Вы должны иметь привилегию DROP для каждой таблицы. Все табличные данные и табличное определение удалены, так что будьте осторожны ! Если какая-либо из таблиц, названных в списке параметров, не существует, MySQL возвращает ошибку, указывая по имени, какие несуществующие таблицы не удалось удалить, но удаляет все таблицы в списке, которые действительно существуют.

Когда таблица удалена, пользовательские привилегии на таблице не удалены автоматически. См. раздел 14.7.1.6.

Для разделенной таблицы DROP TABLE удаляет табличное определение, все его разделение и все данные, которые хранились в разделении. Это также удаляет определения разделения, связанные с удаленной таблицей.

IF EXISTS препятствует ошибке для таблиц, которые не существуют. NOTE произведен для каждой несуществующей таблицы, используя IF EXISTS. См. раздел 14.7.5.40 .

RESTRICT и CASCADE разрешены, чтобы сделать проще портирование. В MySQL 8.0 ничего они не делают.

DROP TABLE автоматически закрывает текущую активную транзакцию, если Вы не используете TEMPORARY.

TEMPORARY имеет следующие эффекты:

  • Запрос удаляется только таблицы TEMPORARY.

  • Запрос не заканчивает продолжающуюся транзакцию.
  • Никакие права доступа не проверены (TEMPORARY видима только сеансу, который создал ее, таким образом, никакая проверка не нужна).

Применение TEMPORARY хороший способ гарантировать, что Вы случайно не удаляете не-TEMPORARY таблицу.

14.1.26. DROP TABLESPACE

DROP TABLESPACE tablespace_name
   [ENGINE [=] engine_name]
Этот запрос используется, чтобы удалить общее табличное пространство InnoDB, которое создавалось, используя CREATE TABLESPACE (см. раздел 14.1.16).

Все таблицы должны быть исключены из табличного пространства до DROP TABLESPACE. Если табличное пространство не пусто, DROP TABLESPACE возвращает ошибку.

tablespace_name чувствительный к регистру идентификатор в MySQL.

ENGINE: Определяет механизм хранения, который использует табличное пространство, где engine_name название механизма хранения. В настоящее время только InnoDB поддержан. Вы не должны определить ENGINE = InnoDB, если InnoDB определен как механизм хранения по умолчанию ( default_storage_engine=InnoDB).

DROP TABLESPACE поддержан с InnoDB с MySQL 5.7.6. В более ранних выпусках DROP TABLESPACE поддерживает NDB, MySQL Cluster. DROP TABLESPACE поддерживает NDB в MySQL 5.7 когда MySQL Cluster переходит кодовой базы MySQL 5.7. Последняя версия MySQL Cluster основана на MySQL 5.6.

Примечания

  • Табличное пространство не удалено автоматически, когда последняя таблица в табличном пространстве удалена. Табличное пространство должно быть удалено явно, используя DROP TABLESPACE tablespace_name .

  • DROP DATABASE может удалить таблицы, которые принадлежат общему табличному пространству, но она не может удалить табличное пространство, даже если удаляет все таблицы, которые принадлежат табличному пространству. Табличное пространство должно быть удалено явно, используя DROP TABLESPACE tablespace_name.
  • Подобно системному табличному пространству, усекание или удаление таблиц, сохраненных в общем табличном пространстве, создает свободное пространство внутренне в общем табличном пространстве InnoDB.

Пример

Этот пример демонстрирует, как удалить общее табличное пространство InnoDB. Общее табличное пространство ts1 создается с единственной таблицей. Прежде чем удалить табличное пространство, таблица должна быть удалена.

mysql> CREATE TABLESPACE `ts1` ADD DATAFILE 'ts1.ibd' Engine=InnoDB;
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE ts10 Engine=InnoDB;
Query OK, 0 rows affected (0.02 sec)

mysql> DROP TABLE t1;
Query OK, 0 rows affected (0.01 sec)

mysql> DROP TABLESPACE ts1;
Query OK, 0 rows affected (0.01 sec)

14.1.27. DROP TRIGGER

DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name
Этот запрос удаляет триггер. Имя хемы (базы данных) является дополнительным. Если схема опущена, триггер исключен из схемы по умолчанию. DROP TRIGGER требует привилегию TRIGGER для таблицы с триггером.

IF EXISTS препятствовует ошибке для триггера, который не существует. См. раздел 14.7.5.40.

Триггеры для таблицы также удалены, если Вы удаляете таблицу.

14.1.28. DROP VIEW

DROP VIEW [IF EXISTS]
view_name [, view_name] ...
[RESTRICT | CASCADE]
DROP VIEW удаляет одно или более представлений. Вы должны иметь привилегию DROP для каждого представления. Если какое-либо из представлений, названных в списке параметров, не существует, MySQL возвращает ошибку, указывая по имени, какие несуществующие представления это было неспособно удалить, но удаляет все представления в списке, которые действительно существуют.

IF EXISTS препятствует ошибке для представлений, которые не существуют. См. раздел 14.7.5.40.

RESTRICT и CASCADE, если дано, разобраны и проигнорированы.

14.1.29. RENAME TABLE

RENAME TABLE tbl_name TO new_tbl_name
[, tbl_name2 TO new_tbl_name2] ...
Это запрос переименовывает одну или более таблиц. Работа сделана атомарно, что означает, что никакой другой сеанс не может получить доступ ни к одной из таблиц в то время, как переименование работает.

Например, таблица old_table может быть переименована new_table:

RENAME TABLE old_table TO new_table;
Этот запрос эквивалентен ALTER TABLE:
ALTER TABLE old_table RENAME new_table;
Если запрос переименовывает больше, чем одну таблицу, операции сделаны слева направо. Если Вы хотите поменять два имени таблиц, Вы можете сделать так (tmp_table пока нет):
RENAME TABLE old_table TO tmp_table, new_table TO old_table,
       tmp_table TO new_table;
MySQL проверяет целевое имя таблицы прежде, чем проверить, существует ли исходная таблица. Например, если new_table уже есть, а old_table пока нет, следующий запрос терпит неудачу, как показано здесь:
mysql> SHOW TABLES;
+----------------+
| Tables_in_mydb |
+----------------+
| table_a        |
+----------------+
1 row in set (0.00 sec)

mysql> RENAME TABLE table_b TO table_a;
ERROR 1050 (42S01): Table 'table_a' already exists
Если две базы данных находятся на той же самой файловой системе, Вы можете использовать RENAME TABLE, чтобы перемещать таблицу от одной базы данных в другую:
RENAME TABLE current_db.tbl_name
       TO other_db.tbl_name;
Вы можете использовать этот метод, чтобы переместить все таблицы от одной базы данных в другую, в действительности переименовывая базу данных. У MySQL нет никакого спецзапроса, чтобы выполнить эту задачу.

Если есть какие-либо триггеры, связанные с таблицей, которая перемещена в иную базу данных, запрос терпит неудачу с ошибкой Trigger in wrong schema.

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

RENAME TABLE также работает для представлений, пока Вы не пытаетесь переименовать представление в иную базу данных.

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

Когда Вы выполняете RENAME TABLE, у Вас не может быть никаких заблокированных таблиц или активных транзакций. Вы должны также иметь привилегии ALTER и DROP на оригинальной таблице, CREATE и INSERT на новой таблице.

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

Вы не можете использовать RENAME TABLE, чтобы переименовать таблицу TEMPORARY. Однако, Вы можете использовать ALTER TABLE.

Подобно RENAME TABLE, ALTER TABLE ... RENAME может также использоваться, чтобы переместить таблицу в иную базу данных. Независимо от запроса, используемого, чтобы выполнить переименовывание, если работа переместила бы таблицу в базу данных, расположенную в иной файловой системе, успех результата определен платформой и зависит от основных требований операционной системы, используемых, чтобы переместить табличные файлы.

14.1.30. TRUNCATE TABLE

TRUNCATE [TABLE] tbl_name
TRUNCATE TABLE освобождает таблицу полностью. Это требует привилегии DROP. Логически TRUNCATE TABLE это DELETE, который удаляет все строки, или последовательность DROP TABLE и CREATE TABLE.

В MySQL 8.0 TRUNCATE TABLE отображен на DROP TABLE и CREATE TABLE. В результате этого изменения TRUNCATE TABLE является временно не атомным. Сьой сервера во время TRUNCATE TABLE может привести к удаленной таблице и ограничениям внешнего ключа в системных таблицах InnoDB SYS_FOREIGN и SYS_FOREIGN_COLS.

Чтобы достигнуть высокой производительности, TRUNCATE TABLE обходит метод DML удаления данных. Таким образом, это не может быть откачено, это не вызывает триггеры ON DELETE и это не может быть выполнено для таблиц InnoDB с родительско-дочерними отношениями внешнего ключа.

Хотя TRUNCATE TABLE подобно DELETE, это классифицировано как запрос DDL, а не запрос DML. Это отличается от DELETE:

  • Усеченные операции удаляют и обновляют таблицу намного быстрее, чем удаление строк, особенно для больших таблиц.

  • Усеченные операции вызывают неявное закрытие транзакции и не могут быть откачены.
  • Операции усечения не могут быть выполнены, если сеанс держит активную табличную блокировку.
  • TRUNCATE TABLE терпит неудачу для таблицы InnoDB или NDB, если есть ограничения FOREIGN KEY от других таблиц. Ограничения внешнего ключа между столбцами той же самой таблицы разрешены.
  • Операции усечения не возвращают значащее значение для числа удаленных строк. Обычный результат 0 rows affected, который должен интерпретироваться как нет данных.
  • Пока табличное определение допустимо, таблица может быть обновлена как пустая таблица с TRUNCATE TABLE , даже если файлы с данными или индексные файлы стали поврежденными.
  • Любое значение AUTO_INCREMENT сброшено к его стартовому значению. Это истина даже для MyISAM и InnoDB, которые обычно не используют значения последовательности снова.
  • Когда используется с разделенными таблицами, TRUNCATE TABLE сохраняет разделение, то есть, файлы с данными и индексные файлы удалены и обновлены в то время, как определения разделения не затронуты.
  • TRUNCATE TABLE не вызывает триггеры ON DELETE triggers.

TRUNCATE TABLE закрывает все обработчики для таблицы, которые были открыты с HANDLER OPEN.

TRUNCATE TABLE пишется в репликацию как DROP TABLE и CREATE TABLE, то есть DDL вместо DML. Это вследствие того, что, используя InnoDB и другие транзакционные механизмы хранения, где операционный уровень изоляции не разрешает основанное на запросе журналирование ( READ COMMITTED или READ UNCOMMITTED), запрос не был зарегистрирован и копировался, используя режим STATEMENT или MIXED (Bug #36763).

В MySQL 5.7 и ранее на системе с большим буферным пулом и включенным innodb_adaptive_hash_index TRUNCATE TABLE может вызвать временное падение системной работы из-за просмотра LRU, который произошел, когда удаление индекса адаптивного хеша таблицы записано (Bug #68184). Переотображение TRUNCATE TABLE на DROP TABLE и CREATE TABLE в MySQL 8.0 избегает проблематичного просмотра LRU.

TRUNCATE TABLE может использоваться с Performance Schema, но эффект состоит в том, чтобы сбросить сводные столбцы к 0 или NULL, а не удалению строк. См. раздел 23.9.15.

14.2. Манипуляции данными

14.2.1. CALL

CALL sp_name([parameter[,...]])
CALL sp_name[()]
CALL вызывает хранимую процедуру, которая была определена ранее с CREATE PROCEDURE.

Хранимые процедуры, которые не берут параметров, могут быть вызваны без круглых скобок. Таким образом, CALL p() и CALL p аналогичны.

CALL может передать назад значения, используя параметры, которые объявлены как OUT или INOUT. Когда процедура возвращается, программа клиента может также получить число строк, затронутых для заключительного запроса, выполненного в пределах подпрограммы: на уровне SQL вызовите ROW_COUNT(), из C API вызовите mysql_affected_rows().

Чтобы возвращать значение из процедуры, используя параметр OUT или INOUT, передайте параметр посредством пользовательской переменной, а затем проверьте значение переменной после возвращений процедуры. Если Вы вызываете процедуру изнутри другой хранимой процедуры или функции, Вы можете также передать обычный параметр или местную переменную как параметр IN или INOUT. Для INOUT инициализируйте его значение прежде, чем передать к процедуре. Следующая процедура имеет параметры OUT, которые процедура устанавливает к текущей версии сервера, и значение INOUT, которое процедура постепенно увеличивает:

CREATE PROCEDURE p (OUT ver_param VARCHAR(25), INOUT incr_param INT)
BEGIN
  # Set value of OUT parameter
  SELECT VERSION() INTO ver_param;
  # Increment value of INOUT parameter
  SET incr_param = incr_param + 1;
END;
Прежде, чем вызвать процедуру, инициализируйте переменную, которую передадут как INOUT. После запроса процедуры значения этих двух переменных будут установлены или изменены:
mysql> SET @increment = 10;
mysql> CALL p(@version, @increment);
mysql> SELECT @version, @increment;
+--------------+------------+
| @version     | @increment |
+--------------+------------+
| 5.5.3-m3-log | 11         |
+--------------+------------+
В готовом запросе CALL, используемом с PREPARE и EXECUTE, заполнители могут использоваться для параметров IN, OUT и INOUT. Эти типы параметров могут использоваться следующим образом:
mysql> SET @increment = 10;
mysql> PREPARE s FROM 'CALL p(?, ?)';
mysql> EXECUTE s USING @version, @increment;
mysql> SELECT @version, @increment;
+--------------+------------+
| @version     | @increment |
+--------------+------------+
| 5.5.3-m3-log | 11         |
+--------------+------------+
Чтобы написать программу на C, которая использует CALL, чтобы выполнить хранимые процедуры, которые производят наборы результатов, флаг CLIENT_MULTI_RESULTS должен быть включен. Это потому, что каждый вызов CALL возвращает результат, чтобы указать на состояние запроса, в дополнение к любым наборам результатов, которые могли бы быть возвращены запросами, выполненными в пределах процедуры. CLIENT_MULTI_RESULTS должен также быть включен, если CALL используется, чтобы выполнить любую хранимую процедуру, которая содержит готовые запросы. Не может быть определено, когда такая процедура загружена, произведут ли те запросы наборы результатов, таким образом, будет необходимо предположить, что они будут.

CLIENT_MULTI_RESULTS может быть включен, когда Вы вызываете mysql_real_connect() , явно, передавая CLIENT_MULTI_RESULTS непосредственно, или неявно, передавая CLIENT_MULTI_STATEMENTS (который также включает CLIENT_MULTI_RESULTS). В MySQL 8.0 CLIENT_MULTI_RESULTS включен по умолчанию.

Чтобы обработать результат CALL, используя mysql_query() или mysql_real_query() , используйте цикл, который вызывает mysql_next_result(), чтобы определить, есть ли больше результатов. Для примера см. раздел 25.8.17.

В MySQL 8.0 программы на C могут использовать интерфейс готового запроса, чтобы выполнить CALL и обратиться к параметрам OUT и INOUT. Это сделано, обрабатывая результат CALL , используя цикл, который вызывает mysql_stmt_next_result() , чтобы определить, есть ли больше результатов. Для примера см. раздел 25.8.20. Языки, которые обеспечивают интерфейс MySQL, могут использовать подготовленный CALL, чтобы непосредственно получить параметры процедуры OUT и INOUT.

В MySQL 8.0 метаданные, измененные объектами, упомянутыми сохраненными программами, обнаружены и вызывают автоматический перепарсинг затронутых запросов, когда программа затем выполнена. Для получения дополнительной информации см. раздел 9.10.4.

14.2.2. DELETE

DELETE это запрос DML, который удаляет строки из таблицы.

Однотабличный синтаксис

DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name
[PARTITION (partition_name,...)]
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
DELETE удаляет строки из tbl_name и возвращает число удаленных строк. Чтобы проверить число удаленных строк, вызовите ROW_COUNT(), см. раздел 13.14.

Главные предложения

Условия в дополнительном WHERE идентифицирует, которые строки удалить. Без WHERE все строки удалены.

where_condition выражение, которое оценивается к истине для каждой строки, которая будет удалена. Это определено как описано в разделе 14.2.9.

Если указан ORDER BY, строки удалены в порядке, который определен. LIMIT устанавливает границу числа строк, которые могут быть удалены. Эти пункты относятся к единственной таблице, но не к удалению из нескольких таблиц.

Многотабличный синтаксис

DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
tbl_name[.*] [, tbl_name[.*]] ...
FROM table_references
[WHERE where_condition]
Или:
DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
FROM tbl_name[.*] [, tbl_name[.*]] ...
USING table_references
[WHERE where_condition]

Привилегии

Вы нуждаетесь в привилегии DELETE на таблице, чтобы удалить строки из нее. Вы нуждаетесь только в привилегии SELECT для любых столбцов, которые только считаны, такие как названные в WHERE.

Работа

Когда Вы не должны знать число удаленных строк, TRUNCATE TABLE более быстрый способ освободить таблицу, чем DELETE без WHERE. В отличие от этого, TRUNCATE TABLE не может использоваться в пределах транзакции, или если у Вас есть блокировка на таблице. См. разделы 14.1.30 и 14.3.5.

Скорость операции удаления может также быть затронута факторами, обсужденными в разделе 9.2.2.3.

Чтобы гарантировать, что данный запрос DELETE не занимает слишком много времени, параметр LIMIT row_count для DELETE определяет максимальное количество строк, которые будут удалены. Если число строк, чтобы удалить, больше предела, повторите DELETE до числа затронутых строк меньше LIMIT.

Подзапросы

Вы не можете удалить из таблицы и выбрать из той же самой таблицы в одном подзапросе.

Разделенные таблицы

DELETE поддерживает явный выбор разделения, используя опцию PARTITION, которая берет список разделенных запятой значений названий из одного или более разделов или подразделов (или обоих), из которых можно выбрать строки, которые будут исключены. Проигнорировано разделение, не включенное в список. Учитывая разделенную таблицу t с разделом p0, выполнение DELETE FROM t PARTITION (p0) имеет тот же самый эффект на таблицу как выполнение ALTER TABLE t TRUNCATE PARTITION (p0), в обоих случаях все строки в разделе p0 удалены.

PARTITION может использоваться наряду с WHERE, тогда условие проверено только на строках в перечисленном разделе. Например, DELETE FROM t PARTITION (p0) WHERE c < 5 удаляет строки только из раздела p0 для которых верно условие c < 5, строки в любом другом разделе не проверены и таким образом не затронуты DELETE.

Опция PARTITION может также использоваться в многотабличном DELETE. Вы можете использовать до одной такой опции на таблицу, названную в опции FROM.

См. раздел 20.5.

Столбцы Auto-Increment

Если Вы удаляете строку, содержащую максимальное значение для AUTO_INCREMENT, значение не использовано снова для MyISAM или InnoDB. Если Вы удаляете все строки в таблице с DELETE FROM tbl_name (без WHERE) в режиме autocommit, последовательность запускается для всех механизмов хранения, кроме InnoDB и MyISAM. Есть некоторые исключения к этому поведению для InnoDB, см. раздел 16.8.5.

Для MyISAM Вы можете определить второй столбец AUTO_INCREMENT в многостолбцовом ключе. В этом случае повторное использование значений, удаленных из вершины последовательности, происходит даже для MyISAM. См. раздел 4.6.9.

Модификаторы

DELETE поддерживает следующие модификаторы:

  • Если Вы определяете LOW_PRIORITY, сервер задерживает выполнение DELETE пока никакие другие клиенты не читают из таблицы. Это затрагивает только механизмы хранения, которые используют только блокировку на уровне таблицы (такие, как MyISAM, MEMORY и MERGE).

  • Для MyISAM таблицы, если Вы используете параметр QUICK, механизм хранения не сливает листья индекса во время удаления, что может убыстрить некоторые виды удаления.
  • IGNORE заставляет MySQL игнорировать ошибки во время процесса удаления строк. Ошибки, с которыми сталкиваются во время этапа парсинга, обработаны в обычной манере. Ошибки, которые проигнорированы из-за использования IGNORE, возвращены как предупреждения.

Порядок удаления

Если DELETE включает ORDER BY, строки удалены в порядке, определенном пунктом. Это полезно прежде всего в соединении с LIMIT. Например, следующий запрос находит строки, соответствующие WHERE, сортирует их по timestamp_column и удаляет первую (самый старую):

DELETE FROM somelog WHERE user = 'jcole'
       ORDER BY timestamp_column LIMIT 1;
ORDER BY также помогает удалить строки в порядке, требуемом, чтобюы избегать нарушений ссылочной целостности.

Таблицы InnoDB

Если Вы удаляете много строк из большой таблицы, Вы можете превысить табличный размер блокировки для InnoDB. Чтобы избежать этой проблемы или просто минимизировать время, когда таблица остается заблокированной, следующая стратегия (которая не использует DELETE вообще), могла бы быть полезным:

  1. Выберите строки, которые не будут удалены в пустую таблицу, у которой есть та же самая структура, как у оригинальной:

    INSERT INTO t_copy SELECT * FROM t WHERE ... ;
    
  2. Используйте RENAME TABLE, чтобы атомарно переместить оригинальную таблицу из пути и переименовать копию к настоящему имени:
    RENAME TABLE t TO t_old, t_copy TO t;
    
  3. Удалите оригинальную таблицу:
    DROP TABLE t_old;
    

Никакие другие сеансы не могут получить доступ к вовлеченным таблицам в то время, как работает RENAME TABLE , таким образом, переименование не подвергается проблемам параллелизма. См. раздел 14.1.29.

Таблицы MyISAM

В MyISAM удаленные строки поддержаны в связанном списке и последующие INSERT повторно используют старые позиции строки. Чтобы восстановить неиспользуемое место и уменьшить размеры файла, используйте OPTIMIZE TABLE или myisamchk, чтобы реорганизовать таблицы. OPTIMIZE TABLE легче использовать, но myisamchk быстрее. См. разделы 14.7.2.4 и 5.6.4.

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

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

  1. Составьте таблицу, которая содержит индексированный столбец AUTO_INCREMENT.

  2. Вставьте много строк в таблицу. Каждая вставка в индекс добавляет значение к верхнему концу индекса.
  3. Удалите блок строк на нижнем конце диапазона столбца, используя DELETE QUICK.

В этом сценарии блоки индекса, связанные с удаленными значениями, становятся сильно пустыми, но не слиты с другим блоками индекса из-за использования QUICK. Они остаются такими, когда новые вставки происходят, потому что новые строки не имеют индексных значений в удаленном диапазоне. Кроме того, они остаются пустыми даже если Вы позже используете DELETE без QUICK, если некоторые из удаленных индексных значений лежат в блоках в пределах или смежных с незаполненными блоками. Чтобы исправить неиспользованное индексное пространство при этих обстоятельствах, используют OPTIMIZE TABLE.

Если Вы собираетесь удалить много строк из таблицы, могло бы быть быстрее, использовать DELETE QUICK сопровождаемый OPTIMIZE TABLE. Это восстанавливает индексирование вместо того, чтобы делать много операций слияния индексных блоков.

Мультитабличное удаление

Вы можете определить много таблиц в DELETE, чтобы удалить строки из одной или более таблиц в зависимости от условия в WHERE. Вы не можете использовать ORDER BY или LIMIT в многотабличном DELETE. table_references перечисляет таблицы, вовлеченные в соединение, как описано в разделе 14.2.9.2.

Для первого многотабличного синтаксиса соответствуют только строки от таблиц, перечисленных перед FROM. Для второго соответствуют только строки от таблиц, перечисленных в FROM (до USING). Эффект состоит в том, что Вы можете удалить строки из многих таблиц в то же самое время и иметь дополнительные таблицы, которые используются только для того, чтобы искать:

DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3
       WHERE t1.id=t2.id AND t2.id=t3.id;
Или:
DELETE FROM t1, t2 USING t1 INNER JOIN t2 INNER JOIN t3
       WHERE t1.id=t2.id AND t2.id=t3.id;
Эти запросы используют все три таблицы, ища строки, чтобы удалить, но удаляют соответствующие строки только из таблиц t1 и t2.

Предыдущее использование в качестве примера INNER JOIN, но мультитабличный DELETE может использовать другие типы соединения, разрешенные в SELECT, например, LEFT JOIN. Например, чтобы удалить строки, которые существуют в t1, у которых нет никакого соответствия в t2, используйте LEFT JOIN:

DELETE t1 FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
Синтаксис допускает .* после каждого tbl_name для совместимости с Access.

Если Вы используете многотабличный DELETE с таблицами InnoDB, для которых есть ограничения внешнего ключа, оптимизатор MySQL мог бы обработать таблицы в порядке, который отличается от их родительских/дочерних отношений. В этом случае запрос терпит неудачу и откатывается. Вместо этого Вы должны удалить из единственной таблицы и использовать ON DELETE, который обеспечивает InnoDB, чтобы заставить другие таблицы быть измененными соответственно.

Если Вы объявляете псевдоним для таблицы, Вы должны использовать псевдоним, обращаясь к таблице:

DELETE t1 FROM test AS t1, test2 WHERE ...

Табличные псевдонимы в многотабличном DELETE должны быть объявлены только в части table_references. В другом месте ссылки псевдонима разрешены, но не декларации псевдонима.

Правильно:

DELETE a1, a2 FROM t1 AS a1 INNER JOIN t2 AS a2
       WHERE a1.id=a2.id;

DELETE FROM a1, a2 USING t1 AS a1 INNER JOIN t2 AS a2
       WHERE a1.id=a2.id;
Неправильно:
DELETE t1 AS a1, t2 AS a2 FROM t1 INNER JOIN t2 WHERE a1.id=a2.id;
DELETE FROM t1 AS a1, t2 AS a2 USING t1 INNER JOIN t2 WHERE a1.id=a2.id;

14.2.3. DO

DO expr [, expr] ...
DO выполняет выражения, но не возвращает результатов. В большинстве отношений DO сокращение для SELECT expr, ..., но имеет преимущество, что это немного быстрее, когда Вы не заботитесь о результате.

DO полезно прежде всего с функциями, у которых есть побочные эффекты, например, с RELEASE_LOCK().

Пример: Этот SELECT тормозит запросы, но также и производит набор результатов:

mysql> SELECT SLEEP(5);
+----------+
| SLEEP(5) |
+----------+
| 0        |
+----------+
1 row in set (5.02 sec)
DO, с другой стороны, делает такую же паузу, не производя набор результатов:
mysql> DO SLEEP(5);
Query OK, 0 rows affected (4.99 sec)
Это могло быть полезно, например в сохраненной функции или триггере которые запрещают запросы, которые производят наборы результатов.

DO только выполняет выражения. Это не может использоваться во всех случаях, где SELECT. Например, DO id FROM t1 недопустимо, потому что это ссылается на таблицу.

14.2.4. HANDLER

HANDLER tbl_name OPEN [ [AS] alias]
HANDLER tbl_name READ index_name
        { = | <= | >= | < | > } (value1,
        value2,...)
        [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name
        { FIRST | NEXT | PREV | LAST }
        [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
        [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name CLOSE
HANDLER обеспечивает прямой доступ к табличным интерфейсам механизма хранения. Это доступно для InnoDB и MyISAM.

HANDLER ... OPEN открывает таблицу, делая это доступным последующму использованию HANDLER ... READ. Этот табличный объект не использован совместно другими сеансами и не закрыт до HANDLER ... CLOSE или конца сеанса.

Если Вы открываете таблицу, используя псевдоним, дальнейшие ссылки на открытую таблицу с другим HANDLER должны использовать псевдоним, а не имя таблицы. Если Вы не используете псевдоним, но открываете таблицу, используя имя таблицы, квалифицированное именем базы данных, дальнейшие ссылки должны использовать неквалифицированное имя таблицы. Например, для таблицы, открытой, используя mydb.mytable, дальнейшие ссылки должны использовать mytable.

Первый синтаксис HANDLER ... READ приносит строку, где указанный индекс удовлетворяет данные значения и соблюдает WHERE. Если у Вас есть многостолбцовый индекс, укажите список значений столбцов как список разделенных запятой значений. Или определите значения для всех столбцов в индексировании, или определите значения для крайнего левого префикса индекса столбцов. Предположите, что индекс my_idx включает три столбца col_a, col_b и col_c, в этом порядке. HANDLER может определить значения для всех трех столбцов в индексе или для столбцов в крайнем левом префиксе. Например:

HANDLER ... READ my_idx = (col_a_val,col_b_val,col_c_val) ...
HANDLER ... READ my_idx = (col_a_val,col_b_val) ...
HANDLER ... READ my_idx = (col_a_val) ...
Чтобы использовать HANDLER интерфейс, чтобы обратиться к таблице PRIMARY KEY, используйте заключенный в кавычки идентификатор `PRIMARY`:
HANDLER tbl_name READ `PRIMARY` ...
Второй синтаксис HANDLER ... READ приносит строку от таблицы в порядке индекса, который соответствует WHERE.

Третий синтаксис HANDLER ... READ приносит строку от таблицы в естественном порядке строк, который соответствует WHERE. Это быстрее HANDLER tbl_name READ index_name, когда полное сканирование таблицы желаемо. Естественный порядок строк это порядок, в котором строки сохранены в файле данных. Это запрос работает на InnoDB также, но нет такого понятия, потому что нет никакого отдельного файла с данными.

Без LIMIT все формы HANDLER ... READ принесут единственную строку. Чтобы возвратить определенное число строк, включайте LIMIT. У него есть тот же самый синтаксис, как у SELECT, см. раздел 14.2.9.

HANDLER ... CLOSE закрывает таблицу, которая была открыта HANDLER ... OPEN.

Есть несколько причин использовать интерфейс HANDLER вместо нормального SELECT:

  • HANDLER быстрее SELECT:

    • Определяемый объект обработчика механизма хранения выделен для HANDLER ... OPEN. Объект снова использован для последующего HANDLER для этой таблицы: это не должно быть повторно инициализировано для каждого.

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

  • HANDLER облегчает портирование на MySQL приложения MySQL, которые используют низкий уровень ISAM См. раздел 16.19.
  • HANDLER позволяет Вам пересечь базу данных в манере, которая является трудной (или даже невозможной) с SELECT. HANDLER более естественный способ смотреть на данные, работая с приложениями, которые обеспечивают интерактивный пользовательский интерфейс базе данных.

HANDLER несколько низкоуровневый запрос. Например, это не обеспечивает последовательность. Таким образом, HANDLER ... OPEN не берет снимок таблицы, и не блокирует таблицу. Это означает, что после HANDLER ... OPEN табличные данные могут быть изменены (текущим сеансом или другими сеансами), и эти модификации могли бы быть только частично видимыми в HANDLER ... NEXT или HANDLER ... PREV.

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

  • Любой сеанс выполняет FLUSH TABLES или запросы DDL на таблице обработчика.

  • Сеанс, в котором обработчик открыт, выполняет не-HANDLER запросы для таблицы.

TRUNCATE TABLE закрывает все обработчики для таблицы, которые были открыты с HANDLER OPEN.

Если таблица сбрасывается с FLUSH TABLES tbl_name WITH READ LOCK, обработчик неявно сбрасывается и теряет свою позицию.

14.2.5. INSERT

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name,...)]
[(col_name,...)]
{VALUES | VALUE} ({expr | DEFAULT},...),(...),...
[ ON DUPLICATE KEY UPDATE
  col_name=expr
[, col_name=expr] ... ]
Или:
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name,...)]
SET col_name={expr | DEFAULT}, ...
[ ON DUPLICATE KEY UPDATE
  col_name=expr
[, col_name=expr] ... ]
Или:
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name,...)]
[(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE
  col_name=expr
[, col_name=expr] ... ]
INSERT вставляет новые строки в существующую таблицу. INSERT ... VALUES и INSERT ... SET формы вставляют строки, основанные на явно указанных значениях. INSERT ... SELECT вставляет строки, выбранные из другой таблицы или таблиц. INSERT ... SELECT рассмотрена в разделе 14.2.5.1.

Вставляя в разделенную таблицу, Вы можете управлять, какие раздел и подраздел принимают новые строки. PARTITION берет список разделенных запятой значений названий одного или более раздела или подразда (или оба) таблицы. Если любая из строк, которые будут вставлены данным INSERT не соответствует одному из перечисленных разделов, INSERT терпит неудачу с ошибкой Found a row not matching the given partition set. См. раздел 20.5.

В MySQL 8.0 DELAYED принято, но проигнорировано сервером. См. раздел 14.2.5.2.

Вы можете использовать REPLACE вместо INSERT, чтобы перезаписывать старые строки. REPLACE копия INSERT IGNORE в обработке новых строк, которые содержат уникальные значения ключа, которые дублируют старые строки: новые строки используются, чтобы заменить старые строки вместо того, чтобы отказать, см. раздел 14.2.8.

tbl_name таблица, в которую должны быть вставлены строки. Столбцы, для которых запрос обеспечивает значения, могут быть определены следующим образом:

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

  • Если Вы не определяете список имен столбцов для INSERT ... VALUES или INSERT ... SELECT, значения для каждого столбца в таблице должны быть обеспечены VALUES или SELECT. Если Вы не знаете порядка столбцов в таблице, надо использовать DESCRIBE tbl_name.
  • SET указывает на имена столбцов явно.

Значения столбцов могут быть даны несколькими способами:

  • Если Вы не работаете в строгом режиме SQL, любой столбец, не явно заданный, установлен в его значение по умолчанию (явное или неявное). Например, если Вы определяете список столбца, который не называет все столбцы в таблице, неназванные столбцы установлены в их значения по умолчанию. Назначение значения по умолчанию описано в разделе 12.7. См. раздел 1.8.3.3.

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

  • Используйте ключевое слово DEFAULT, чтобы установить столбец явно в его значение по умолчанию. Это облегчает написание INSERT, которые назначают значения всем кроме нескольких столбцов, потому что это позволяет Вам избежать писать неполный список VALUES, который не включает значение для каждого столбца в таблице. Иначе, Вы должны были бы выписать список имен столбцов, соответствующих каждому значению в VALUES.

    Вы можете также использовать DEFAULT(col_name) как более общую форму, которая может использоваться в выражениях, чтобы произвести значение по умолчанию данного столбца.

  • Если и список столбца и VALUES список пуст, INSERT создает строку с каждым столбцом, установленным к его значению по умолчанию:
    INSERT INTO tbl_name () VALUES();
    
    В строгом режиме происходит ошибка, если у какого-либо столбца нет значения по умолчанию. Иначе MySQL использует неявное значение по умолчанию для любого столбца, у которого нет явно определенного значения по умолчанию.
  • Вы можете определить выражение expr, чтобы обеспечить значение столбца. Это могло бы вовлечь преобразование типа, если тип выражения не соответствует тип столбца, и преобразование данного значения может привести к различным вставленным значениям в зависимости от типа данных. Например, вставка строки '1999.0e-2' в INT, FLOAT, DECIMAL(10,6) или YEAR приводит к значениям 1999, 19.9921, 19.992100 и 1999, соответственно. Причина: значение, сохраненное в INT и YEAR 1999 это конверсия строки к целому числу только на такое большое количество начальной части строки, как может считаться допустимым целым числом или годом. Для столбцов с плавающей запятой и столбцов фиксированной точки, преобразование строки к плавающей запятой считает всю строку допустимым значением с плавающей запятой.

    expr может обратиться к любому столбцу, который был установлен ранее в списке значения. Например, Вы можете сделать это потому, что значение для col2 обращается к col1, который был ранее назначен:

    INSERT INTO tbl_name (col1,col2) VALUES(15,col1*2);
    
    Но следующее не является законным, потому что значение для col1 обращается к col2, который назначен после col1:
    INSERT INTO tbl_name (col1,col2) VALUES(col2*2,15);
    
    Одно исключение вовлекает столбцы, которые содержат AUTO_INCREMENT. Поскольку AUTO_INCREMENT произведено после других значений, любые ссылки на столбец AUTO_INCREMENT возвращают 0.

INSERT с использованием VALUES может вставить многократные строки. Чтобы сделать это, включайте многократные списки значений столбцов, каждый в пределах круглых скобок и отделенный запятыми. Пример:

INSERT INTO tbl_name (a,b,c)
       VALUES(1,2,3), (4,5,6), (7,8,9);
Список значений для каждой строки должен быть приложен в пределах круглых скобок. Следующий запрос незаконный, потому что число значений в списке не соответствует числу имен столбцов:
INSERT INTO tbl_name (a,b,c)
       VALUES(1,2,3,4,5,6,7,8,9);
VALUE синоним VALUES этом контексте. Ни один ничего не подразумевает о числе списков значений, и может использоваться, есть ли единственный список значений или многократные списки.

Число затронутых строк для INSERT может быть получено, используя ROW_COUNT() (см. раздел 13.14) или mysql_affected_rows() C API (см. раздел 25.8.7.1).

Если Вы используете INSERT ... VALUES с многократными списками значения или INSERT ... SELECT, запрос возвращает информационную строку в этом формате:

Records: 100 Duplicates: 0 Warnings: 0
Records указывает на число строк, обработанных запросом. Это не обязательно число строк, фактически вставленных, потому что Duplicates может быть отличным от нуля. Duplicates указывает на число строк, которые не могли быть вставлены, потому что они дублируют некоторые существующие уникальные индексные значения. Warnings указывает на число попыток вставить значения столбцов, которые были проблематичны в некотором роде. Предупреждения могут произойти при любом из следующих условий:

  • Вставка NULL в столбец, который был объявлен NOT NULL. Для многострочного INSERT или INSERT INTO ... SELECT столбец установлен в неявное значение по умолчанию для типа данных столбца. Это 0 для числовых типов, пустая строка ('') для строковых типов и нулевое значение для типов времени и даты. INSERT INTO ... SELECT обработаны так же, как многократные строки, потому что сервер не исследует набор результатов от SELECT, чтобы видеть, возвращает ли это единственную строку. Для единственной строки INSERT никакое предупреждение не происходит, когда NULL вставлен в столбец NOT NULL. Вместо этого запрос терпит неудачу с ошибкой.

  • Установка числового столбца к значению, которое находится вне диапазона столбца. Значение отсечено к самой близкой конечной точке диапазона.
  • Назначение такого значения, как '10.34 a' числовому столбцу. Нечисловой текст отрезан, а остающаяся числовая часть вставлена. Если у строкового значения нет никакой ведущей числовой части, столбец установлен в 0.
  • Вставка строки в строковый столбец (CHAR, VARCHAR, TEXT или BLOB), которая превышает максимальную длину столбца. Значение является усеченным к максимальной длине столбца.
  • Вставка значения, которое незаконен для типа данных, в столбец даты или времени. Столбец установлен в соответствующее нулевое значение для типа.

Если произведенный столбец вставлен явно, единственное разрешенное значение DEFAULT. См. раздел 14.1.15.5.

Если Вы используете C API, информационная строка может быть получена, вызывая mysql_info(), см. раздел 25.8.7.36.

Если INSERT вставляет строку в таблицу, которая имеет AUTO_INCREMENT, Вы можете считать значение для этого столбца при использовании SQL LAST_INSERT_ID(). Из C API используйте mysql_insert_id(). Однако, Вы должны отметить, что две функции не всегда ведут себя тождественно. Поведение INSERT относительно AUTO_INCREMENT рассмотрено в разделах 13.14 и 25.8.7.38.

INSERT поддерживает следующие модификаторы:

  • INSERT DELAYED устарел в MySQL 5.7 и намечен для возможного удаления. В MySQL 8.0 DELAYED принято, но проигнорировано. Надо использовать INSERT (без DELAYED), см. раздел 14.2.5.2.

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

    LOW_PRIORITY не должен обычно использоваться с таблицами MyISAM, потому что его выполнение отключает параллельные вставки. См. раздел 9.11.3.

    Если Вы определяете HIGH_PRIORITY, это переопределяет эффект --low-priority-updates, если сервер был запущен с этой опцией. Это также заставляет параллельные вставки не использоваться. См. раздел 9.11.3.

    LOW_PRIORITY и HIGH_PRIORITY затронут только механизмы хранения, которые используют только блокировку на уровне таблицы (MyISAM, MEMORY и MERGE).

  • Если Вы используете IGNORE, ошибки, которые происходят, выполняя INSERT проигнорированы. Например, без IGNORE строка, которая дублирует существующий индекс UNIQUE или значение PRIMARY KEY в таблице вызывает ошибку, и запрос прерван. С IGNORE от строки отказываются, и никакая ошибка не происходит. Проигнорированные ошибки производят предупреждения вместо этого.

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

    Преобразования данных, которые вызвали бы ошибки, прерывают запрос, если IGNORE не определен. С IGNORE недопустимые значения скорректированы к самым близким значениям и вставлены, предупреждения произведены, но запрос не прерывается. Вы можете определить с mysql_info() C API, сколько строк было фактически вставлено в таблицу.

  • Если Вы определяете ON DUPLICATE KEY UPDATE, и строка вставлена, которая вызвала бы дубликат значения в индексе UNIQUE или PRIMARY KEY, UPDATE из старой строки выполнен. Значение затронутых строк за строку 1, если строка вставлена как новая строка, 2, если существующая строка обновлена, и 0, если существующая строка установлена в ее текущее значение. Если Вы определяете CLIENT_FOUND_ROWS для mysql_real_connect() , соединяясь с mysqld , значение затронутых строк 1 (не 0), если существующая строка установлена в ее текущее значение. См. раздел 14.2.5.3.

Вставка в таблицу требует привилегии INSERT для таблицы. Если ON DUPLICATE KEY UPDATE используется, и дубликат ключа вызываетUPDATE вместо этого, запрос требует привилегию UPDATE для столбцов, которые будут обновлены. Для столбцов, которые считаны, но не изменены, нужна только SELECT (для столбцов в правой части col_name=expr в ON DUPLICATE KEY UPDATE).

В MySQL 8.0 INSERT, затрагивающий разделенную таблицу, используя такой механизм хранения, как MyISAM, который использует блокировки на уровне таблицы, блокирует только тот раздел, в который фактически вставлены строки. Для механизмов хранения вроде InnoDB, которые используют блокировку на уровне строки, никакая блокировка раздела не имеет места. См. Partitioning and Locking.

14.2.5.1. INSERT ... SELECT

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name,...)]
[(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE col_name=expr, ... ]
С INSERT ... SELECT Вы можете быстро вставить много строк в таблицу от одной или многих таблиц. Например:
INSERT INTO tbl_temp2 (fld_id)
       SELECT tbl_temp1.fld_order_id
       FROM tbl_temp1 WHERE tbl_temp1.fld_order_id > 100;
Следующие условия держатся для INSERT ... SELECT:

  • Определите IGNORE, чтобы проигнорировать строки, которые вызвали бы ошибки дублирования ключа.

  • Целевая таблица INSERT может появиться в FROM части SELECT запроса. Это не было возможно в некоторых более старых версиях MySQL. Однако, Вы не можете вставить в таблицу и выбрать из той же самой таблицы в подзапросе.

    Выбирая из и вставляя в таблицу в то же самое время, MySQL составляет временную таблицу, чтобы держать строки из SELECT и затем вставляет те строки в целевую таблицу. Однако, это остается истиной, что Вы не можете использовать INSERT INTO t ... SELECT ... FROM t, когда t TEMPORARY, потому что таблицы TEMPORARY не могут быть упомянуты дважды в том же самом запросе (см. раздел B.5.6.2).

  • AUTO_INCREMENT работают как обычно.
  • Чтобы гарантировать, что двоичный журнал может использоваться, чтобы обновить оригинальные таблицы, MySQL не разрешает параллельные вставки для INSERT ... SELECT (см. раздел 9.11.3).
  • Чтобы избегать неоднозначных ссылочных проблем столбца, когда SELECT и INSERT обращаются к той же самой таблице, обеспечьте уникальный псевдоним для каждой таблицы, используемой в части SELECT, и определите имена столбцов в этой части с соответствующим псевдонимом.

Вы можете явно выбрать, какой раздел или подраздел (или оба) источника или таблицы назначения (или обеих) должны использоваться с опцией PARTITION после названия таблицы. Когда PARTITION используется с названием исходной таблицы в части SELECT, строки выбраны только из раздела или подраздела, названного в его списке разделов. Когда PARTITION используется с названием целевой таблицы для части INSERT, тогда должно быть возможно вставить все строки в раздел или подраздел, названный в списке разделов после опции, иначе INSERT ... SELECT терпит неудачу. Для получения дополнительной информации и примеров см. раздел 20.5.

В части значений ON DUPLICATE KEY UPDATE Вы можете обратиться к столбцам в других таблицах, пока Вы не используете GROUP BY в части SELECT . Один побочный эффект состоит в том, что Вы должны квалифицировать групповые имена столбцов в части значений.

Порядок, в котором строки возвращены SELECT без ORDER BY не определен. Это означает, что, используя репликацию нет никакой гарантии, что такой SELECT возвращает в том же самом порядке на ведущем и ведомом устройствах, это может привести к несогласованностям между ними. Чтобы препятствовать этому, Вы должны всегда писать INSERT ... SELECT, которые должны копироваться как INSERT ... SELECT ... ORDER BY column . Выбор column не имеет значения, пока тот же самый порядок строк проведен в жизнь на ведущем и на ведомом устройствах. См. также раздел 19.4.1.17.

Из-за этой проблемы INSERT ... SELECT ON DUPLICATE KEY UPDATE и INSERT IGNORE ... SELECT отмечены как опасные для основанной на запросе репликации. С этим изменением такие запросы производят предупреждение в журнале, используя основанный на запросе режим и зарегистрированы, используя основанный на строке формат, используя режим MIXED (Bug #11758262, Bug #50439).

См. также раздел 19.2.1.1.

В MySQL 8.0 INSERT ... SELECT, который действовал на разделенные таблицы, используя такой механизм хранения, как MyISAM, который использует блокировки на уровне таблицы, блокирует все разделы целевой таблицы. Однако, только тот раздел, который фактически считан из исходной таблицы, заблокирован. Это не происходит с таблицами, используя такие механизмы хранения, как InnoDB, которые работают с блокировкой на уровне строки. См. Partitioning and Locking.

14.2.5.2. INSERT DELAYED

INSERT DELAYED ...
Опция DELAYED для INSERT в MySQL это расширение MySQL к стандартному SQL. В предыдущих версиях MySQL это может использоваться для определенных видов таблиц (таких, как MyISAM), таким образом это, когда клиент использует INSERT DELAYED, регистрируется сервером сразу, и строка стоит в очереди, чтобы быть вставленной, когда таблица не находится в использовании никаким другим потоком.

DELAYED устарела в MySQL 5.6.6. В MySQL 8.0 DELAYED не поддерживается. Сервер признает, но игнорирует DELAYED, обрабатывает вставку как неотсроченную вставку и производит предупреждение ER_WARN_LEGACY_SYNTAX_CONVERTED (INSERT DELAYED is no longer supported. The statement was converted to INSERT). DELAYED намечено для удаления в будущем выпуске.

14.2.5.3. INSERT ... ON DUPLICATE KEY UPDATE

Если Вы определяете ON DUPLICATE KEY UPDATE, и строка вставлена, которая вызвала бы дубликат значения в индексе UNIQUE или PRIMARY KEY, MySQL применит UPDATE из старой строки. Например, если столбец a объявлен как UNIQUE и содержит значение 1, следующие два запроса имеют подобный эффект:

INSERT INTO table (a,b,c) VALUES (1,2,3)
       ON DUPLICATE KEY UPDATE c=c+1;
UPDATE table SET c=c+1 WHERE a=1;
Эффекты не идентичны для таблицы InnoDB, где a столбец auto-increment. Со столбцом auto-increment INSERT увеличивает значение auto-increment, но UPDATE не делает.

ON DUPLICATE KEY UPDATE может содержать многократные назначения столбца, отделенные запятыми.

С ON DUPLICATE KEY UPDATE значение затронутых строк за строку 1, если строка вставлена как новая строка, 2, если существующая строка обновлена, и 0, если существующая строка установлена в ее текущее значение. Если Вы определяете CLIENT_FOUND_ROWS для mysql_real_connect() соединяясь с mysqld , значение затронутых строк 1 (не 0), если существующая строка установлена в ее текущее значение.

Если b также уникален, INSERT эквивалентен UPDATE:

UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;
Если a=1 OR b=2 соответствует несколько строк, только одна обновлена. Вообще, Вы должны попытаться избегать использования ON DUPLICATE KEY UPDATE на таблицах с уникальным многократным индексом.

Вы можете использовать VALUES(col_name) в UPDATE, чтобы обратиться к значениям столбцов из части INSERT запроса INSERT ... ON DUPLICATE KEY UPDATE. Другими словами, VALUES(col_name ) в ON DUPLICATE KEY UPDATE относится к значению col_name было бы вставлено, если бы не было никакой ошибки дублирования ключа. Эта функция особенно полезна при вставке многих строк. VALUES() является значащей только в INSERT ... UPDATE, иначе вернет NULL:

INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
       ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
Этот запрос идентичен следующим двум запросам:
INSERT INTO table (a,b,c) VALUES (1,2,3)
       ON DUPLICATE KEY UPDATE c=3;
INSERT INTO table (a,b,c) VALUES (4,5,6)
       ON DUPLICATE KEY UPDATE c=9;
Если таблица содержит AUTO_INCREMENT и INSERT ... ON DUPLICATE KEY UPDATE вставляет или обновляет строку, LAST_INSERT_ID() возвращает значение AUTO_INCREMENT.

DELAYED проигнорирована, когда Вы используете ON DUPLICATE KEY UPDATE.

Поскольку результаты INSERT ... SELECT зависят от упорядочивания строк из SELECT и этот порядок не может всегда гарантироваться, возможно, регистрируя INSERT ... SELECT ON DUPLICATE KEY UPDATE для ведущего и ведомого устройств получить разные результаты. Таким образом, INSERT ... SELECT ON DUPLICATE KEY UPDATE отмечены как опасные для основанной на запросе репликации. С этим изменением такие запросы производят предупреждение в журнале, используя основанный на запросе режим и зарегистрированы, используя основанный на строке формат, используя режим MIXED. Кроме того, INSERT ... ON DUPLICATE KEY UPDATE для таблицы, имеющей больше чем один уникальный или первичный ключ, также отмечен как опасный (Bug #11765650, Bug #58637), см. раздел 19.2.1.1.

В MySQL 8.0 INSERT ... ON DUPLICATE KEY UPDATE на разделенной таблице, используя механизм хранения MyISAM, который использует блокировки на уровне таблицы, блокирует любой раздел таблицы, в котором обновлен ключевой столбец раздела. Для механизмов хранения, которые используют блокировку на уровне строки, это не так. См. Partitioning and Locking.

14.2.6. LOAD DATA INFILE

LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name'
[REPLACE | IGNORE]
INTO TABLE tbl_name
[PARTITION (partition_name,...)]
[CHARACTER SET charset_name]
[{FIELDS | COLUMNS}
[TERMINATED BY 'string']
[[OPTIONALLY] ENCLOSED BY 'char']
[ESCAPED BY 'char']
]
[LINES
[STARTING BY 'string']
[TERMINATED BY 'string']
]
[IGNORE number {LINES | ROWS}]
[(col_name_or_user_var,...)]
[SET col_name = expr,...]
LOAD DATA INFILE читает строки из текстового файла в таблицу на сверхвысокой скорости. LOAD DATA INFILE дополнение SELECT ... INTO OUTFILE , см. раздел 14.2.9.1). Чтобы писать данные из таблицы в файл, надо использовать SELECT ... INTO OUTFILE. Чтобы считать файл назад в таблицу, надо использовать LOAD DATA INFILE. Синтаксис FIELDS и LINES тот же самый для обоих запросов. Оба пункта являются дополнительными, но FIELDS должен предшествовать LINES, если оба определены.

Вы можете также загрузить файлы с данными при использовании mysqlimport , это работает, посылая серверу запрос LOAD DATA INFILE. Опция --local заставляет mysqlimport читать файлы с данными из хоста клиента. Вы можете определить --compress, чтобы получить лучшую работу по медленным сетям, если клиент и сервер поддерживают сжатый протокол. См. раздел 5.5.5.

Имя файла должно быть дано как буквальная строка. На Windows определите наклонные черты влево в путях как наклонные черты вправо или удвоенные наклонные черты влево. character_set_filesystem управляет интерпретацией имени файла.

LOAD DATA поддерживает явный выбор раздел, используя PARTITION со списком разделенных запятой значений одного или более названий разделов, подразделов или обоих. Когда эта опция используется, если какие-либо строки из файла не могут быть вставлены ни в один раздел, названный в списке, запрос терпит неудачу с ошибкой Found a row not matching the given partition set. См. раздел 20.5.

Для разделенных таблиц, используя механизмы хранения, которые используют табличные блокировки, например, MyISAM, LOAD DATA не может сократить блокировки раздела. Это не относится к таблицам, использующим механизмы хранения, которые используют блокировку на уровне строки, например, InnoDB. См. Partitioning and Locking.

Сервер использует набор символов, обозначенный character_set_database, чтобы интерпретировать информацию в файле. SET NAMES и установка character_set_client не затрагивают интерпретацию ввода. Если содержание входного файла использует набор символов, который отличается от значения по умолчанию, обычно предпочтительно определить набор символов файла при использовании CHARACTER SET. Набор символов binary определяет отсутствие конвертации.

LOAD DATA INFILE интерпретирует все области в файле как наличие того же самого набора символов, независимо от типов данных столбцов, в которые загружены значения полей. Для правильной интерпретации содержания файла Вы должны гарантировать, что он был написан с правильным набором символов. Например, если Вы пишете файл с данными с mysqldump -T или через SELECT ... INTO OUTFILE в mysql , надо убедиться, что использовали опцию --default-character-set, чтобы вывод был написан в наборе символов, который будет использоваться, когда файл загружен LOAD DATA INFILE.

Невозможно загрузить файлы с данными, которые используют ucs2, utf16, utf16le или utf32.

Если Вы используете LOW_PRIORITY, выполнение LOAD DATA отсрочено, пока никакие другие клиенты не читают из таблицы. Это затрагивает только механизмы хранения, которые используют только блокировку на уровне таблицы (MyISAM, MEMORY и MERGE).

Если Вы определяете CONCURRENT с MyISAM, которая удовлетворяет условию для параллельных вставок (то есть, не содержит свободных блоков в середине), другие потоки могут получить данные от таблицы в то время, как работает LOAD DATA. Эта опция затрагивает исполнение LOAD DATA, даже если никакой другой поток не использует таблицу в то же самое время.

С основанной на строке репликацией CONCURRENT копируется независимо от версии MySQL. С основанной на запросе репликацией CONCURRENT не копируется до MySQL 5.5.1 (см. Bug #34628). См. раздел 19.4.1.18.

LOCAL затрагивает ожидаемое местоположение файла и обработку ошибок, как описано позже. LOCAL применим только если Ваш сервер и Ваш клиент оба были сконфигурированы, чтобы разрешить это. Например, если mysqld был запущен с --local-infile=0, LOCAL не работает. См. раздел 7.1.6.

LOCAL затрагивает, где файл, как ожидают, будет найден:

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

    Используя LOCAL с LOAD DATA , копия файла создается во временном каталоге сервера. Это не каталог, определенный значением tmpdir или slave_load_tmpdir , а временный каталог операционной системы, и он не конфигурируем в сервере MySQL. Как правило, временный каталог системы /tmp в Linux и C:\WINDOWS\TEMP в Windows. Нехватка достаточного пространства для копии в этом каталоге может вызвать сбой LOAD DATA LOCAL.

  • Если LOCAL не определен, файл должен быть расположен на машине сервера и считан непосредственно сервером. Сервер использует следующие правила определения местонахождения файла:

    • Если имя файла абсолютный путь, сервер использует его как дано.

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

В не-LOCAL случае эти правила означают, что файл ./myfile.txt считан из каталога данных сервера, тогда как файл myfile.txt считан из каталога базы данных по умолчанию. Например, если база данных значения по умолчанию db1, следующий запрос LOAD DATA читает файл data.txt из каталога базы данных db1, даже при том, что запрос явно загружает файл в таблицу в db2:

LOAD DATA INFILE 'data.txt' INTO TABLE db2.my_table;
Из соображений безопасности, читая текстовые файлы, расположенные на сервере, файлы должны находиться в каталоге базы данных или быть читаемыми учетной записью пользователя, используемой, чтобы выполнить сервер. Кроме того, чтобы использовать LOAD DATA INFILE на файлах сервера Вы должны иметь привилегию FILE. См. раздел 7.2.1. Для не-LOCAL, если secure_file_priv установлена в непустое имя каталога, файл, который будет загружен, должен быть расположен в том каталоге.

Использование LOCAL немного медленнее, чем разрешение серверу получить доступ к файлам непосредственно, потому что содержание файла должен послать по соединению клиент к серверу. С другой стороны, Вы не нуждаетесь в привилегии FILE, чтобы загрузить местные файлы.

LOCAL также меняет обработку ошибок:

  • С LOAD DATA INFILE интерпретация данных и ошибки дубликата ключа заканчивают работу.

  • С LOAD DATA LOCAL INFILE интерпретация данных и ошибки дубликата ключа становятся предупреждениями, и работа продолжается, потому что у сервера нет никакого способа остановить передачу файла в середине работы. Для ошибок дубликата ключа это то же самое, как будто указан IGNORE. IGNORE объяснен позже в этом разделе.

REPLACE и IGNORE управляют обработкой входных строк, которые дублируют существующие строки на уникальных значениях ключа:

  • Если указан REPLACE, входные строки заменяют существующие строки. Другими словами, строки, у которых есть то же самое значение для первичного ключа или уникального индекса как у существующей строки. См. раздел 14.2.8.

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

Чтобы проигнорировать ограничения внешнего ключа во время работы загрузки, установите SET foreign_key_checks = 0 перед LOAD DATA.

Если Вы используете LOAD DATA INFILE на пустой таблице MyISAM, все групповые индексы создаются в отдельном пакете (что касается REPAIR TABLE). Обычно это делает LOAD DATA INFILE намного быстрее, когда Вы имеете много индексов. В некоторых крайних случаях Вы можете создать индексирование еще быстрее, выключая их с ALTER TABLE ... DISABLE KEYS прежде, чем загрузить файл в таблицу и используя ALTER TABLE ... ENABLE KEYS, чтобы пересоздать индексирование после загрузки файла. См. раздел 9.2.2.1.

Для LOAD DATA INFILE и SELECT ... INTO OUTFILE синтаксис FIELDS и LINES одинаков. Оба пункта являются дополнительными, но FIELDS должен предшествовать LINES, если оба определены.

Если Вы определяете FIELDS, каждый из его подпунктов (TERMINATED BY, [OPTIONALLY] ENCLOSED BY и ESCAPED BY) является также дополнительным, за исключением того, что Вы должны определить по крайней мере один из них.

Если Вы не определяете FIELDS или LINES, значения по умолчанию те же самые, как будто Вы написали:

FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'
LINES TERMINATED BY '\n' STARTING BY ''
Наклонная черта влево это символ ESC MySQL в пределах строк в запросах SQL, чтобы определить буквальную наклонную черту влево, Вы должны определить две наклонных черты влево для значения, которое будет интерпретироваться как единственная наклонная черта влево. Escape-последовательности '\t' и '\n' определяют символы tab и newline, соответственно.

Другими словами, по умолчанию в LOAD DATA INFILE спецсимволы обработаны следующим образом, когда ввод читается:

  • Ищет границы строки в новых строках.

  • Не перескакивает ни через какие префиксы строки.
  • Разрывы строк в полях по tab.
  • Не ожидается, что области будут в пределах любых символов заключения в кавычки.
  • Интерпретируются символы, которым предшествует символ ESC \ как escape-последовательности. Например, \t, \n и \\ значат tab, newline и backslash, соответственно. См. обсуждение FIELDS ESCAPED BY позже для полного списка escape-последовательностей.

Наоборот значения по умолчанию SELECT ... INTO OUTFILE в выводе:

  • Пишет tab между областями.

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

Если Вы произвели текстовый файл на системе Windows, Вам, возможно, придется использовать LINES TERMINATED BY '\r\n', чтобы считать файл должным образом, потому что программы Windows, как правило, используют два символа в качестве разделителя строки. Некоторые программы, такие как WordPad, могли бы использовать \r как разделитель строки при записи файлов. Чтобы считать такие файлы, надо использовать LINES TERMINATED BY '\r'.

Если у всех строк, которые Вы хотите читать, есть общий префикс, который Вы хотите проигнорировать, Вы можете использовать LINES STARTING BY 'prefix_string', чтобы перескакивать через префикс и что-либо перед ним. Если строка не включает префикс, вся строка пропущена. Предположите, что Вы делаете следующий запрос:

LOAD DATA INFILE '/tmp/test.txt' INTO TABLE test
     FIELDS TERMINATED BY ','  LINES STARTING BY 'xxx';
Если файл с данными похож на это:
xxx"abc",1
something xxx"def",2
"ghi",3
Получающиеся строки будут ("abc",1) и ("def",2). Третья строка в файле пропущена, потому что это не содержит префикс.

IGNORE number LINES может использоваться, чтобы проигнорировать строки в начале файла. Например, Вы можете использовать IGNORE 1 LINES, чтобы перескакивать через начальную строку заголовка, содержащую имена столбцов:

LOAD DATA INFILE '/tmp/test.txt' INTO TABLE test IGNORE 1 LINES;
Когда Вы используете SELECT ... INTO OUTFILE c LOAD DATA INFILE, чтобы написать данные от базы данных в файл и затем считать файл назад в базу данных позже, опции для обоих запросов должны соответствовать. Иначе LOAD DATA INFILE не будет интерпретировать содержание файла должным образом. Предположите, что Вы используете SELECT ... INTO OUTFILE, чтобы написать файл с областями, разграниченными запятыми:
SELECT * INTO OUTFILE 'data.txt' FIELDS TERMINATED BY ',' FROM table2;
Чтобы считать файл разделенных запятыми значений назад, правильный запрос:
LOAD DATA INFILE 'data.txt' INTO TABLE table2
     FIELDS TERMINATED BY ',';
Если бы вместо этого Вы попытались читать файл запросом, показанным ниже, то это не работало бы, потому что это инструктирует LOAD DATA INFILE искать tab между областями:
LOAD DATA INFILE 'data.txt' INTO TABLE table2 FIELDS TERMINATED BY '\t';
Вероятный результат состоит в том, что каждая входная строка интерпретировалась бы как единственная область.

LOAD DATA INFILE может использоваться, чтобы считать файлы, полученные из внешних источников. Например, много программ могут экспортировать данные в формате отделенных запятыми значений (CSV). Если строки в таком файле закончены возвратом каретки и новой строкой, запрос, показанный здесь, иллюстрирует опции, которые Вы использовали бы, чтобы загрузить файл:

LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name
     FIELDS TERMINATED BY ',' ENCLOSED BY '"'
     LINES TERMINATED BY '\r\n' IGNORE 1 LINES;
Если входные значения не обязательно приложены в пределах кавычек, надо использовать OPTIONALLY перед ENCLOSED BY.

Любая опция может определить пустую строку (''). Если не пуста, значения FIELDS [OPTIONALLY] ENCLOSED BY и FIELDS ESCAPED BY должны быть единственным символом. FIELDS TERMINATED BY, LINES STARTING BY и LINES TERMINATED BY могут быть больше, чем одним символом. Например, чтобы написать строки, которые закончены возвратом каретки/ переводом строки или считать файл, содержащий такие строки, определяют LINES TERMINATED BY '\r\n' clause.

Считать файл, содержащий записи, которые отделены строками, состоящими из %%, можно таким запросом:

CREATE TABLE jokes (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
       joke TEXT NOT NULL);
LOAD DATA INFILE '/tmp/jokes.txt' INTO TABLE jokes
     FIELDS TERMINATED BY '' LINES TERMINATED BY '\n%%\n' (joke);
FIELDS [OPTIONALLY] ENCLOSED BY управляет цитированием полей. Для вывода (SELECT ... INTO OUTFILE ), если Вы опускаете слово OPTIONALLY, все области заключены в символ ENCLOSED BY. Пример такого вывода (использующий запятую в качестве полевого разделителя):
"1","a string","100.20"
"2","a string containing a , comma","102.20"
"3","a string containing a \" quote","102.20"
"4","a string containing a \", quote and comma","102.20"
Если указано OPTIONALLY, символ ENCLOSED BY используется только, чтобы приложить значения от столбцов, у которых есть строковый тип данных (CHAR, BINARY, TEXT или ENUM):
1,"a string",100.20
2,"a string containing a , comma",102.20
3,"a string containing a \" quote",102.20
4,"a string containing a \", quote and comma",102.20
Возникновения символа ENCLOSED BY в пределах значения поля оставляют, предварительно помечая их символом ESCAPED BY. Также отметьте, что если Вы определяете пустой ESCAPED BY, возможно неосторожно произвести вывод, который не может быть считан должным образом LOAD DATA INFILE. Например, предыдущий вывод выглядел бы следующим образом, если символ ESC пуст. Заметьте, что вторая область в четвертой строке содержит запятую после кавычки, которая ошибочно заканчивает область:
1,"a string",100.20
2,"a string containing a , comma",102.20
3,"a string containing a " quote",102.20
4,"a string containing a ", quote and comma",102.20
Для ввода символ ENCLOSED BY, если есть, отрезан от концов значений полей. Это истина, независимо от того, определен ли OPTIONALLY, OPTIONALLY не имеет никакого эффекта на входную интерпретацию. Возникновения символа ENCLOSED BY, которому предшествует символ ESCAPED BY интерпретируются как часть текущего значения поля.

Если область начинается с ENCLOSED BY, экземпляры того символа признаны завершением значения поля, только если сопровождаемы областью или строкой TERMINATED BY. Чтобы избегать двусмысленности возникновений, ENCLOSED BY в пределах значения поля может быть удвоен и интерпретируется как единственный случай символа. Например, если ENCLOSED BY '"' определен, кавычки обработаны как показано здесь:

"The ""BIG"" boss"  -> The "BIG" boss
The "BIG" boss  -> The "BIG" boss
The ""BIG"" boss-> The ""BIG"" boss
FIELDS ESCAPED BY определяет, как читать или писать специальные символы:

  • Для ввода, если FIELDS ESCAPED BY не пуст, возникновения этого символа обрезаны и следующий символ взят буквально в качестве части значения поля. Некоторые двухсимвольные последовательности, которые являются исключениями, где первый символ это символ ESC. Эти последовательности показывают в следующей таблице (использован \ для символа ESC). Правила для обработки NULL описаны позже в этом разделе.

    Символ Escape-последовательность
    \0 ASCII NUL (X'00')
    \b backspace
    \n newline (linefeed)
    \r carriage return
    \t tab
    \Z ASCII 26 (Control+Z)
    \N NULL

    Если FIELDS ESCAPED BY пуст, интерпретация escape-последовательности не происходит.

  • Для вывода, если FIELDS ESCAPED BY не пуст, он используется как префикс следующих символов:

    • FIELDS ESCAPED BY.

    • FIELDS [OPTIONALLY] ENCLOSED BY.
    • Первый символ FIELDS TERMINATED BY и LINES TERMINATED BY.
    • ASCII 0 (что фактически написано после символа ESC, ASCII 0, не нулевой байт).

    Если FIELDS ESCAPED BY пуст, никаких символов не оставляют и NULL выведен как NULL, не \N. Это, вероятно, не хорошая идея определить пустой символ ESC, особенно если значения полей в Ваших данных содержат какой-либо из символов из данного списка.

В определенных случаях взаимодействуют опции:

  • Если LINES TERMINATED BY пустая, а FIELDS TERMINATED BY непустая, строки также закончены с FIELDS TERMINATED BY.

  • Если FIELDS TERMINATED BY и FIELDS ENCLOSED BY обе пусты (''), (неразграниченный) формат фиксированной строки используется. С форматом фиксированной строки никакие разделители не используются между областями (но у Вас может все еще быть разделитель строки). Вместо этого значения столбцов считаны и написаны, используя ширину, достаточно большую, чтобы содержать все значения в области. Для TINYINT, SMALLINT, MEDIUMINT, INT и BIGINT ширина 4, 6, 8, 11 и 20, соответственно, независимо от того какова заявленная ширина отображения.

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

    Формат фиксированной строки также затрагивает обработку NULL, как описано позже.

    Формат фиксированной строки не работает, если Вы используете многобайтовый набор символов.

Обработка NULL изменяется согласно FIELDS и LINES:

  • Для значения по умолчанию FIELDS и LINES NULL написан как значение поля \N, для вывода, и значение поля \N считано как NULL для ввода (предполагается, что ESCAPED BY \).

  • Если FIELDS ENCLOSED BY не пусто, область, содержащая буквальное слово NULL считана как NULL. Это отличается от слова NULL в пределах FIELDS ENCLOSED BY , которое считано как строка 'NULL'.
  • Если FIELDS ESCAPED BY пуст, NULL написан как слово NULL.
  • С форматом фиксрованной строки (который используется, когда FIELDS TERMINATED BY и FIELDS ENCLOSED BY пусты), NULL написан как пустая строка. Это делает значения NULL и пустые строки в таблице неразличимыми, когда написаны в файл, потому что оба написаны как пустые строки. Если Вы должны быть в состоянии их отличить, когда идет чтение файла Вы не должны использовать формат фиксированной строки.

Попытка загрузить NULL в столбец NOT NULL вызывает назначение неявного значения по умолчанию для типа данных столбца и предупреждения или ошибки в строгом режиме SQL. Неявные значения по умолчанию обсуждены в раздел 12.7.

Некоторые случаи не поддержаны LOAD DATA INFILE:

  • Строки фиксированного размера (FIELDS TERMINATED BY и FIELDS ENCLOSED BY пусты) и столбцы BLOB или TEXT.

  • Если Вы определяете один разделитель, который является тем же самым как префикс другого, LOAD DATA INFILE не может интерпретировать ввод должным образом. Например, следующее FIELDS вызовет проблемы:
    FIELDS TERMINATED BY '"' ENCLOSED BY '"'
    
  • Если FIELDS ESCAPED BY пуст, значение поля, которое содержит возникновение FIELDS ENCLOSED BY или LINES TERMINATED BY, сопровождаемый FIELDS TERMINATED BY, LOAD DATA INFILE прекратит читать область или строку слишком рано. Это происходит потому, что LOAD DATA INFILE не может должным образом определить, где область или строка кончается.

Следующий пример загружает все столбцы таблицы persondata:

LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata;
По умолчанию, когда никакой список столбцов не обеспечен в конце LOAD DATA INFILE, входные строки, как ожидают, будут содержать область для каждого столбца таблицы. Если Вы хотите загрузить только некоторые из столбцов таблицы, определите список столбцов:
LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata (col1,col2,...);
Вы должны также определить список столбцов, если порядок областей во входном файле отличается от порядка столбцов в таблице. Иначе, MySQL не может сказать, как соотнести поля ввода со столбцами таблицы.

Список столбцов может содержать имена столбцов или пользовательские переменные. С пользовательскими переменными SET позволяет Вам выполнить преобразования на их значениях прежде, чем назначить результат столбцам.

Пользовательские переменные в SET могут использоваться несколькими способами. Следующий пример использует первый входной столбец непосредственно для значения t1.column1 и назначает второй входной столбец на пользовательскую переменную, которая подвергнута делению прежде, чем назначена t1.column2:

LOAD DATA INFILE 'file.txt' INTO TABLE t1 (column1, @var1)
     SET column2 = @var1/100;
SET может использоваться, чтобы поставлять значения, не сделанные во входном файле. Следующий запрос установит column3 к текущей дате и времени:
LOAD DATA INFILE 'file.txt' INTO TABLE t1 (column1, column2)
     SET column3 = CURRENT_TIMESTAMP;
Вы можете также отказаться от входного значения, назначая его на пользовательскую переменную, но не назначая переменную столбцу таблицы:
LOAD DATA INFILE 'file.txt' INTO TABLE t1
     (column1, @dummy, column2, @dummy, column3);
Использование списка столбца/переменной и SET подвергается следующим ограничениям:

  • У SET должны быть только имена столбцов на левой стороне операторов назначения.

  • Вы можете использовать подзапросы в правой стороне SET. Подзапрос, который возвращает значение, которое будет назначено на столбец, может быть только скалярным подзапросом. Кроме того, Вы не можете использовать подзапрос, чтобы выбрать из таблицы, которая загружается.
  • Строки, проигнорированные IGNORE, не обработаны для списка столбца/переменной или SET.
  • Пользовательские переменные не могут использоваться, загружая данные с форматом фиксированной строки, потому что у пользовательских переменных нет ширины отображения.

Обрабатывая входную строку, LOAD DATA разделяет ее на области и использует значения согласно списку столбца/переменной и SET, если они присутствуют. Тогда получающаяся строка вставлена в таблицу. Если есть BEFORE INSERT или AFTER INSERT триггеры для таблицы, они активированы прежде или после вставки строки, соответственно.

Если у входной строки есть слишком много областей, дополнительные области проигнорированы, и число предупреждений увеличено.

Если у входной строки есть слишком мало областей, столбцы таблицы, для которых отсутствуют поля ввода, установлены в их значения по умолчанию. Назначение значения по умолчанию описано в разделе 12.7.

Пустое значение поля интерпретируется как отличающееся от недостающей области:

  • Для строковых типов столбец установлен в пустую строку.

  • Для числовых типов столбец установлен в 0.
  • Для типов даты и времени, столбец установлен в соответствующее нулевое. См. раздел 12.3.

Это те же самые значения, которые будут результатом, если Вы назначаете пустую строку явно на строку, число или тип даты или времени явно в INSERT или UPDATE.

Обработка пустых или неправильных значений полей отличается от только что описанного, если режим SQL установлен в строгое значение. Например, если sql_mode TRADITIONAL, преобразование пустого значения или значения такого, как 'x' для числового столбца приводит к ошибке, а не преобразованию в 0. С LOCAL или IGNORE предупреждения происходят, а не ошибки, даже со строгим sql_mode, и строка вставлены, используя то же самое поведение самого близкого значения, используемое для не ограничивающих режимов SQL. Это происходит, потому что у сервера нет никакого способа остановить передачу файла в середине работы.

TIMESTAMP установлены в текущую дату и время, только если есть значение NULL для столбца (то есть, \N) и столбец не разрешает значения NULL или если значение по умолчанию столбца TIMESTAMP текущий timestamp и это опущено в полевом списке, когда полевой список определен.

LOAD DATA INFILE воспринимает весь ввод как строки, таким образом, Вы не можете использовать числовые значения для ENUM или SET, как с INSERT. Все значения ENUM и SET должны быть определены как строки.

Значения BIT не могут быть загружены, используя двоичную запись (например, b'011010'). Чтобы работать вокруг этого, определите значения как регулярные целые числа и используйте SET, чтобы преобразовать их так, чтобы MySQL выполнил числовое преобразование типа и загрузил их в столбец BIT должным образом:

shell> cat /tmp/bit_test.txt
2
127

shell> mysql test
mysql> LOAD DATA INFILE '/tmp/bit_test.txt'
    ->      INTO TABLE bit_test (@var1) SET b = CAST(@var1 AS UNSIGNED);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Deleted: 0  Skipped: 0  Warnings: 0

mysql> SELECT BIN(b+0) FROM bit_test;
+----------+
| bin(b+0) |
+----------+
| 10       |
| 1111111  |
+----------+
2 rows in set (0.00 sec)
В Unix, если LOAD DATA надо читать из канала, Вы можете использовать следующий метод (пример загружает каталог / в таблицу db1.t1):
mkfifo /mysql/data/db1/ls.dat
chmod 666 /mysql/data/db1/ls.dat
find / -ls > /mysql/data/db1/ls.dat &
mysql -e "LOAD DATA INFILE 'ls.dat' INTO TABLE t1" db1
Здесь Вы должны выполнить команду, которая производит данные, которые будут загружены и mysql на отдельных терминалах или выполнить процесс генерации данных в фоне (как показано в предыдущем примере). Если Вы не сделаете этого, то канал заблокируется, пока данные не считаны процессом mysql.

Когда LOAD DATA INFILE завершится, это возвращает информационную строку в следующем формате:

Records: 1  Deleted: 0  Skipped: 0  Warnings: 0
Предупреждения происходят при тех же самых обстоятельствах как когда значения вставлены, используя INSERT (см. раздел 14.2.5), за исключением того, что LOAD DATA INFILE также производит предупреждения, когда есть слишком мало или слишком много областей во входной строке.

Вы можете использовать SHOW WARNINGS , чтобы получить список первых max_error_count предупреждений как информацию о том, что пошло не так, как надо. См. раздел 14.7.5.40.

Если Вы используете C API, Вы можете получить информацию о запросе, вызывая mysql_info(). См. раздел 25.8.7.36.

14.2.7. LOAD XML

LOAD XML [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name'
[REPLACE | IGNORE]
INTO TABLE [db_name.]tbl_name
[CHARACTER SET charset_name]
[ROWS IDENTIFIED BY '<tagname>']
[IGNORE number {LINES | ROWS}]
[(field_name_or_user_var,...)]
[SET col_name = expr,...]
LOAD XML читает данные из XML-файла в таблицу. file_name должен быть дан как буквальная строка. tagname в дополнительном ROWS IDENTIFIED BY должен также быть дан как буквальная строка, и должен быть окружен угловыми скобками (< и >).

LOAD XML работает как дополнение выполнения mysql в режим вывода XML (то есть, запуская клиента с --xml). Чтобы написать данные от таблицы в XML-файл, Вы можете вызвать mysql с опциями --xml и -e:

shell> mysql --xml -e 'SELECT * FROM mydb.mytable' > file.xml
Чтобы считать файл назад в таблицу, надо использовать LOAD XML INFILE. По умолчанию элемент <row> является эквивалентом строки таблицы базы данных, это может быть изменено, используя ROWS IDENTIFIED BY.

Этот запрос поддерживает три различных формата XML:

  • Имена столбцов как признаки и значения столбцов как значения атрибута:

    <row column1="value1"
    column2="value2" .../>
    
  • Имена столбцов как теги и значения столбцов как контент этих тегов:
    <row>
      <column1>value1</column1>
      <column2>value2</column2>
    </row>
    
  • Имена столбцов name признаки тэгов <field>, значения как содержание этих тегов: contents of these tags:
    <row>
      <field name='column1'>value1</field>
      <field name='column2'>value2</field>
    </row>
    
    Это формат, используемый другими инструментами MySQL, такими как mysqldump.

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

Следующие пункты работают для LOAD XML по существу аналогично LOAD DATA:

  • LOW_PRIORITY или CONCURRENT

  • LOCAL
  • REPLACE или IGNORE
  • CHARACTER SET
  • SET

См. раздел 14.2.6.

(field_name_or_user_var, ...) список разделенных запятой значений одной или более областей XML или пользовательских переменных. Название пользовательской переменной, используемой с этой целью, должно соответствовать название области из XML-файла с префиксом @. Вы можете использовать имена полей, чтобы выбрать только желаемые области. Пользовательские переменные могут использоваться, чтобы сохранить соответствующие значения полей для последующего повторного использования.

IGNORE number LINES или IGNORE number ROWS пропускает первые number строк в XML-файле. Это походит на LOAD DATA IGNORE ... LINES.

Предположите, что нам назвали таблицу person, создаваемую как показано здесь:

USE test;
CREATE TABLE person (person_id INT NOT NULL PRIMARY KEY,
       fname VARCHAR(40) NULL, lname VARCHAR(40) NULL,
       created TIMESTAMP);
Предположите далее, что эта таблица первоначально пуста.

Теперь предположите, что у нас есть простой XML-файл person.xml, чье содержание показано здесь:

<list>
  <person person_id="1" fname="Kapek" lname="Sainnouine"/>
  <person person_id="2" fname="Sajon" lname="Rondela"/>
  <person person_id="3"><fname>Likame</fname><lname>ц√rrtmons</lname></person>
  <person person_id="4"><fname>Slar</fname><lname>Manlanth</lname></person>
  <person><field name="person_id">5</field><field name="fname">Stoma</field>
<field name="lname">Milu</field></person>
  <person><field name="person_id">6</field><field name="fname">Nirtam</field>
<field name="lname">Sklц╤d</field></person>
  <person person_id="7"><fname>Sungam</fname><lname>Dulbц╔d</lname></person>
  <person person_id="8" fname="Sraref" lname="Encmelt"/>
</list>
Каждый из допустимых форматов XML, обсужденных ранее, представлен в этом файле в качестве примера.

Импортировать данные из person.xml в таблицу person можно так:

mysql> LOAD XML LOCAL INFILE 'person.xml'
    ->      INTO TABLE person
    ->      ROWS IDENTIFIED BY '<person>';

Query OK, 8 rows affected (0.00 sec)
Records: 8  Deleted: 0  Skipped: 0  Warnings: 0
Здесь мы принимаем, что person.xml расположен в каталоге данных MySQL. Если файл не может быть найден, то будет ошибка:
ERROR 2 (HY000): File '/person.xml' not found (Errcode: 2)
ROWS IDENTIFIED BY '<person>' означает, что каждый элемент <person> в XML-файле считают эквивалентным строке в таблице, в которую должны быть импортированы данные. В этом случае это таблица person в базе данных test.

Как видно из ответа по серверу, 8 строк были импортированы в таблицу test.person. Это может быть проверено простым SELECT:

mysql> SELECT * FROM person;
+-----------+--------+------------+---------------------+
| person_id | fname  | lname      | created             |
+-----------+--------+------------+---------------------+
| 1         | Kapek  | Sainnouine | 2007-07-13 16:18:47 |
| 2         | Sajon  | Rondela    | 2007-07-13 16:18:47 |
| 3         | Likame | ц√rrtmons  | 2007-07-13 16:18:47 |
| 4         | Slar   | Manlanth   | 2007-07-13 16:18:47 |
| 5         | Stoma  | Nilu       | 2007-07-13 16:18:47 |
| 6         | Nirtam | Sklц╤d     | 2007-07-13 16:18:47 |
| 7         | Sungam | Dulbц╔d    | 2007-07-13 16:18:47 |
| 8         | Sreraf | Encmelt    | 2007-07-13 16:18:47 |
+-----------+--------+------------+---------------------+
8 rows in set (0.00 sec)
Это показывает, как заявлено ранее в этом разделе, что любые из 3 форматов XML могут появиться в единственном файле и быть считаны при использовании LOAD XML.

Инверсия работы импорта то есть, вывод табличных данных MySQL в XML, может быть достигнута, используя mysql:

shell> mysql --xml -e "SELECT * FROM test.person" > person-dump.xml
shell> cat person-dump.xml
<?xml version="1.0"?>

<resultset statement="SELECT * FROM test.person" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <row>
<field name="person_id">1</field>
<field name="fname">Kapek</field>
<field name="lname">Sainnouine</field>
  </row>

  <row>
<field name="person_id">2</field>
<field name="fname">Sajon</field>
<field name="lname">Rondela</field>
  </row>

  <row>
<field name="person_id">3</field>
<field name="fname">Likema</field>
<field name="lname">ц√rrtmons</field>
  </row>

  <row>
<field name="person_id">4</field>
<field name="fname">Slar</field>
<field name="lname">Manlanth</field>
  </row>

  <row>
<field name="person_id">5</field>
<field name="fname">Stoma</field>
<field name="lname">Nilu</field>
  </row>

  <row>
<field name="person_id">6</field>
<field name="fname">Nirtam</field>
<field name="lname">Sklц╤d</field>
  </row>

  <row>
<field name="person_id">7</field>
<field name="fname">Sungam</field>
<field name="lname">Dulbц╔d</field>
  </row>

  <row>
<field name="person_id">8</field>
<field name="fname">Sreraf</field>
<field name="lname">Encmelt</field>
  </row>
</resultset>

Опция --xml предписывает клиенту mysql использовать XML-формат для его вывода, опция -e заставляет клиента немедленно выполнить запрос SQL после опции. См. раздел 5.5.1.

Вы можете проверить, что дамп допустим, создавая копию person и импортируя файл дампа в новую таблицу:

mysql> USE test;
mysql> CREATE TABLE person2 LIKE person;
Query OK, 0 rows affected (0.00 sec)

mysql> LOAD XML LOCAL INFILE 'person-dump.xml' INTO TABLE person2;
Query OK, 8 rows affected (0.01 sec)
Records: 8  Deleted: 0  Skipped: 0  Warnings: 0

mysql> SELECT * FROM person2;
+-----------+--------+------------+---------------------+
| person_id | fname  | lname      | created             |
+-----------+--------+------------+---------------------+
| 1         | Kapek  | Sainnouine | 2007-07-13 16:18:47 |
| 2         | Sajon  | Rondela    | 2007-07-13 16:18:47 |
| 3         | Likema | ц√rrtmons  | 2007-07-13 16:18:47 |
| 4         | Slar   | Manlanth   | 2007-07-13 16:18:47 |
| 5         | Stoma  | Nilu       | 2007-07-13 16:18:47 |
| 6         | Nirtam | Sklц╤d     | 2007-07-13 16:18:47 |
| 7         | Sungam | Dulbц╔d    | 2007-07-13 16:18:47 |
| 8         | Sreraf | Encmelt    | 2007-07-13 16:18:47 |
+-----------+--------+------------+---------------------+
8 rows in set (0.00 sec)
Нет никакого требования что каждая область в XML-файле быть соответствующей столбцу в соответствующей таблице. Пропущены области, у которых нет никаких соответствующих столбцов. Вы можете видеть это, опустошив таблицу person2 и удалив столбец created, затем используйте тот же самый LOAD XML:
mysql> TRUNCATE person2;
Query OK, 8 rows affected (0.26 sec)

mysql> ALTER TABLE person2 DROP COLUMN created;
Query OK, 0 rows affected (0.52 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW CREATE TABLE person2\G
*************************** 1. row ***************************
   Table: person2
Create Table: CREATE TABLE `person2` (
  `person_id` int(11) NOT NULL,
  `fname` varchar(40) DEFAULT NULL,
  `lname` varchar(40) DEFAULT NULL,
  PRIMARY KEY (`person_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> LOAD XML LOCAL INFILE 'person-dump.xml' INTO TABLE person2;
Query OK, 8 rows affected (0.01 sec)
Records: 8  Deleted: 0  Skipped: 0  Warnings: 0

mysql> SELECT * FROM person2;
+-----------+--------+------------+
| person_id | fname  | lname      |
+-----------+--------+------------+
| 1         | Kapek  | Sainnouine |
| 2         | Sajon  | Rondela    |
| 3         | Likema | ц√rrtmons  |
| 4         | Slar   | Manlanth   |
| 5         | Stoma  | Nilu       |
| 6         | Nirtam | Sklц╤d     |
| 7         | Sungam | Dulbц╔d    |
| 8         | Sreraf | Encmelt    |
+-----------+--------+------------+
8 rows in set (0.00 sec)
Порядок, в котором области даны в каждой строке XML-файла, не затрагивает работу LOAD XML, полевой порядок может измениться от строки до строки, и не обязан быть в том же самом порядке, как соответствующие столбцы в таблице.

Как упомянуто ранее, Вы можете использовать список из одной или более областей XML (field_name_or_user_var, ...) (чтобы выбрать желаемые области только) или пользовательские переменные (чтобы сохранить соответствующие значения полей для более позднего использования). Пользовательские переменные могут быть особенно полезными, когда Вы хотите вставить данные из XML-файла в столбцы таблицы, имена которых не соответствуют таковым из областей XML. Чтобы видеть, как это работает, мы сначала составляем таблицу individual, которая соответствует структуре person, но столбцы называются по-другому:

mysql> CREATE TABLE individual (individual_id INT NOT NULL PRIMARY KEY,
    ->        name1 VARCHAR(40) NULL,
    ->        name2 VARCHAR(40) NULL, made TIMESTAMP);
Query OK, 0 rows affected (0.42 sec)
В этом случае Вы не можете просто загрузить XML-файл непосредственно в таблицу, потому что имена полей и имена столбцов не соответствуют:
mysql> LOAD XML INFILE '../bin/person-dump.xml' INTO TABLE test.individual;
ERROR 1263 (22004): Column set to default value; NULL supplied to
NOT NULL column 'individual_id' at row 1
Это происходит, потому что сервер MySQL ищет имена полей, соответствующие имена столбцов целевой таблицы. Вы можете работать вокруг этой проблемы, выбирая значения полей в пользовательские переменные, затем устанавливая столбцы целевой таблицы, равные значениям тех переменных, через использование SET. Вы можете выполнить обе эти операции в единственном запросе, как показано здесь:
mysql> LOAD XML INFILE '../bin/person-dump.xml'
    ->      INTO TABLE test.individual (@person_id, @fname, @lname, @created)
    ->      SET individual_id=@person_id, name1=@fname, name2=@lname, made=@created;
Query OK, 8 rows affected (0.05 sec)
Records: 8  Deleted: 0  Skipped: 0  Warnings: 0

mysql> SELECT * FROM individual;
+---------------+--------+------------+---------------------+
| individual_id | name1  | name2      | made                |
+---------------+--------+------------+---------------------+
| 1             | Kapek  | Sainnouine | 2007-07-13 16:18:47 |
| 2             | Sajon  | Rondela    | 2007-07-13 16:18:47 |
| 3             | Likema | ц√rrtmons  | 2007-07-13 16:18:47 |
| 4             | Slar   | Manlanth   | 2007-07-13 16:18:47 |
| 5             | Stoma  | Nilu       | 2007-07-13 16:18:47 |
| 6             | Nirtam | Sklц╤d     | 2007-07-13 16:18:47 |
| 7             | Sungam | Dulbц╔d    | 2007-07-13 16:18:47 |
| 8             | Srraf  | Encmelt    | 2007-07-13 16:18:47 |
+---------------+--------+------------+---------------------+
8 rows in set (0.00 sec)
Названия пользовательских переменных должны соответствовать таковым из соответствующих областей XML-файла с добавлением необходимого префикса @, чтобы указать, что это переменные. Пользовательские переменные не должны быть перечислены или назначены в том же самом порядке в качестве соответствующих областей.

Используя ROWS IDENTIFIED BY '<tagname >' возможно импортировать данные из того же самого XML-файла в таблицы базы данных с различными определениями. Для этого примера, предположите, что Вам назвали файл address.xml, который содержит следующий XML:

<?xml version="1.0"?>

<list>
  <person person_id="1">
<fname>Robert</fname>
<lname>Jones</lname>
<address address_id="1" street="Mill Creek Road" zip="45365" city="Sidney"/>
<address address_id="2" street="Main Street" zip="28681" city="Taylorsville"/>
  </person>

  <person person_id="2">
<fname>Mary</fname>
<lname>Smith</lname>
<address address_id="3" street="River Road" zip="80239" city="Denver"/>
<!-- <address address_id="4" street="North Street" zip="37920" city="Knoxville"/> -->
  </person>

</list>
Вы можете снова использовать таблицу test.person как определено ранее в этом разделе, после очистки всех существующих записей из таблицы и затем показа ее структуры как показано здесь:
mysql< TRUNCATE person;
Query OK, 0 rows affected (0.04 sec)

mysql< SHOW CREATE TABLE person\G
*************************** 1. row ***************************
   Table: person
Create Table: CREATE TABLE `person` (
  `person_id` int(11) NOT NULL,
  `fname` varchar(40) DEFAULT NULL,
  `lname` varchar(40) DEFAULT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`person_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
Теперь создайте таблицу address в базе данных test, используя следующий запрос CREATE TABLE :
CREATE TABLE address (address_id INT NOT NULL PRIMARY KEY,
       person_id INT NULL, street VARCHAR(40) NULL,
       zip INT NULL, city VARCHAR(40) NULL, created TIMESTAMP);
Чтобы импортировать данные из XML-файла в person, выполните следующий запрос LOAD XML , который определяет, что строки должны быть определены элементом <person>;
mysql> LOAD XML LOCAL INFILE 'address.xml'
    ->      INTO TABLE person
    ->      ROWS IDENTIFIED BY '<person>';
Query OK, 2 rows affected (0.00 sec)
Records: 2  Deleted: 0  Skipped: 0  Warnings: 0
Вы можете проверить, что записи были импортированы, используя SELECT:
mysql> SELECT * FROM person;
+-----------+--------+-------+---------------------+
| person_id | fname  | lname | created             |
+-----------+--------+-------+---------------------+
| 1         | Robert | Jones | 2007-07-24 17:37:06 |
| 2         | Mary   | Smith | 2007-07-24 17:37:06 |
+-----------+--------+-------+---------------------+
2 rows in set (0.00 sec)
Начиная с <address> у элементов в XML-файле нет никаких соответствующих столбцов в person, они пропущены.

Чтобы импортировать данные из элементов <address> в таблицу address, используйте LOAD XML так:

mysql> LOAD XML LOCAL INFILE 'address.xml'
    ->      INTO TABLE address
    ->      ROWS IDENTIFIED BY '<address>';
Query OK, 3 rows affected (0.00 sec)
Records: 3  Deleted: 0  Skipped: 0  Warnings: 0
Вы можете видеть, что данные были импортированы, используя такой запрос SELECT, как этот:
mysql> SELECT * FROM address;
+------------+-----------+-----------------+-------+--------------+---------------------+
| address_id | person_id | street          | zip   | city         | created             |
+------------+-----------+-----------------+-------+--------------+---------------------+
|  1         | 1         | Mill Creek Road | 45365 | Sidney       | 2007-07-24 17:37:37 |
|  2         | 1         | Main Street     | 28681 | Taylorsville | 2007-07-24 17:37:37 |
|  3         | 2         | River Road      | 80239 | Denver       | 2007-07-24 17:37:37 |
+------------+-----------+-----------------+-------+--------------+---------------------+
3 rows in set (0.00 sec)
Данные из элемента <address>, который приложен в XML-комментариях, не импортированы. Однако, начиная со столбца person_id в таблице address, значение person_id от родительского элемента <person> для каждого <address> импортировано в таблицу address.

Соображения безопасности. Как с LOAD DATA, передача XML-файла от хоста клиента до узла сервера начата сервером MySQL. В теории исправленный сервер мог быть создан, который скажет программе клиента передавать файл, выбранный сервером, а не файл, названный клиентом в LOAD XML. Такой сервер мог получить доступ к любому файлу на хосте клиента, к которому пользователь клиента имеет доступ.

В Web клиенты обычно соединяются с MySQL от веб-сервера. Пользователь, который может выполнить любую команду сервера MySQL, может использовать LOAD XML LOCAL, чтобы читать любые файлы, к которым процесс веб-сервера имеет доступ. В этой окружающей среде клиент относительно сервера MySQL фактически веб-сервер, а не удаленная программа, выполняемая пользователем, который соединяется с веб-сервером.

Вы можете отключить загрузку XML-файлов от клиентов, запуская сервер с опциецй --local-infile=0 или --local-infile=OFF. Эта опция может также использоваться, запуская mysql, чтобы выключить LOAD XML для этого сеанса клиента.

Чтобы препятствовать тому, чтобы клиент загрузил XML-файлы из сервера, не предоставляйте привилегию FILE соответствующей учетной записи пользователя MySQL или отмените эту привилегию, если у учетной записи пользователя клиента она уже есть.

Отмена привилегии FILE (или не предоставление этого) не даст пользователю выполнять только LOAD XML INFILE (так же как LOAD_FILE() ), это не препятствует тому, чтобы пользователь выполнил LOAD XML LOCAL INFILE. Чтобы отвергнуть этот запрос, Вы должны запустить сервер или клиента с опцией --local-infile=OFF.

Другими словами, привилегия FILE затрагивает только, может ли клиент читать файлы на сервере, у этого нет никакого действия, может ли клиент считать файлы в местной файловой системе.

Для разделенных таблиц, используя механизмы хранения, которые используют табличные блокировки, например, MyISAM, любые блокировки, вызванные LOAD XML, блокируют все разделы таблицы. Это не относится к таблицам, использующим механизмы хранения, которые используют блокировку на уровне строки, например, InnoDB. См. Partitioning and Locking.

14.2.8. REPLACE

REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name
[PARTITION (partition_name,...)]
[(col_name,...)]
{VALUES | VALUE} ({expr | DEFAULT},...),(...),...
Или:
REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name
[PARTITION (partition_name,...)]
SET col_name={expr | DEFAULT}, ...
Или:
REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name
[PARTITION (partition_name,...)]
[(col_name,...)]
SELECT ...
REPLACE работает точно как INSERT, за исключением того, что, если у старой строки в таблице есть то же самое значение, как новая строка для PRIMARY KEY или индекса UNIQUE, старая строка удалена прежде, чем новая строка вставлена. См. раздел 14.2.5.

REPLACE это расширение MySQL к стандарту SQL. Это вставляет или удаляет и вставляет. Для другого расширения MySQL к стандарту SQL, которое вставляет или обноввляет, см. раздел 14.2.5.3.

DELAYED вставки и замены устарели в MySQL 5.6.6. В MySQL 8.0 DELAYED не работает. Сервер признает, но игнорирует DELAYED, обрабатывает замену как неотсроченную замену, и производит предупреждение ER_WARN_LEGACY_SYNTAX_CONVERTED (REPLACE DELAYED is no longer supported. The statement was converted to REPLACE). DELAYED будет удалено в будущем выпуске.

REPLACE имеет смысл, только если у таблицы есть PRIMARY KEY или индекс UNIQUE. Иначе это становится эквивалентным INSERT, потому что нет индекса, чтобы определить, дублирует ли новая строка другую.

Значения для всех столбцов взяты от значений, определенных в REPLACE. Любые недостающие столбцы установлены в их значения по умолчанию, как это происходит для INSERT. Вы не можете обратиться к значениям от текущей строки и использовать их в новой строке. Если Вы используете такое назначение, как SET col_name = col_name+1 , ссылка на имя столбца на правой стороне обработана как DEFAULT(col_name ), таким образом, назначение эквивалентно SET col_name = DEFAULT(col_name) + 1.

Если произведенный столбец заменен явно, единственное разрешенное значение DEFAULT. Для информации о произведенных столбцах см. раздел 14.1.15.5.

Чтобы использовать REPLACE, у Вас должны быть обе привилегии INSERT и DELETE для таблицы.

REPLACE поддерживает явный выбор раздела, используя PARTITION со списком разделенных запятой значений названий разделов, подразделов или обоих. Как с INSERT , если не возможно вставить новую строку в какой-либо раздел или подраздел, REPLACE терпит неудачу с ошибкой Found a row not matching the given partition set. См. раздел 20.5.

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

Количество затронутых строк облегчает определение того, что REPLACE только добавил строку или заменял также какие-либо строки: проверьте, является ли счетчик 1 (добавил) или больше (заменил).

Если Вы используете C API, количество затронутых строк может быть получено, используя mysql_affected_rows().

Вы не можете заменять в таблице и выбрать из той же самой таблицы в подзапросе.

MySQL использует следующий алгоритм для REPLACELOAD DATA ... REPLACE):

  1. Попытайтесь вставить новую строку в таблицу.

  2. В то время как вставка терпит неудачу, потому что происходит ошибка дублирования ключа для первичного ключа или уникального индекса:

    1. Удалите из таблицы противоречивую строку, у которой есть дублирующее значение ключа.

    2. Попробуйте еще раз вставлять новую строку в таблицу.

Возможно, что в случае ключевой ошибки, механизм хранения может обработать REPLACE как обновление, а не удаление плюс вставка, но семантика та же самая. Нет никаких видимых пользователем эффектов, кроме возможной разницы в том, как механизм хранения постепенно увеличивает переменную Handler_xxx.

Поскольку результаты REPLACE ... SELECT зависят от упорядочивания строк из SELECT , и этот порядок не может всегда гарантироваться, возможно, регистрируя эти запросы для ведущего и ведомого устройств получить разный порядок. Поэтому REPLACE ... SELECT отмечены как опасный для основанной на запросе репликации. С этим изменением такие запросы производят предупреждение в журнале, используя двоичной режим журналирования STATEMENT и зарегистрированы, используя основанный на строке формат, используя режим MIXED. См. раздел 19.2.1.1.

Изменяя существующую таблицу, которая не разделена, чтобы добавить разделение или изменяя разделение уже разделенной таблицы, Вы можете рассмотреть изменение первичного ключа таблицы (см. раздел 20.6.1). Вы должны знать что, если Вы делаете это, результаты REPLACE могут быть затронуты, как если бы Вы изменили первичный ключ неразделенной таблицы. Считайте таблицу создаваемой следующим запросом CREATE TABLE:

CREATE TABLE test (id INT UNSIGNED NOT NULL AUTO_INCREMENT,
       data VARCHAR(64) DEFAULT NULL,
       ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON
       UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id));
Когда мы составляем эту таблицу и выполняем запросы, показанные в клиенте mysql, результаты следующие:
mysql> REPLACE INTO test VALUES (1, 'Old', '2014-08-20 18:47:00');
Query OK, 1 row affected (0.04 sec)

mysql> REPLACE INTO test VALUES (1, 'New', '2014-08-20 18:47:42');
Query OK, 2 rows affected (0.04 sec)

mysql> SELECT * FROM test;
+----+------+---------------------+
| id | data | ts                  |
+----+------+---------------------+
|  1 | New  | 2014-08-20 18:47:42 |
+----+------+---------------------+
1 row in set (0.00 sec)
Теперь мы составляем вторую таблицу, почти идентичную первой , за исключением того, что первичный ключ теперь покрывает 2 столбца, как показано здесь (подчеркнутый текст):
CREATE TABLE test2 (id INT UNSIGNED NOT NULL AUTO_INCREMENT,
       data VARCHAR(64) DEFAULT NULL,
       ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON
       UPDATE CURRENT_TIMESTAMP,
       PRIMARY KEY (id, ts));
Когда мы работаем с test2, те же самые два REPLACE, как мы сделали на оригинальной таблице test, дают различный результат:
mysql> REPLACE INTO test2 VALUES (1, 'Old', '2014-08-20 18:47:00');
Query OK, 1 row affected (0.05 sec)

mysql> REPLACE INTO test2 VALUES (1, 'New', '2014-08-20 18:47:42');
Query OK, 1 row affected (0.06 sec)

mysql> SELECT * FROM test2;
+----+------+---------------------+
| id | data | ts                  |
+----+------+---------------------+
|  1 | Old  | 2014-08-20 18:47:00 |
|  1 | New  | 2014-08-20 18:47:42 |
+----+------+---------------------+
2 rows in set (0.00 sec)
Это потому, что значения столбцов id и ts должны соответствовать таковым из существующей строки для строки, которая будет заменена, иначе строка вставлена.

В MySQL 8.0 REPLACE, затрагивающий разделенную таблицу, используя механизм хранения подобный MyISAM, блокирует на уровне таблицы только раздел, содержащий строки, которые соответствуют параметру WHERE в REPLACE, пока ни один из столбцов раздела таблицы не обновлен, иначе вся таблица заблокирована. Для механизмов хранения вроде InnoDB с блокировкой на уровне строки, никакой блокировки раздела нет. См. Partitioning and Locking.

14.2.9. SELECT

SELECT
[ALL | DISTINCT | DISTINCTROW ]
  [HIGH_PRIORITY]
  [MAX_STATEMENT_TIME = N]
  [STRAIGHT_JOIN]
  [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
  [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
select_expr [, select_expr ...]
[FROM table_references
  [PARTITION partition_list]
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
  [ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
  [ASC | DESC], ...]
[LIMIT {[offset,] row_count |
         row_count OFFSET offset}]
[PROCEDURE procedure_name(argument_list)]
[INTO OUTFILE 'file_name'
[CHARACTER SET charset_name]
export_options
  | INTO DUMPFILE 'file_name'
  | INTO var_name [, var_name]]
[FOR UPDATE | LOCK IN SHARE MODE]]
SELECT используется, чтобы получить строки, выбранные из одной или более таблиц, и может включать UNION и подзапросы. См. разделы 14.2.9.3 и 14.2.10.

Обычно используемые параметры SELECT:

  • Каждый select_expr указывает на столбец, который Вы хотите получить. Должен быть по крайней мере один select_expr.

  • table_references указывает на таблицу или таблицы, из которых нужно получить строки. Его синтаксис описан в разделе 14.2.9.2.
  • SELECT поддерживает явный выбор раздела, используя PARTITION со списком разделов или подраздов (или обоих) после названия таблицы в table_reference (см. раздел 14.2.9.2). В этом случае строки выбраны только из перечисленного раздела, и любой другой раздел таблицы проигнорирован. Для получения дополнительной информации и примеров см. раздел 20.5.

    SELECT ... PARTITION от таблиц, используя механизмы хранения вроде MyISAM, который выполняет блокировки на уровне таблицы (и таким образом блокировки разделов), блокирует только разделы или подразделы, названные в опции PARTITION.

    См. Partitioning and Locking.

  • WHERE, если есть, указывает на условие или условия, которым строки должны удовлетворять, чтобы быть выбранными. where_condition выражение, которое оценивается к истине для каждой строки, которая будет выбрана. Запрос выбирает все строки, если нет WHERE.

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

SELECT может также использоваться, чтобы получить строки, вычисленные независимо от любой таблицы.

Например:

mysql> SELECT 1 + 1;
    -> 2
Вам разрешают определить DUAL как фиктивное имя таблицы в ситуациях, где ни на какие таблицы не ссылаются:
mysql> SELECT 1 + 1 FROM DUAL;
    -> 2
DUAL просто для удобства людей, которые требуют, что все запросы SELECT должны иметь FROM и, возможно, другие параметры. MySQL может проигнорировать параметры. MySQL не требует FROM DUAL, если ни на какие таблицы не ссылаются.

Вообще, используемые пункты должны быть поданы точно в порядке, показанном в описании синтаксиса. Например, HAVING должен быть после любого GROUP BY и перед любым ORDER BY. Исключение то, что INTO может появиться как показано в описании синтаксиса или немедленно после списка select_expr. См. раздел 14.2.9.1.

Список select_expr включают избранный список, который указывает, которые столбцы получить. Это определяет столбец или выражение или может использовать *-сокращения:

  • Список, состоящий только из * может использоваться, чтобы выбрать все столбцы из всех таблиц:

    SELECT * FROM t1 INNER JOIN t2 ...
    
  • tbl_name.* может использоваться, чтобы выбрать все столбцы из названной таблицы:
    SELECT t1.*, t2.* FROM t1 INNER JOIN t2 ...
    
  • Использование * с другими элементами в избранном списке может произвести ошибку разбора. Чтобы избежать этой проблемы, используйте tbl_name.*:
    SELECT AVG(score), t1.* FROM t1 ...
    

Следующий список обеспечивает дополнительную информацию о других параметрах SELECT:

  • select_expr может быть дан использованием псевдонима AS alias_name. Псевдоним используется в качестве имени столбца выражения и может использоваться в GROUP BY, ORDER BY или HAVING:

    SELECT CONCAT(last_name,', ',first_name) AS full_name
           FROM mytable ORDER BY full_name;
    
    AS является дополнительным, когда совмещение имен select_expr с идентификатором. Предыдущий пример может быть написан так:
    SELECT CONCAT(last_name,', ',first_name) full_name
           FROM mytable ORDER BY full_name;
    
    Однако, потому что AS является дополнительным, тонкая проблема может произойти, если Вы забываете запятую между двумя select_expr: MySQL интерпретирует второе как имя псевдонима. Например, в следующем запросе, columnb обработан как имя псевдонима:
    SELECT columna columnb FROM mytable;
    
    Поэтому хорошая практика иметь привычку использовать AS явно, определяя псевдонимы столбца.

    Недопустимо обратиться к псевдониму столбца в WHERE, потому что значение столбца еще не могло бы быть определено, когда WHERE выполнен, см. раздел B.5.4.4.

  • FROM table_references указывает на таблицу или таблицы, из которых можно получить строки. Если Вы называете больше, чем одну таблицу, Вы выполняете соединение. Для информации о синтаксисе соединения см. раздел 14.2.9.2. Для каждой определенной таблицы Вы можете произвольно определить псевдоним.
    tbl_name [[AS] alias] [index_hint]
    

    Использование индексной подсказки предоставляет оптимизатору информацию о том, как выбрать индекс во время обработки запроса. Для описания синтаксиса, чтобы определить эти подсказки см. раздел 9.9.4.

    Вы можете использовать SET max_seeks_for_key=value как альтернативный способ вынудить MySQL предпочесть просмотр ключей вместо сканирования таблицы. См. раздел 6.1.5.

  • Вы можете обратиться к таблице в пределах базы данных по умолчанию как tbl_name или как db_name.tbl_name, чтобы определить базу данных явно. Вы можете обратиться к столбцу как col_name, tbl_name.col_name или db_name.tbl_name. col_name. Вы не должны определить префикс tbl_name или db_name. tbl_name для ссылки на столбец, если ссылка не была бы неоднозначна. См. раздел 10.2.1.
  • Табличная ссылка может быть псевдонимом с использованием tbl_name AS alias_name или tbl_name alias_name:
    SELECT t1.name, t2.salary FROM employee AS t1, info AS t2
           WHERE t1.name = t2.name;
    SELECT t1.name, t2.salary FROM employee t1, info t2
           WHERE t1.name = t2.name;
    
  • Столбцы, выбранные для вывода, могут быть упомянуты в ORDER BY и GROUP BY, используя имена столбцов, псевдонимы столбца или позиции столбца. Позиции столбца это целые числа и начинаются с 1:
    SELECT college, region, seed FROM tournament ORDER BY region, seed;
    SELECT college, region AS r, seed AS s FROM tournament ORDER BY r, s;
    SELECT college, region, seed FROM tournament ORDER BY 2, 3;
    
    Чтобы сортировать в обратном порядке, добавьте DESC к названию столбца в ORDER BY, которым Вы сортируете. Значение по умолчанию: порядок по возрастанию, это может быть определено явно, используя ASC.

    Если ORDER BY происходит в пределах подзапроса и также применен во внешнем запросе, наиболее удаленный ORDER BY имеет приоритет. Например, результаты следующего запроса отсортированы в порядке убывания, а не по возрастанию:

    (SELECT ... ORDER BY a) ORDER BY a DESC;
    
    Использование позиций столбца устарело, потому что синтаксис был удален из стандарта SQL.
  • Если Вы используете GROUP BY, выходные строки сортированы согласно GROUP BY, как будто Вы имели ORDER BY для тех же самых столбцов. Чтобы избегать повторной сортировки этого GROUP BY, добавьте ORDER BY NULL:
    SELECT a, COUNT(b) FROM test_table GROUP BY a ORDER BY NULL;
    
    Доверие неявному GROUP BY в MySQL 8.0 устарело. Чтобы достигнуть определенного порядка сортировки сгруппированных результатов, предпочтительно использовать явное ORDER BY. Сортировка GROUP BY это расширение MySQL, которое может измениться в будущем выпуске, например, чтобы позволить оптимизатору упорядочить группировки в любой манере, которую он считает самой эффективной и избегать издержек сортировки.
  • MySQL расширяет GROUP BY так, чтобы Вы могли также определить ASC и DESC после того, как назвали столбцы:
    SELECT a, COUNT(b) FROM test_table GROUP BY a DESC;
    
  • MySQL расширяет использование GROUP BY, чтобы разрешить выбирать области, которые не упомянуты в GROUP BY. Если Вы не получаете результаты, которые Вы ожидаете от своего запроса, читайте описание GROUP BY разделе 13.19.
  • GROUP BY позволяет модификатор WITH ROLLUP. См. раздел 13.19.2.
  • HAVING применен почти последним, непосредственно перед тем, как элементы посылают клиенту, без оптимизации. LIMIT применен после HAVING.

    SQL требует, что HAVING должен сослаться только на столбцы в GROUP BY или столбцы, которые используются в совокупных функциях. Однако, MySQL поддерживает расширение к этому поведению и разрешает HAVING обратиться к столбцам в SELECT и столбцам во внешних подзапросах также.

    Если HAVING относится к столбцу, который неоднозначен, предупреждение происходит. В следующем запросе col2 неоднозначно, потому что это используется в качестве псевдонима и в качестве имени столбца:

    SELECT COUNT(col1) AS col2 FROM t GROUP BY col2 HAVING col2 = 2;
    
    Предпочтение отдано стандартному поведению SQL, так если имя столбца HAVING используется в GROUP BY и как псевдоним столбца в выходном списке столбца, предпочтение отдано столбцу в GROUP BY.
  • Не надо использовать HAVING для элементов, которые должны быть в WHERE. Например, не пишите следующее:
    SELECT col_name FROM tbl_name
           HAVING col_name > 0;
    
    Пишите это так:
    SELECT col_name FROM tbl_name
           WHERE col_name > 0;
    
  • HAVING может отнестись к совокупным функциям, которые WHERE не может:
    SELECT user, MAX(salary) FROM users GROUP BY user HAVING MAX(salary) > 10;
    
    Это не работало в некоторых более старых версиях MySQL.
  • MySQL разрешает дублировать имена столбцов. Таким образом, может быть больше, чем один select_expr с тем же самым именем. Это расширение к стандартному SQL. Поскольку MySQL также разрешает GROUP BY и HAVING обратиться к select_expr, это может привести к двусмысленности:
    SELECT 12 AS a, a FROM t GROUP BY a;
    
    В этом запросе у обоих столбцов есть имя a. Чтобы гарантировать, что правильный столбец используется для того, чтобы сгруппировать, используйте различные имена для каждого select_expr.
  • MySQL разрешает неквалифицированный столбец или ссылки псевдонима в ORDER BY ища в select_expr, затем в столбцах таблиц в FROM. Для GROUP BY или HAVING это ищет FROM прежде, чем искать в select_expr. Для GROUP BY и HAVING это отличается от pre-MySQL 5.0, которые использовали те же самые правила, что касаются ORDER BY.
  • LIMIT может использоваться, чтобы ограничить число строк, возвращенных SELECT. LIMIT берет один или два числовых параметра, которые должны оба быть неотрицательными константами целого числа, с этими исключениями:

    • В пределах готовых запросов LIMIT параметры могут быть определены, используя маркеры заполнителя ?.

    • В пределах сохраненных программ LIMIT параметры могут быть определены, используя оцененные к целому числу обычные параметры или местные переменные.

    С двумя параметрами первый параметр определяет смещение первой строки, чтобы возвратить, второе определяет максимальное количество строк, чтобы возвратить. Смещение начальной строки 0 (не 1):

    SELECT * FROM tbl LIMIT 5,10;  # Вернет строки 6-15
    
    Чтобы получить все строки от определенного смещения до конца набора результатов, Вы можете использовать некоторое большое количество для второго параметра. Это запрос получает все строки от 96-ой строки до последней:
    SELECT * FROM tbl LIMIT 95,18446744073709551615;
    
    С одним параметром значение определяет число строк, чтобы возвратить с начала набора результатов:
    SELECT * FROM tbl LIMIT 5; # Вернет первые 5 строк
    
    Другими словами, LIMIT row_count эквивалентно LIMIT 0, row_count.

    Для готовых запросов Вы можете использовать заполнители. Следующие запросы возвратят одну строку из tbl:

    SET @a=1;
    PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?';
    EXECUTE STMT USING @a;
    
    Следующие запросы возвратят строки 2-6 из tbl:
    SET @skip=1; SET @numrows=5;
    PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?, ?';
    EXECUTE STMT USING @skip, @numrows;
    
    Для совместимости с PostgreSQL MySQL также поддерживает синтаксис LIMIT row_count OFFSET offset.

    Если LIMIT происходит в пределах подзапроса и также применен во внешнем запросе, наиболее удаленный LIMIT имеет приоритет. Например, следующий запрос производит две строки, не одну:

    (SELECT ... LIMIT 1) LIMIT 2;
    
  • PROCEDURE вызывает процедуру, которая должна обработать данные в наборе результатов. Для примера см. раздел 9.4.2.4, который описывает ANALYSE, процедуру, которая может использоваться, чтобы получить предложения для оптимальных типов данных столбца, которые могут помочь уменьшить табличные размеры.

    PROCEDURE не разрешен в UNION.

  • SELECT ... INTO позволяет результату запроса быть записанным в файл или сохранится в переменных. Для получения дополнительной информации см. раздел 14.2.9.1.
  • Если Вы используете FOR UPDATE с механизмом хранения, который использует блокировку страницы или строки, строки, исследованные запросом, блокированы на запись до конца текущей транзакции. Использование LOCK IN SHARE MODE устанавливает совместно используемую блокировку, которая разрешает другим транзакциям читать исследованные строки, но не обновлять или удалять их. См. раздел 16.5.2.4.

    Кроме того, Вы не можете использовать FOR UPDATE как часть SELECT в таком запросе, как CREATE TABLE new_table SELECT ... FROM old_table .... Если Вы пытаетесь сделать так, запрос отклонен с ошибкой Can't update table 'old_table' while 'new_table' is being created. Это изменение в поведении MySQL 5.5 и ранее, который разрешал CREATE TABLE ... SELECT , чтобы произвести изменения в таблицах кроме составленной таблицы.

После SELECT Вы можете использовать много опций, которые затрагивают работу запроса. HIGH_PRIORITY, MAX_STATEMENT_TIME, STRAIGHT_JOIN и опции SQL_ это расширения MySQL к стандартному SQL.

  • ALL и DISTINCT определяют, должны ли дублирующиеся строки быть возвращены. ALL (значение по умолчанию), определяет, что все строки соответствия должны быть возвращены, включая дубликаты. DISTINCT определяет удаление дублирующихся строк из набора результатов. Ошибка определить обе опции. DISTINCTROW синоним для DISTINCT.

  • HIGH_PRIORITY дает SELECT более высокий приоритет, чем запросу, который обновляет таблицу. Вы должны использовать это только для запросов, которые очень быстры и должны быть сделаны сразу. SELECT HIGH_PRIORITY блокирует таблицу для чтения, даже если есть запрос обновления, ждущий таблицу. Это затрагивает только механизмы хранения, которые используют только блокировку на уровне таблицы (MyISAM, MEMORY и MERGE).

    HIGH_PRIORITY не может использоваться с SELECT, которые являются частью UNION.

  • STRAIGHT_JOIN вынуждает оптимизатор присоединять таблицы в порядке, в котором они перечислены в FROM. Вы можете использовать это, чтобы ускорить запрос, если оптимизатор присоединяет таблицы в неоптимальном порядке. STRAIGHT_JOIN также может использоваться в table_references. См. раздел 14.2.9.2.

    STRAIGHT_JOIN не относится ни к какой таблице, которую оптимизатор обрабатывает как const или system . Такая таблица производит единственную строку, считанную во время фазы оптимизации выполнения запроса, и ссылки на ее столбцы заменены соответствующими значениями столбцов прежде, чем выполнение запроса продолжится. Эти таблицы будут казаться первыми в плане запроса, выведенном на экран EXPLAIN. См. раздел 9.8.1. Это исключение, возможно, не относится к таблицам const или system, которые используются на NULL-стороне внешнего соединения (то есть, таблица правой стороны в LEFT JOIN или таблица левой стороны в RIGHT JOIN.

  • SQL_BIG_RESULT или SQL_SMALL_RESULT может использоваться с GROUP BY или DISTINCT, чтобы сказать оптимизатору, что набор результатов имеет много строк или является небольшим, соответственно. Для SQL_BIG_RESULT MySQL непосредственно использует основанные на диске временные таблицы, если нужно, и предпочитает сортировать с использованием временной таблицы с ключом элементы GROUP BY. Для SQL_SMALL_RESULT MySQL использует быстрые временные таблицы, чтобы сохранить получающуюся таблицу вместо того, чтобы использовать сортировку. Это не должно обычно быть необходимо.
  • SQL_BUFFER_RESULT вынуждает результат быть помещенным во временную таблицу. Это помогает MySQL освободить табличные блокировки рано и помогает в случаях, где требуется много времени, чтобы послать набор результатов клиенту. Эта опция может использоваться только для верхнего уровня SELECT, не для подзапросов или после UNION.
  • SQL_CALC_FOUND_ROWS говорит MySQL вычислять сколько строк было бы в наборе результатов, игнорируя любой LIMIT. Число строк может тогда быть получено с SELECT FOUND_ROWS(). См. раздел 13.14.
  • SQL_CACHE и SQL_NO_CACHE влияют на кэширование результатов запроса в кэше запроса (см. раздел 9.10.3). SQL_CACHE говорит MySQL хранить результат в кэше запроса, если это кэшируемо и значение query_cache_type 2 или DEMAND. С SQL_NO_CACHE сервер не использует кэш запроса. Это не проверяет кэш запроса, чтобы видеть, кэшировал ли результат уже, и при этом не кэширует результат запроса.

    Эти две опции являются взаимоисключающими, и ошибка происходит, если они обе определены. Кроме того, эти опции не разрешены в подзапросах (включая подзапросы в FROM), и SELECT в объединениях кроме первого SELECT.

    Для представлений SQL_NO_CACHE применяется, если это появляется в каком-либо SELECT в запросе. Для кэшируемого запроса SQL_CACHE применяется, если это появляется в первом SELECT из представления, упомянутого запросом.

В MySQL 8.0 SELECT из разделенной таблицы, используя такой механизм хранения, как MyISAM, блокируется только раздел, содержащий строки, которые соответствуют параметру WHERE в SELECT. Это не происходит с механизмами хранения вроде InnoDB, которые используют блокировку на уровне строки. См. Partitioning and Locking.

14.2.9.1. SELECT ... INTO

SELECT ... INTO позволяет результату запроса быть сохраненным в переменных или файле:

  • SELECT ... INTO var_list выбирает значения столбцов и хранит их в переменных.

  • SELECT ... INTO OUTFILE пишет выбранные строки в файл. Столбец и разделители строки могут быть определены, чтобы произвести определенный выходной формат.
  • SELECT ... INTO DUMPFILE пишет единственную строку в файл без форматирования.

SELECT (см. раздел 14.2.9) показывает INTO около конца запроса. Также возможно использовать INTO немедленно после select_expr.

INTO не должен использоваться во вложенном SELECT потому что такой SELECT должен возвратить его результат к внешнему контексту.

INTO может назвать список из одной или более переменных, которые могут быть определяемыми пользователем переменными, параметрами хранимой процедуры или функции или местными переменными сохраненной программы. В пределах готового SELECT ... INTO OUTFILE только определяемые пользователем переменные разрешены, см. раздел 14.6.4.2.

Выбранные значения назначены на переменные. Число переменных должно соответствовать числу столбцов. Запрос должен возвратить единственную строку. Если запрос не возвращает строк, происходит предупреждение с кодом ошибки 1329 (No data), и значения переменных остаются неизменными. Если запрос возвращает много строк, происходит ошибка (Result consisted of more than one row). Если возможно, что запрос может получить много строк, Вы можете использовать LIMIT 1, чтобы ограничить набор результатов единственной строкой.

SELECT id, data INTO @x, @y FROM test.t1 LIMIT 1;
Пользовательские имена переменных не являются чувствительными к регистру. См. раздел 10.4.

SELECT ... INTO OUTFILE 'file_name' пишет выбранные строки в файл. Файл создается на сервере, таким образом, Вы должны иметь привилегию FILE . file_name не может быть существующим файлом. character_set_filesystem управляет интерпретацией имени файла.

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

Однако, если клиентское программное обеспечение MySQL установлено на удаленной машине, Вы можете вместо этого использовать команду клиента mysql -e "SELECT ..." > file_name, чтобы произвести файл на хосте клиента.

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

SELECT ... INTO OUTFILE дополнение LOAD DATA INFILE. Значения столбцов записаны преобразованными в набор символов, определенный в CHARACTER SET. Если никакой такой пункт не присутствует, значения выведены, используя binary. В действительности нет никакого преобразования набора символов. Если набор результатов будет содержать столбцы в нескольких наборах символов, то файл выходных данных будет такой же, и Вы не можете перезагрузить файл правильно.

Синтаксис для export_options состоит из тех же самых FIELDS и LINES из LOAD DATA INFILE. См. раздел 14.2.6.

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

  • FIELDS ESCAPED BY.

  • FIELDS [OPTIONALLY] ENCLOSED BY.
  • Первый символ FIELDS TERMINATED BY и LINES TERMINATED BY.
  • ASCII NUL (нулевой байт, то, что фактически написано после символа ESC, является ASCII 0).

FIELDS TERMINATED BY, ENCLOSED BY, ESCAPED BY или LINES TERMINATED BY нужно экранировать, чтобы Вы могли читать файл назад.

Получающийся файл не должен соответствовать синтаксису SQL, таким образом, ничто иное не должно быть экранировано.

Если FIELDS ESCAPED BY символ пуст, никакие символы не экранируются, NULL в выводе будет NULL, не \N. Вероятно, не хорошая идея определить пустой символ ESC, особенно если значения полей в Ваших данных содержат какой-либо из символов в списке.

Вот пример, который производит файл с отделенными запятыми значениями (формат CSV), используемый многими программами:

SELECT a, b, a+b INTO OUTFILE '/tmp/result.txt'
       FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
       LINES TERMINATED BY '\n' FROM test_table;

Если Вы используете INTO DUMPFILE вместо INTO OUTFILE, MySQL пишет только одну строку в файл, без любого столбца или завершения строки и не выполняя обработки escape. Это полезно, если Вы хотите сохранить BLOB в файл.

Любой файл, создаваемый INTO OUTFILE или INTO DUMPFILE перезаписываем всеми пользователями на сервере. Причина этого состоит в том, что сервер MySQL не может создать файл, который принадлежит никому, кроме пользователя, от учетной записи которого он работает. Вы никогда не должны выполнять mysqld как root. Файл таким образом должен быть перезаписываемым всеми, чтобы Вы могли управлять его содержанием.

Если secure_file_priv установлена в непустое имя каталога, файл, который будет написан, должен быть расположен в том каталоге.

В контексте SELECT ... INTO запросы, которые происходят как часть событий, запущенных Планировщиком Событий, сообщения диагностики (не только ошибки, но также и предупреждения) написаны в журнал ошибок и в Windows в журнал событий приложения. Для дополнительной информации см. раздел 21.4.5.

14.2.9.2. JOIN

MySQL поддерживает следующие синтаксисы JOIN для части table_references в SELECT и мультитабличных DELETE и UPDATE:

table_references:
escaped_table_reference [, escaped_table_reference] ...

escaped_table_reference:
table_reference
  | { OJ table_reference }

table_reference:
table_factor
  | join_table

table_factor:
tbl_name [PARTITION (partition_names)]
[[AS] alias] [index_hint_list]
  | table_subquery [AS] alias
  | ( table_references )

join_table:
table_reference [INNER | CROSS] JOIN table_factor
  [join_condition]
  | table_reference STRAIGHT_JOIN table_factor
  | table_reference STRAIGHT_JOIN table_factor
    ON conditional_expr
  | table_reference {LEFT|RIGHT} [OUTER] JOIN
    table_reference join_condition
  | table_reference NATURAL [INNER | {LEFT|RIGHT} [OUTER]]
    JOIN table_factor

join_condition:
ON conditional_expr
  | USING (column_list)

index_hint_list:
index_hint [, index_hint] ...

index_hint:
USE {INDEX|KEY}
  [FOR {JOIN|ORDER BY|GROUP BY}] ([index_list])
  | IGNORE {INDEX|KEY}
  [FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
  | FORCE {INDEX|KEY}
  [FOR {JOIN|ORDER BY|GROUP BY}] (index_list)

index_list:
index_name [, index_name] ...
Табличная ссылка также известна как выражение соединения.

Табличная ссылка (когда это обращается к разделенной таблице) может содержать PARTITION, включая список разделенных запятой значений разделов. Эта опция следует за названием таблицы и предшествует любой декларации псевдонима. Эффект этой опции состоит в том, что строки выбраны только из перечисленного раздела. Другими словами, любой раздел или подраздел, не названный в списке, проигнорирован. Для получения дополнительной информации см. раздел 20.5.

Синтаксис table_factor расширен по сравнению со стандартом SQL. Последний принимает только table_reference , а не список в круглых скобках.

Это консервативное расширение, если мы рассматриваем каждую запятую в списке table_reference как эквивалент внутреннему соединению. Например:

SELECT * FROM t1 LEFT JOIN (t2, t3, t4) ON (t2.a=t1.a AND t3.b=t1.b AND
         t4.c=t1.c)
аналогично вот этому:
SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4) ON
         (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)
В MySQL JOIN, CROSS JOIN и INNER JOIN синтаксические эквиваленты (они могут заменить друг друга). В стандартном SQL они не эквивалентны. INNER JOIN используется с ON, CROSS JOIN иначе.

Вообще, круглые скобки могут быть проигнорированы в выражениях соединения, содержащих только внутренние операции соединения. MySQL также поддерживает вложенные соединения (см. раздел 9.2.1.11).

Индексные подсказки могут быть определены, чтобы затронуть, как оптимизатор MySQL использует индекс. Для получения дополнительной информации см. раздел 9.9.4.

Следующий список описывает общие факторы, чтобы принять во внимание при написании соединений.

  • Табличная ссылка может быть использованием псевдонима tbl_name AS alias_name или tbl_name alias_name:

    SELECT t1.name, t2.salary
           FROM employee AS t1 INNER JOIN info AS t2 ON t1.name = t2.name;
    SELECT t1.name, t2.salary
           FROM employee t1 INNER JOIN info t2 ON t1.name = t2.name;
    
  • table_subquery также известен как подзапрос в FROM. Такие подзапросы должны включать псевдоним, чтобы дать результату подзапроса имя таблицы. Тривиальный пример следует, см. также раздел 14.2.10.8 .
    SELECT * FROM (SELECT 1, 2, 3) AS t1;
    
  • INNER JOIN и запятая (,) семантически эквивалентны в отсутствие условия соединения: оба производят объединение между указанными таблицами (то есть, каждая строка в первой таблице соединена с каждой строкой во второй таблице).

    Однако, приоритет оператора запятой меньше, чем INNER JOIN, CROSS JOIN, LEFT JOIN и и т.д. Если Вы смешиваете соединения запятой с другими типами соединения, когда есть условие соединения, может произойти ошибка формы Unknown column 'col_name' in 'on clause'. Информация о контакте с этой проблемой дана позже в этом разделе.

  • conditional_expr, используемый с ON, это любое условное выражение формы, которая может использоваться в WHERE. Вообще Вы должны использовать ON для условий, которые определяют, как присоединиться к таблицам, и WHERE, чтобы ограничить, какие строки Вы хотите в наборе результатов.
  • Если нет никакой строки соответствия для правильной таблицы в ON или USING в LEFT JOIN, строка со всем набором столбцов установлена в NULL и используется для правой таблицы. Вы можете использовать этот факт, чтобы найти строки в таблице, у которых нет никакой копии в другой таблице:
    SELECT left_tbl.* FROM left_tbl LEFT JOIN right_tbl ON
           left_tbl.id = right_tbl.id
           WHERE right_tbl.id IS NULL;
    
    Этот пример находит все строки в left_tbl с id, которое не присутствует в right_tbl (то есть, все строки в left_tbl без соответствующей строки в right_tbl). Это принимает, что right_tbl.id NOT NULL. См. раздел 9.2.1.9.
  • USING(column_list) называет список столбцов, которые должны существовать в обеих таблицах. Если таблицы a и b обе содержат столбцы c1, c2 и c3, следующее соединение сравнивает соответствующие столбцы от этих двух таблиц:
    a LEFT JOIN b USING (c1,c2,c3)
    
  • NATURAL [LEFT] JOIN из двух таблиц определен, чтобы быть семантически эквивалентным INNER JOIN или LEFT JOIN с USING, который называет все столбцы, которые существуют в обеих таблицах.
  • RIGHT JOIN аналог LEFT JOIN. Чтобы сохранить код портируемым через базы данных, рекомендуется, чтобы Вы использовали LEFT JOIN вместо RIGHT JOIN.
  • { OJ ... } синтаксис, показанный в описании синтаксиса соединения, существует только для совместимости с ODBC. Вьющиеся скобы в синтаксисе должны быть написаны буквально: они не метасинтаксис как в другом месте в описаниях синтаксиса.
    SELECT left_tbl.* FROM { OJ left_tbl LEFT OUTER JOIN right_tbl ON
           left_tbl.id = right_tbl.id }
           WHERE right_tbl.id IS NULL;
    
    Вы можете использовать другие типы соединений в пределах { OJ ...}, например, INNER JOIN или RIGHT OUTER JOIN. Это помогает с совместимостью с некоторыми имеющими отношение к третьей стороне приложениями, но не является официальным синтаксисом ODBC.
  • STRAIGHT_JOIN подобен JOIN, за исключением того, что левая таблица всегда читается перед правой таблицей. Это может использоваться для тех случаев, для которых оптимизатор помещает таблицы в неправильном порядке.

Некоторые примеры соединения:

SELECT * FROM table1, table2;
SELECT * FROM table1 INNER JOIN table2 ON table1.id=table2.id;
SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id;
SELECT * FROM table1 LEFT JOIN table2 USING (id);
SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id
         LEFT JOIN table3 ON table2.id=table3.id;
Присоединитесь к изменениям обработки в MySQL 5.0.12

Естественные соединения и соединения с USING, включая внешние разновидности соединения, обработаны согласно стандарту SQL:2003. Цель состояла в том, чтобы выровнять синтаксис и семантику MySQL относительно NATURAL JOIN и JOIN ... USING согласно SQL:2003. Однако, эти изменения в обработке соединения могут привести к различным выходным столбцам для некоторых соединений. Кроме того, некоторые запросы, которые, казалось, работали правильно в более старых версиях (до 5.0.12) должны быть переписаны, чтобы выполнить стандарт.

У этих изменений есть пять основных аспектов:

  • Способ, из которого MySQL определяет столбцы результата операции соединения NATURAL или USING (и таким образом результат всего FROM).

  • Расширение SELECT * и SELECT tbl_name.* в список выбранных столбцов.
  • Разрешение имен столбцов в соединениях NATURAL или USING.
  • Преобразование NATURAL или USING в JOIN ... ON.
  • Разрешение имен столбцов в выражении ON JOIN ... ON.

Следующий список обеспечивает больше деталей относительно нескольких эффектов текущей обработки соединения против обработки в более старых версиях. Термин старые значит до MySQL 5.0.12.

  • Столбцы в NATURAL или USING при соединении могут отличаться от того, что было ранее. Определенно, избыточные выходные столбцы больше не появляются, и порядок столбцов для SELECT * может отличаться.

    Рассмотрите этот набор запросов:

    CREATE TABLE t1 (i INT, j INT);
    CREATE TABLE t2 (k INT, j INT);
    INSERT INTO t1 VALUES(1,1);
    INSERT INTO t2 VALUES(1,1);
    SELECT * FROM t1 NATURAL JOIN t2;
    SELECT * FROM t1 JOIN t2 USING (j);
    
    Ранее, запросы произвели этот вывод:
    +---+---+---+---+
    | i | j | k | j |
    +---+---+---+---+
    | 1 | 1 | 1 | 1 |
    +---+---+---+---+
    +---+---+---+---+
    | i | j | k | j |
    +---+---+---+---+
    | 1 | 1 | 1 | 1 |
    +---+---+---+---+
    
    В первом SELECT столбец j появляется в обеих таблицах и таким образом становится столбцом соединения, таким образом, согласно стандартному SQL, это должно появиться только однажды в выводе, а не дважды. Точно так же во втором SELECT столбец j назван в USING и должен появиться только однажды в выводе, а не дважды. Но в обоих случаях избыточный столбец не устранен. Кроме того, порядок столбцов не правилен, согласно стандартному SQL.

    Теперь запросы производят этот вывод:

    +---+---+---+
    | j | i | k |
    +---+---+---+
    | 1 | 1 | 1 |
    +---+---+---+
    +---+---+---+
    | j | i | k |
    +---+---+---+
    | 1 | 1 | 1 |
    +---+---+---+
    
    Избыточный столбец устранен, и порядок следования столбцов правилен, согласно стандартному SQL:

    • Во-первых, общие столбцы двух таблиц присоединяются в порядке, в котором они происходят в первой таблице.

    • Во-вторых, столбцы, уникальные для первой таблицы, в порядке, в котором они происходят в той таблице.
    • В-третьих, столбцы, уникальные для второй таблицы, в порядке, в котором они происходят в той таблице.

    Единственный столбец результата, который заменяет два общих столбца, определен, используя объединение. Таким образом, для двух столбцов t1.a и t2.a получающийся единственный столбец соединения a определен как a = COALESCE(t1.a, t2.a), где:

    COALESCE(x, y) = (CASE WHEN V1 IS NOT NULL THEN V1 ELSE V2 END)
    
    Если работа соединения какое-либо другое соединение, столбцы результата соединения состоит из связи всех столбцов таблиц, к которым присоединяются. Это то же самое, как ранее.

    Последствие определения соединенных столбцов: для внешних соединений соединенный столбец содержит значение столбца не-NULL, если один из двух столбцов всегда NULL. Если ни один или оба столбца не NULL, у обоих общих столбцов есть то же самое значение, таким образом, не имеет значения, какой выбран в качестве значения соединенного столбца. Простой способ интерпретировать это состоит в том, чтобы полагать, что соединенный столбец внешнего соединения представлен общим столбцом внутренней таблицы JOIN. Предположите, что таблицы t1(a,b) и t2(a,c) имеют следующее содержание:

    t1    t2
    ----  ----
    1 x   2 z
    2 y   3 w
    
    Тогда:
    mysql> SELECT * FROM t1 NATURAL LEFT JOIN t2;
    +---+---+------+
    | a | b | c    |
    +---+---+------+
    | 1 | x | NULL |
    | 2 | y | z    |
    +---+---+------+
    
    Здесь столбец a содержит значения t1.a.
    mysql> SELECT * FROM t1 NATURAL RIGHT JOIN t2;
    +---+---+------+
    | a | c | b    |
    +---+---+------+
    | 2 | z | y    |
    | 3 | w | NULL |
    +---+---+------+
    
    Здесь столбец a содержит значения t2.a.

    Сравните эти результаты с иначе эквивалентными запросами с JOIN ... ON:

    mysql> SELECT * FROM t1 LEFT JOIN t2 ON (t1.a = t2.a);
    +---+---+------+------+
    | a | b | a    | c    |
    +---+---+------+------+
    | 1 | x | NULL | NULL |
    | 2 | y | 2    | z    |
    +---+---+------+------+
    
    mysql> SELECT * FROM t1 RIGHT JOIN t2 ON (t1.a = t2.a);
    +------+------+---+---+
    | a    | b    | a | c |
    +------+------+---+---+
    | 2    | y    | 2 | z |
    | NULL | NULL | 3 | w |
    +------+------+---+---+
    
  • Ранее USING мог быть переписан как ON, который сравнивает соответствующие столбцы. Например, следующие два пункта были семантически идентичны:
    a LEFT JOIN b USING (c1,c2,c3)
    a LEFT JOIN b ON a.c1=b.c1 AND a.c2=b.c2 AND a.c3=b.c3
    
    Теперь эти два пункта больше не вполне то же самое:

    • Относительно определения, какие строки удовлетворяют условие соединения, оба соединения остаются семантически идентичными.

    • Относительно определения, которые столбцы вывести для SELECT *, два соединения не семантически идентичны. USING соединение выбирает соединенное значение соответствующих столбцов, тогда как ON выбирает все столбцы из всех таблиц. Для предыдущего USING SELECT * выбирает эти значения:
      COALESCE(a.c1,b.c1), COALESCE(a.c2,b.c2), COALESCE(a.c3,b.c3)
      
      Для ON SELECT * выбирает эти значения:
      a.c1, a.c2, a.c3, b.c1, b.c2, b.c3
      
      С внутренним соединением COALESCE(a.c1,b.c1) то же самое, как a.c1 или b.c1 потому что у обоих столбцов будет то же самое значение. С внешним соединением (например, LEFT JOIN) один из двух столбцов может быть NULL. Тот столбец будет убран из результата.

  • Оценка многоканальных естественных соединений отличается очень важным способом, который затрагивает результат NATURAL или USING, и это может потребовать перезаписи запроса. Предположите, что у Вас есть три таблицы t1(a,b), t2(c,b) и t3(a,c), которые имеют одну строку: t1(1,2), t2(10,2) и t3(7,10). Предположите также, что у Вас есть NATURAL JOIN на этих трех таблицах:
    SELECT ... FROM t1 NATURAL JOIN t2 NATURAL JOIN t3;
    
    Ранее, левый операнд второго соединения, как полагали, был t2, тогда как это должно быть вложенное соединение (t1 NATURAL JOIN t2) . В результате столбцы t3 проверены на общие столбцы только в t2, и, если t3 имеет общие столбцы с t1, эти столбцы не используются в качестве столбцов equi-join. Таким образом, ранее, предыдущий запрос был преобразован к следующему equi-соединению:
    SELECT ... FROM t1, t2, t3 WHERE t1.b = t2.b AND t2.c = t3.c;
    
    То соединение пропускает еще один предикат equi-соединения (t1.a = t3.a). В результате это производит одну строку, а не пустой результат, как должно. Правильный эквивалентный запрос:
    SELECT ... FROM t1, t2, t3 WHERE t1.b = t2.b AND t2.c = t3.c AND t1.a = t3.a;
    
    Если Вы требуете того же самого результата запроса в текущих версиях MySQL, как в более старых версиях, переписывайте естественное соединение как первое equi-соединение.
  • Ранее у оператора запятой (,) и JOIN был тот же самый приоритет, таким образом, выражение соединения t1, t2 JOIN t3 интерпретировалось как ((t1, t2) JOIN t3). Теперь JOIN имеет более высокий приоритет, таким образом, выражение интерпретируется как (t1, (t2 JOIN t3)). Это изменение затрагивает запросы, которые используют ON, потому что тот пункт может отнестись только к столбцам в операндах соединения, и изменению в интерпретации изменений приоритета того, каковы те операнды.

    Например:

    CREATE TABLE t1 (i1 INT, j1 INT);
    CREATE TABLE t2 (i2 INT, j2 INT);
    CREATE TABLE t3 (i3 INT, j3 INT);
    INSERT INTO t1 VALUES(1,1);
    INSERT INTO t2 VALUES(1,1);
    INSERT INTO t3 VALUES(1,1);
    SELECT * FROM t1, t2 JOIN t3 ON (t1.i1 = t3.i3);
    
    Ранее SELECT было законным из-за неявной группировки t1,t2 как (t1,t2). Теперь JOIN имеет приоритет, таким образом, операнды для ON это t2 и t3. Поскольку t1.i1 не столбец в любом из операндов, результат: ошибка Unknown column 't1.i1' in 'on clause'. Чтобы позволить соединению быть обработанным, сгруппируйте первые две таблицы явно с круглыми скобками так, чтобы операнды для ON (t1,t2) и t3:
    SELECT * FROM (t1, t2) JOIN t3 ON (t1.i1 = t3.i3);
    
    Альтернативно, избегите использования оператора запятой и используйте вместо него JOIN:
    SELECT * FROM t1 JOIN t2 JOIN t3 ON (t1.i1 = t3.i3);
    
    Это изменение также относится к запросам, которые смешивают оператор запятой с INNER JOIN, CROSS JOIN, LEFT JOIN и RIGHT JOIN, у всех из которых теперь есть более высокий приоритет, чем у оператора запятой.
  • Ранее ON мог отнестись к столбцам в таблицах, названных с правой стороны от него. Теперь ON может отнестись только к его операндам.

    Пример:

    CREATE TABLE t1 (i1 INT);
    CREATE TABLE t2 (i2 INT);
    CREATE TABLE t3 (i3 INT);
    SELECT * FROM t1 JOIN t2 ON (i1 = i3) JOIN t3;
    
    Ранее SELECT был законным. Теперь запрос терпит неудачу с ошибкой Unknown column 'i3' in 'on clause', поскольку i3 столбец в t3, который не является операндом ON. Запрос должен быть переписан следующим образом:
    SELECT * FROM t1 JOIN t2 JOIN t3 ON (i1 = i3);
    
  • Разрешение имен столбцов в соединениях NATURAL или USING отличаются от того, что было ранее. Для имен столбцов, которые вне FROM, MySQL теперь обрабатывает супернабор запросов по сравнению с ранней логикой. Таким образом, в случаях, когда MySQL прежде выпустил ошибку, что некоторый столбец неоднозначен, запрос теперь обработан правильно. Это вследствие того, что MySQL теперь обрабатывает общие столбцы соединения NATURAL или USING как единственный столбец, так что, когда запрос обращается к таким столбцам, компилятор запроса не рассматривает их как неоднозначные.

    Пример:

    SELECT * FROM t1 NATURAL JOIN t2 WHERE b > 1;
    
    Ранее этот запрос произвел бы ошибку ERROR 1052 (23000): Column 'b' in where clause is ambiguous. Теперь запрос приводит к правильному результату:
    +---+---+---+
    | b | c | y |
    +---+---+---+
    | 4 | 2 | 3 |
    +---+---+---+
    
    Одно расширение MySQL по сравнению со стандартом SQL:2003 состоит в том, что MySQL позволяет Вам указать общие (coalesced) столбцы соединения NATURAL или USING (так же, как ранее) в то время, как стандарт отвергает это.

14.2.9.3. UNION

SELECT ... UNION [ALL | DISTINCT] SELECT ...
           [UNION [ALL | DISTINCT] SELECT ...]
UNION используется, чтобы объединить следствие многократного SELECT в единственный набор результатов.

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

Если типы данных соответствующих столбцов SELECT не соответствуют типам и длинам столбцов в UNION, принимаются во внимание значения, полученные всеми SELECT. Например, рассмотрите следующее:

mysql> SELECT REPEAT('a',1) UNION SELECT REPEAT('b',10);
+---------------+
| REPEAT('a',1) |
+---------------+
| a             |
| bbbbbbbbbb    |
+---------------+
SELECT это нормальные запросы, но со следующими ограничениями:

  • Только последний SELECT может использовать INTO OUTFILE. Однако, все результаты UNION написаны в файл.

  • HIGH_PRIORITY не может использоваться с SELECT, которые являются частью UNION. Если Вы определяете это для первого SELECT, это не имеет никакого эффекта. Если Вы определяете это для кого-либо последующего SELECT, будет синтаксическая ошибка.

Поведение по умолчанию для UNION: дублирующиеся строки удалены из результата. Дополнительно DISTINCT не имеет никакого эффекта кроме значения по умолчанию, потому что это также определяет удаление дублирующейся строки. С дополнительным ALL удаления дублирующейся строки не происходит, и результат включает все строки соответствия от всех SELECT.

Вы можете смешать UNION ALL и UNION DISTINCT в запросе. Смешанные UNION обработаны таким образом, что a DISTINCT переопределяет любой ALL с его левой стороны. DISTINCT может быть произведен явно при использовании UNION DISTINCT или неявно при использовании UNION без следующего DISTINCT или ALL.

Применять ORDER BY или LIMIT к отдельному SELECT можно, поместив его в круглых скобках, которые сопровождают SELECT:

(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10) UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);
Однако, использование ORDER BY для отдельного SELECT ничего не подразумевает о порядке, в котором строки появляются в окончательном результате, потому что UNION по умолчанию производит неупорядоченный набор строк. Поэтому, использование ORDER BY в этом контексте, как правило, находится в соединении с LIMIT, чтобы это использовалось, чтобы определить подмножество выбранных строк для SELECT, даже при том, что это не обязательно затрагивает порядок тех строк в финальном результате UNION. Если ORDER BY появляется без LIMIT в SELECT, это оптимизировано далеко, потому что это не будет иметь никакого эффекта так или иначе.

Используя ORDER BY или LIMIT, чтобы сортировать или ограничить все UNION, введите индивидуальный SELECT поместите ORDER BY или LIMIT после последнего. Следующий пример использует оба параметра:

(SELECT a FROM t1 WHERE a=10 AND B=1) UNION
          (SELECT a FROM t2 WHERE a=11 AND B=2)
          ORDER BY a LIMIT 10;
Запрос без круглых скобок эквивалентен одному параметру, как показано.

Этот ORDER BY не может использовать ссылки столбца, которые включают имя таблицы (то есть, имена в формате tbl_name.col_name). Вместо этого обеспечьте псевдоним столбца в первом SELECT и обратитесь к псевдониму в ORDER BY. Альтернативно, обратитесь к столбцу в ORDER BY с использованием его позиции столбца. Однако, использование позиций столбца устарело.

Кроме того, если столбец, который будет сортирован, является псевдонимом, ORDER BY должен отнестись к псевдониму, а не имени столбца. Первый из следующих запросов будет работать, но второй потерпит неудачу с ошибкой Unknown column 'a' in 'order clause':

(SELECT a AS b FROM t) UNION (SELECT ...) ORDER BY b;
(SELECT a AS b FROM t) UNION (SELECT ...) ORDER BY a;
При вызове строк в UNION результат будет состоять из наборов строк, полученных каждым SELECT один за другим, выберите дополнительный столбец в каждом SELECT, чтобы использовать в качестве столбца сортировки и добавить ORDER BY после последнего SELECT:
(SELECT 1 AS sort_col, col1a, col1b, ... FROM t1) UNION
          (SELECT 2, col2a, col2b, ... FROM t2) ORDER BY sort_col;
Чтобы дополнительно поддержать порядок сортировки в пределах SELECT, добавьте вторичный столбец к ORDER BY:
(SELECT 1 AS sort_col, col1a, col1b, ... FROM t1) UNION
          (SELECT 2, col2a, col2b, ... FROM t2) ORDER BY sort_col, col1a;
Использование дополнительного столбца также позволяет Вам определить, из которого SELECT каждая строка прибывает. Дополнительные столбцы могут предоставить другую информацию об идентификации также, такую как строку, которая указывает на имя таблицы.

Запросы UNION с совокупной функцией в ORDER BY отклонены с ошибкой ER_AGGREGATE_ORDER_FOR_UNION:

SELECT 1 AS foo UNION SELECT 2 ORDER BY MAX(1);

14.2.10. Синтаксис подзапроса

Подзапрос это SELECT в пределах другого запроса.

Все подформы запросов и операции, которых требует стандарт SQL, поддержаны, так же как несколько особенностей, которые являются MySQL-определенными.

Вот пример подзапроса:

SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
В этом примере SELECT * FROM t1 ... внешний запрос, а (SELECT column1 FROM t2) подзапрос. Мы говорим, что подзапрос вложен в пределах внешнего запроса и фактически возможно вложить подзапросы в пределах других подзапросов на значительную глубину. Подзапрос должен всегда появляться в пределах круглых скобок.

Основные преимущества подзапросов:

  • Они позволяют запросы, которые структурированы так, чтобы было возможно изолировать каждую часть запроса.

  • Они обеспечивают альтернативные способы выполнить операции, которые иначе потребовали бы сложных соединений и союзов.
  • Много людей считают подзапросы более читаемыми, чем сложные соединения или союзы. Действительно, это было новшество подзапросов, которые дали людям оригинальную идею назвать ранний SQL Structured Query Language.

Вот запрос в качестве примера, который показывает важные пункты о синтаксисе подзапроса, как определено стандартом SQL и поддержано в MySQL:

DELETE FROM t1 WHERE s11 > ANY
       (SELECT COUNT(*) /* no hint */ FROM t2
               WHERE NOT EXISTS (SELECT * FROM t3 WHERE ROW(5*t2.s1,77)=
               (SELECT 50,11*s1 FROM t4 UNION SELECT 50,77 FROM
               (SELECT * FROM t5) AS t5)));
Подзапрос может возвратить скаляр (единственное значение), единственную строку, единственный столбец или таблицу (одна или более строк одного или более столбцов). Их называют скаляром, столбцом, строкой и табличными подзапросами. Подзапросы, которые возвращают особый вид результата, часто могут использоваться только в определенных контекстах, как описано в следующих разделах.

Есть немного ограничений на тип запросов, в которых могут использоваться подзапросы. Подзапрос может содержать многие из ключевых слов, которые допустимы в рамках SELECT: DISTINCT, GROUP BY, ORDER BY, LIMIT, объединения, UNION, комментарии, функции и так далее.

Внешний запрос подзапроса может быть любым из: SELECT, INSERT, UPDATE, DELETE, SET или DO.

В MySQL Вы не можете изменить таблицу и выбрать из той же самой таблицы в подзапросе. Это относится к таким запросам, как DELETE, INSERT, REPLACE, UPDATE и (потому что подзапросы могут использоваться в SET) LOAD DATA INFILE.

14.2.10.1. Подзапрос как скалярный операнд

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

CREATE TABLE t1 (s1 INT, s2 CHAR(5) NOT NULL);
INSERT INTO t1 VALUES(100, 'abcde');
SELECT (SELECT s2 FROM t1);
Подзапрос в этом SELECT возвращает единственное значение ('abcde'), у этого есть тип данных CHAR, длина 5, набор символов и сопоставление, равное значениям по умолчанию во время CREATE TABLE, и признак, что значение в столбце может быть NULL. Такие значения, выбранные скалярным подзапросом, не скопированы, потому что, если результат подзапроса пуст, результат NULL. Для показанного подзапроса, если t1 пуст, результат будет NULL даже при том, что s2 NOT NULL.

Есть несколько контекстов, в которых не может использоваться скалярный подзапрос. Если запрос разрешает только буквальное значение, Вы не можете использовать подзапрос. Например, LIMIT требует буквальных параметров целого числа, и LOAD DATA INFILE требует буквального строкового имени файла. Вы не можете использовать подзапросы, чтобы поставлять эти значения.

Когда Вы видите примеры в следующих разделах, которые содержат довольно спартанскую конструкцию (SELECT column1 FROM t1), предположите, что Ваш собственный код содержит намного более разнообразные и сложные конструкции.

Предположите, что мы делаем две таблицы:

CREATE TABLE t1 (s1 INT);
INSERT INTO t1 VALUES (1);
CREATE TABLE t2 (s1 INT);
INSERT INTO t2 VALUES (2);
Тогда выполните SELECT:
SELECT (SELECT s1 FROM t2) FROM t1;
Результат 2 потому что есть строка в t2, содержащая столбец s1, а у этого есть значение 2.

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

SELECT UPPER((SELECT s1 FROM t1)) FROM t2;

14.2.10.2. Сравнения, используя подзапросы

Наиболее популярный способ использования подзапроса находится в форме:

non_subquery_operand comparison_operator
(subquery)
Здесь comparison_operator один из этих операторов:
=  >  <  >=  <=  <>  !=  <=>
Например:
... WHERE 'a' = (SELECT column1 FROM t1)
MySQL также разрешает эту конструкцию:
non_subquery_operand LIKE (subquery)
Когда-то единственное место для подзапроса было на правой стороне сравнения, и Вы могли бы все еще найти некоторые старые DBMS, которые настаивают на этом.

Вот пример сравнения подзапроса стандартной формы, которое Вы не можете сделать с соединением. Это находит все строки в таблице t1 для которых column1 равно максимальному значению в таблице t2:

SELECT * FROM t1 WHERE column1 = (SELECT MAX(column2) FROM t2);
Вот другой пример, который снова невозможен с соединением, потому что он вовлекает соединение для одной из таблиц. Это находит все строки в таблице t1, содержа значение, которое встречается дважды в данном столбце:
SELECT * FROM t1 AS t WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);
Для сравнения подзапроса и скаляра подзапрос должен возвратить скаляр. Для сравнения подзапроса со строкой подзапрос должен быть подзапросом строки, который возвращает строку с тем же самым числом значений, как конструктор строки. См. раздел 14.2.10.5.

14.2.10.3. Подзапросы с ANY, IN или SOME

operand comparison_operator ANY (subquery)
operand IN (subquery)
operand comparison_operator SOME (subquery)
Здесь comparison_operator одно из:
=  >  <  >=  <=  <>  !=
ANY должно следовать за оператором сравнения, означает вернуть TRUE, если сравнение TRUE для ANY из значений в столбце, который вернул подзапрос :
SELECT s1 FROM t1 WHERE s1 > ANY (SELECT s1 FROM t2);
Предположите, что есть строка в таблице t1, содержащая (10). Выражение TRUE, если таблица t2 содержит (21,14,7) потому, что есть значение 7 в t2, это меньше 10. Выражение FALSE, если таблица t2 содержит (20,10), или если таблица t2 пуста. Выражение неизвестно (то есть, NULL), если таблица t2 содержит (NULL,NULL,NULL).

Когда используется с подзапросом IN псевдоним для = ANY. Таким образом, эти два запроса то же самое:

SELECT s1 FROM t1 WHERE s1 = ANY (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 IN(SELECT s1 FROM t2);
IN и = ANY не синонимы, когда используются со списком выражений. IN может взять список выражений, но = ANY нет, см. раздел 13.3.2.

NOT IN псевдоним не для <> ANY, а для <> ALL. См. раздел 14.2.10.4.

SOME псевдоним для ANY. Таким образом, эти два запроса то же самое:

SELECT s1 FROM t1 WHERE s1 <> ANY  (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 <> SOME (SELECT s1 FROM t2);
Использование слова SOME редко, но этот пример показывает, почему это могло бы быть полезно. Большинству людей фраза a не равный любому b означает нет никакого b, который равен a, но это не то, что предназначается синтаксисом SQL. Синтаксис означает есть некоторый b, который не равен a. Использование <> SOME вместо этого помогает гарантировать, что все понимают значение запроса.

14.2.10.4. Подзапросы с ALL

operand comparison_operator
    ALL (subquery)
ALL, который должен следовать за оператором сравнения, означает вернуть TRUE, если сравнение TRUE для ALL значений в столбце, который вернул подзапрос:
SELECT s1 FROM t1 WHERE s1 > ALL (SELECT s1 FROM t2);
Предположите, что есть строка в таблице t1, содержащая (10). Выражение TRUE, если таблица t2 содержит (-5,0,+5), поскольку 10 больше чем все три значения в t2. Выражение FALSE, если таблица t2 содержит (12,6,NULL,-100) потому, что есть единственное значение 12 в таблице t2, которое больше 10. Выражение неизвестно (то есть, NULL), если таблица t2 содержит (0,NULL,1).

Наконец, выражение TRUE, если таблица t2 пуста. Так, следующее выражение TRUE, когда таблица t2 пуста:

SELECT * FROM t1 WHERE 1 > ALL (SELECT s1 FROM t2);
Но это выражение NULL, когда таблица t2 пуста:
SELECT * FROM t1 WHERE 1 > (SELECT s1 FROM t2);
Кроме того, следующее выражение NULL когда таблица t2 пуста:
SELECT * FROM t1 WHERE 1 > ALL (SELECT MAX(s1) FROM t2);
Вообще, таблицы, содержащие значения NULL и пустые таблицы проблемные ситуации при написании подзапросов, всегда рассматривайте, приняли ли Вы эти две возможности во внимание.

NOT IN псевдоним для <> ALL. Таким образом, эти два запроса те же самые:

SELECT s1 FROM t1 WHERE s1 <> ALL (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 NOT IN (SELECT s1 FROM t2);

14.2.10.5. Подзапросы строки

Скаляр или подзапросы столбца возвращают единственное значение или столбец значений. Подзапрос строки это разновидность подзапроса, которая возвращает единственную строку и может таким образом возвратить больше, чем одно значение столбца. Операторы для сравнений подзапроса строки:

=  >  <  >=  <=  <>  !=  <=>
Вот два примера:
SELECT * FROM t1 WHERE (col1,col2) = (SELECT col3, col4 FROM t2
         WHERE id = 10);
SELECT * FROM t1 WHERE ROW(col1,col2) = (SELECT col3, col4 FROM t2
         WHERE id = 10);
Для обоих запросов, если таблица t2 содержит единственную строку с id = 10, подзапрос возвращает единственную строку. Если эта строка имеет значения col3 и col4, равные col1 и col2 любых строк в t1, WHERE TRUE и каждый запрос возвращает те строки t1. Если значения строк col3 и col4 в t2 не равны значениям col1 и col2 любой строки в t1, выражение FALSE и запрос возвращает пустой набор результатов. Выражение неизвестно (то есть, NULL), если подзапрос не производит строк. Ошибка происходит, если подзапрос производит много строк, потому что подзапрос строки может возвратить самое большее одну строку.

Выражения (1,2) и ROW(1,2) иногда называются конструкторами строки. Эти два эквивалентны. Конструктор строки и строка, возвращенная подзапросом, должны содержать то же самое число значений.

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

SELECT * FROM t1 WHERE ROW(1) = (SELECT column1 FROM t2)
Конструкторы строки являются законными в других контекстах. Например, следующие два запроса семантически эквивалентны (и обработаны таким же образом оптимизатором):
SELECT * FROM t1 WHERE (column1,column2) = (1,1);
SELECT * FROM t1 WHERE column1 = 1 AND column2 = 1;
Следующий запрос отвечает на запрос найти все строки в таблице t1, которые также существуют в таблице t2:
SELECT column1,column2,column3 FROM t1 WHERE (column1,column2,column3) IN
       (SELECT column1,column2,column3 FROM t2);

14.2.10.6. Подзапросы с EXISTS или NOT EXISTS

Если подзапрос возвращает какие-либо строки вообще, EXISTS subquery TRUE, а NOT EXISTS subquery FALSE:

SELECT column1 FROM t1 WHERE EXISTS (SELECT * FROM t2);
Традиционно подзапрос EXISTS начинается с SELECT *, но это могло начаться с SELECT 5 или SELECT column1 или вообще с чего угодно. MySQL игнорирует список SELECT в таком подзапросе, таким образом, это не имеет никакого значения.

Для предыдущего примера, если t2 содержит любые строки, даже строки только со значениями NULL, условие EXISTS TRUE. Это фактически маловероятный пример потому, что подзапрос [NOT] EXISTS почти всегда содержит корреляции. Вот некоторые более реалистические примеры:

  • Какое хранилище присутствует в одном или более городах?

    SELECT DISTINCT store_type FROM stores
           WHERE EXISTS (SELECT * FROM cities_stores
           WHERE cities_stores.store_type = stores.store_type);
    
  • Какое хранилище не присутствует ни в каких городах?
    SELECT DISTINCT store_type FROM stores
           WHERE NOT EXISTS (SELECT * FROM cities_stores
           WHERE cities_stores.store_type = stores.store_type);
    
  • Какое хранилище присутствует во всех городах?
    SELECT DISTINCT store_type FROM stores s1
           WHERE NOT EXISTS (SELECT * FROM cities WHERE NOT EXISTS (
           SELECT * FROM cities_stores
                    WHERE cities_stores.city = cities.city AND
                    cities_stores.store_type = stores.store_type));
    

Последний пример двоичным образом вложенный запрос NOT EXISTS. Таким образом, у этого есть NOT EXISTS в пределах NOT EXISTS. Формально это отвечает на вопрос есть ли город с хранилищем, которое не находится в Stores? Но легче сказать что вложенный NOT EXISTS отвечает на вопрос есть ли x TRUE для всех y?

14.2.10.7. Коррелированые подзапросы

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

SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM t2
         WHERE t2.column2 = t1.column2);
Заметьте, что подзапрос содержит ссылку на столбец t1 даже при том, что FROM подзапроса не упоминает таблицу t1. MySQL смотрит вне подзапроса и находит t1 во внешнем запросе.

Предположите, что таблица t1 содержит строку, где column1 = 5 и column2 = 6, тем временем таблица t2 содержит строку, где column1 = 5 и column2 = 7. Простое выражение ... WHERE column1 = ANY (SELECT column1 FROM t2) было бы TRUE, но в этом примере WHERE в пределах подзапроса FALSE (потому что (5,6) не (5,7)), таким образом, выражение в целом FALSE.

Правило обзора данных: MySQL оценивает изнутри к внешней стороне. Например:

SELECT column1 FROM t1 AS x WHERE x.column1 = (SELECT column1 FROM t2 AS x
       WHERE x.column1 = (SELECT column1 FROM t3
       WHERE x.column2 = t3.column1));
В этом запросе x.column2 должен быть столбец в таблице t2 потому, что SELECT column1 FROM t2 AS x ... переименовывает t2. Это не столбец в таблице t1, потому что SELECT column1 FROM t1 ... внешний запрос, который дальше отсутствует.

Для подзапросов в HAVING или ORDER BY MySQL также ищет имена столбцов во внешнем избранном списке.

Для определенных случаев оптимизирован коррелированый подзапрос. Например:

val IN (SELECT key_val FROM
tbl_name WHERE correlated_condition)
Иначе они неэффективны и вероятны будут медленными. Запрос переписан, поскольку соединение могло бы улучшить работу.

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

14.2.10.8. Подзапросы в FROM

Подзапросы являются законными в параметре FROM SELECT:

SELECT ... FROM (subquery) [AS] name ...
[AS] name принудителен, потому что каждая таблица в FROM должна иметь имя. Любые столбцы в subquery должны иметь уникальные имена.

Ради иллюстрации предположите, что у Вас есть эта таблица:

CREATE TABLE t1 (s1 INT, s2 CHAR(5), s3 FLOAT);
Вот как использовать подзапрос в FROM, используя таблицу в качестве примера:
INSERT INTO t1 VALUES (1,'1',1.0);
INSERT INTO t1 VALUES (2,'2',2.0);
SELECT sb1,sb2,sb3 FROM (SELECT s1 AS sb1, s2 AS sb2, s3*2 AS sb3 FROM t1)
       AS sb WHERE sb1 > 1;
Результат: 2, '2', 4.0.

Вот другой пример: предположите, что Вы хотите знать среднее число ряда сумм для сгруппированной таблицы. Это не работает:

SELECT AVG(SUM(column1)) FROM t1 GROUP BY column1;
Однако, этот запрос предоставляет желаемую информацию:
SELECT AVG(sum_column1) FROM (SELECT SUM(column1) AS sum_column1
       FROM t1 GROUP BY column1) AS t1;
Заметьте, что имя столбца, использованное в пределах подзапроса (sum_column1), признано во внешнем запросе.

Подзапросы в FROM могут возвратить скаляр, столбец, строку или таблицу. Подзапросы в FROM не могут быть коррелированными подзапросами, если не используются в пределах ON в JOIN.

В MySQL 8.0 оптимизатор определяет информацию о полученных таблицах таким способом, для которого не происходит материализация их для EXPLAIN. См. раздел 9.2.1.18.3.

Возможно при определенных обстоятельствах изменить табличное использование данных, применив EXPLAIN SELECT. Это может произойти, если внешние запросы обращаются к любым таблицам, а внутренний запрос вызывает сохраненную функцию, которая изменяет одну или более строк таблицы. Предположите, что есть две таблицы t1 и t2 в базе данных d1, создаваемой как показано здесь:

mysql> CREATE DATABASE d1;
Query OK, 1 row affected (0.00 sec)

mysql> USE d1;
Database changed

mysql> CREATE TABLE t1 (c1 INT);
Query OK, 0 rows affected (0.15 sec)

mysql> CREATE TABLE t2 (c1 INT);
Query OK, 0 rows affected (0.08 sec)
Теперь мы создаем сохраненную функцию f1, которая изменяет t2:
mysql> DELIMITER //
mysql> CREATE FUNCTION f1(p1 INT) RETURNS INT
mysql>   BEGIN
mysql> INSERT INTO t2 VALUES (p1);
mysql> RETURN p1;
mysql>   END //
Query OK, 0 rows affected (0.01 sec)

mysql> DELIMITER ;
Ссылка на функцию непосредственно в EXPLAIN SELECT не имеет никакого эффекта на t2, как показано здесь:
mysql> SELECT * FROM t2;
Empty set (0.00 sec)

mysql> EXPLAIN SELECT f1(5);
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
|  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | No tables used |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM t2;
Empty set (0.00 sec)
Это потому, что SELECT не ссылается ни на какие таблицы, как может быть замечено в столбцах table и Extra вывода. Это также верно для вложенного следующего SELECT:
mysql> EXPLAIN SELECT NOW() AS a1, (SELECT f1(5)) AS a2;
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
|  1 | PRIMARY     | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | No tables used |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS;
+-------+------+------------------------------------------+
| Level | Code | Message                                  |
+-------+------+------------------------------------------+
| Note  | 1249 | Select 2 was reduced during optimization |
+-------+------+------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM t2;
Empty set (0.00 sec)
Однако, если внешний SELECT ссылаетя на любые таблицы, оптимизатор выполняет запрос в подзапросе также:
mysql> EXPLAIN SELECT * FROM t1 AS a1, (SELECT f1(5)) AS a2;
+----+-------------+------------------+--------+---------------+------+---------+------+------+---------------------+
| id | select_type | table            | type   | possible_keys | key  | key_len | ref  | rows | Extra               |
+----+-------------+------------------+--------+---------------+------+---------+------+------+---------------------+
|  1 | PRIMARY     | a1               | system | NULL          | NULL | NULL    | NULL | 0    | const row not found |
|  1 | PRIMARY     | <derived2> | system | NULL          | NULL | NULL    | NULL | 1    |                     |
|  2 | DERIVED     | NULL             | NULL   | NULL          | NULL | NULL    | NULL | NULL | No tables used      |
+----+-------------+------------------+--------+---------------+------+---------+------+------+---------------------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM t2;
+----+
| c1 |
+----+
| 5  |
+----+
1 row in set (0.00 sec)
Это также означает, что такой запрос EXPLAIN SELECT, как один показанный здесь, может занять много времени, чтобы выполнить, потому что функция BENCHMARK() выполнена однажды для каждой строки в t1:
EXPLAIN SELECT * FROM t1 AS a1, (SELECT BENCHMARK(1000000, MD5(NOW())));

14.2.10.9. Ошибки подзапроса

Есть некоторые ошибки, которые применяются только к подзапросам. Этот раздел описывает их.

  • Неподдержанный синтаксис подзапроса:

    ERROR 1235 (ER_NOT_SUPPORTED_YET)
    SQLSTATE = 42000
    Message = "This version of MySQL doesn't yet support
    'LIMIT & IN/ALL/ANY/SOME subquery'"
    
    Это означает, что MySQL не поддерживает запросы следующей формы:
    SELECT * FROM t1 WHERE s1 IN (SELECT s2 FROM t2 ORDER BY s1 LIMIT 1)
    
  • Неправильное число столбцов в подзапросе:
    ERROR 1241 (ER_OPERAND_COL)
    SQLSTATE = 21000
    Message = "Operand should contain 1 column(s)"
    
    Эта ошибка происходит в таких случаях:
    SELECT (SELECT column1, column2 FROM t2) FROM t1;
    
    Вы можете использовать подзапрос, который возвращает много столбцов, если цель сравнение строк. В других контекстах подзапрос должен быть скалярным операндом. См. раздел 14.2.10.5.
  • Неправильное число строк от подзапроса:
    ERROR 1242 (ER_SUBSELECT_NO_1_ROW)
    SQLSTATE = 21000
    Message = "Subquery returns more than 1 row"
    
    Эта ошибка происходит для запросов, куда подзапрос должен возвратить самое большее одну строку, но возвращает много строк. Рассмотрите следующий пример:
    SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
    
    Если SELECT column1 FROM t2 вернет только одну строку, предыдущий запрос будет работать. Если подзапрос возвратит больше, чем одну строку, будет ошибка 1242. В этом случае запрос должен быть переписан так:
    SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM t2);
    
  • Неправильно используемая таблица в подзапросе:
    Error 1093 (ER_UPDATE_TABLE_USED)
    SQLSTATE = HY000
    Message = "You can't specify target table 'x'
    for update in FROM clause"
    
    Эта ошибка происходит в таких случаях, как следующий, который пытается изменить таблицу и выбрать из той же самой таблицы в подзапросе:
    UPDATE t1 SET column2 = (SELECT MAX(column1) FROM t1);
    
    Вы можете использовать подзапрос для назначения в пределах UPDATE потому, что подзапросы являются законными в UPDATE и DELETE так же, как в SELECT. Однако, Вы не можете использовать ту же самую таблицу (в этом случае таблица t1) для обоих подзапросов FROM и цели обновления.

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

14.2.10.10. Оптимизация подзапросов

Развитие является продолжающимся, таким образом, никакая подсказка по оптимизации не надежна в течение длительного срока. Следующий список обеспечивает некоторые интересные уловки, с которыми Вы могли бы работать:

  • Используйте пункты подзапроса, которые затрагивают число или порядок строк в подзапросе. Например:

    SELECT * FROM t1 WHERE t1.column1 IN
             (SELECT column1 FROM t2 ORDER BY column1);
    SELECT * FROM t1 WHERE t1.column1 IN (SELECT DISTINCT column1 FROM t2);
    SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 LIMIT 1);
    
  • Замените соединение подзапросом. Например, попробуйте это:
    SELECT DISTINCT column1 FROM t1 WHERE t1.column1 IN (
           SELECT column1 FROM t2);
    
    Вместо этого:
    SELECT DISTINCT t1.column1 FROM t1, t2 WHERE t1.column1 = t2.column1;
    
  • Некоторые подзапросы могут быть преобразованы к соединениям для совместимости с более старыми версиями MySQL, которые не поддерживают подзапросы. Однако, в некоторых случаях, преобразование подзапроса к соединению может улучшить работу. См. раздел 14.2.10.11.
  • Переместите пункты снаружи во внутреннюю часть подзапрос. Например, используйте этот запрос:
    SELECT * FROM t1 WHERE s1 IN (SELECT s1 FROM t1 UNION ALL SELECT s1 FROM t2);
    
    Вместо этого запроса:
    SELECT * FROM t1 WHERE s1 IN (SELECT s1 FROM t1) OR s1 IN (SELECT s1 FROM t2);
    
    Для другого примера используйте этот запрос:
    SELECT (SELECT column1 + 5 FROM t1) FROM t2;
    
    Вместо этого запроса:
    SELECT (SELECT column1 FROM t1) + 5 FROM t2;
    
  • Используйте подзапрос строки вместо коррелированого подзапроса. Например, используйте этот запрос:
    SELECT * FROM t1 WHERE (column1,column2) IN (SELECT column1,column2 FROM t2);
    
    Вместо этого запроса:
    SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2
             WHERE t2.column1=t1.column1 AND
                   t2.column2=t1.column2);
    
  • Используйте NOT (a = ANY (...)) вместо a <> ALL (...).
  • Используйте x = ANY (таблица содержит (1,2)) вместо x=1 OR x=2.
  • Используйте = ANY вместо EXISTS.
  • Для некоррелированых подзапросов, которые всегда возвращают одну строку, IN всегда медленнее =. Например:
    SELECT * FROM t1 WHERE t1.col_name = (SELECT a
             FROM t2 WHERE b = some_const);
    
    Вместо этого запроса:
    SELECT * FROM t1 WHERE t1.col_name IN
           (SELECT a FROM t2 WHERE b = some_const);
    

Эти уловки могли бы заставить программы идти быстрее или медленнее. Используя средства MySQL, например, BENCHMARK(), Вы можете понять, что помогает в Вашей ситуации. См. раздел 13.14.

Некоторая оптимизация, которую делает сам MySQL:

  • MySQL выполняет некоррелированые подзапросы только однажды. Используйте EXPLAIN, чтобы удостовериться, что данный подзапрос действительно является некоррелированым.

  • MySQL переписывает IN, ALL, ANY и SOME в попытке использовать в своих интересах возможность, что столбцы избранного списка в подзапросе индексированы.
  • MySQL заменяет подзапросы следующей формы с функцией индекса-поиска, который EXPLAIN описывает как специальный тип соединения (unique_subquery или index_subquery ):
    ... IN (SELECT indexed_column FROM single_table ...)
    
  • MySQL улучшает выражения следующей формы с вовлечением выражения MIN() или MAX(), если значения NULL или пустые наборы вовлечены:
    value {ALL|ANY|SOME} {> | < | >= | <=}
    (uncorrelated subquery)
    
    Например, этот WHERE:
    WHERE 5 > ALL (SELECT x FROM t)
    
    мог бы быть обработан оптимизатором так:
    WHERE 5 > (SELECT MAX(x) FROM t)
    

См. также MySQL Internals: How MySQL Transforms Subqueries.

14.2.10.11. Перезапись подзапросов как соединения

Иногда есть другие способы проверить членство в ряде значений, чем использование подзапроса. Кроме того, в некоторых случаях не только возможно переписать запрос без подзапроса, но может быть более эффективно использовать некоторые из этих методов, а не использовать подзапросы. Один из них IN():

Например, этот запрос:

SELECT * FROM t1 WHERE id IN (SELECT id FROM t2);
Может быть переписан как:
SELECT DISTINCT t1.* FROM t1, t2 WHERE t1.id=t2.id;
Запросы:
SELECT * FROM t1 WHERE id NOT IN (SELECT id FROM t2);
SELECT * FROM t1 WHERE NOT EXISTS (SELECT id FROM t2 WHERE t1.id=t2.id);
Могут быть переписаны как:
SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id=table2.id
                WHERE table2.id IS NULL;
LEFT [OUTER] JOIN может быть быстрее, чем эквивалентный подзапрос, потому что сервер мог бы быть в состоянии оптимизировать это лучше. До SQL-92 не существовали внешние соединения, таким образом, подзапросы были единственным способом сделать определенные вещи. Сегодня MySQL Server и много других современных систем базы данных предлагают широкий диапазон внешних типов соединения.

MySQL Server поддерживает многотабличный DELETE, который может использоваться, чтобы эффективно удалить строки, основанные на информации от одной таблицы или даже от многих таблиц в то же самое время. Многотабличный UPDATE также поддержан. См. разделы 14.2.2 и 14.2.11.

14.2.11. UPDATE

Однотабличный вариант:

UPDATE [LOW_PRIORITY] [IGNORE] table_reference
SET col_name1={expr1|DEFAULT}
    [, col_name2={expr2|DEFAULT}] ...
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
Многотабличный вариант:
UPDATE [LOW_PRIORITY] [IGNORE] table_references
SET col_name1={expr1|DEFAULT}
    [, col_name2={expr2|DEFAULT}] ...
[WHERE where_condition]
Для однотабличного синтаксиса UPDATE обновляет столбцы существующих строк в названной таблице с новыми значениями. SET указывает, какие столбцы изменить и значения им нужно дать. Каждое значение может быть дано как выражение или ключевое слово DEFAULT, чтобы установить столбец явно в его значение по умолчанию. WHERE, если дано, определяет условия, которые идентифицируют который строки обновить. Без WHERE все строки обновлены. Если ORDER BY определен, строки обновлены в порядке, который определен. LIMIT устанавливает границу числа строк, которые могут быть обновлены.

Для многотабличного синтаксиса UPDATE строки обновлены в каждой таблице, названной в table_references, которая удовлетворяет условиям. Однажды обновлена каждая строка соответствия, даже если она соответствует условиям многократно. Для многотабличного синтаксиса ORDER BY и LIMIT не могут использоваться.

Для разделенных таблиц однотабличные и многотабличные формы этого запросы поддерживают использование PARTITION как часть табличной ссылки. Эта опция берет список из одного или более раздела или подраздела (или оба). Только перечисленный раздел (или подраздел) проверен на соответствия, и строка, которая не находится ни в одном этом разделе или подразделе, не обновлена, удовлетворяет ли она where_condition или нет.

В отличие от случая использования PARTITION с INSERT или REPLACE допустимый запрос UPDATE ... PARTITION считают успешным, даже если никакие строки в перечисленном разделе не соответствуют where_condition.

См. раздел 20.5.

where_condition выражение, которое оценивается к истине для каждой строки, которая будет обновлена. Для синтаксиса выражения см. раздел 10.5.

table_references и where_condition определены как описано в раздел 14.2.9.

Вы нуждаетесь в привилегии UPDATE только для столбцов, на которые ссылаются в UPDATE, которые фактически обновлены. Вы нуждаетесь только в привилегии SELECT для любых столбцов, которые считаны, но не изменены.

UPDATE поддерживает следующие модификаторы:

  • С LOW_PRIORITY выполнение UPDATE отсрочен, пока никакие другие клиенты не перестанут читать из таблицы. Это затрагивает только механизмы хранения, которые используют только блокировку на уровне таблицы (MyISAM, MEMORY и MERGE).

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

UPDATE IGNORE, включая тех, которые имеют ORDER BY отмечены как опасные для основанной на запросе репликации. Это потому, что порядок, в котором обновлены строки, определяет, какие строки проигнорированы. С этим изменением такие запросы производят предупреждение в журнале, используя основанный на запросе режим и зарегистрированы, используя основанный на строке формат, используя режим MIXED (Bug #11758262, Bug #50439), см. раздел 19.2.1.3.

Если Вы получаете доступ к столбцу от таблицы, которая будет обновлена в выражении, UPDATE использует текущее значение столбца. Например, следующий запрос увеличивает col1 на единицу:

UPDATE t1 SET col1 = col1 + 1;
Второе назначение устанавливает col2 к (обновленному) текущему значению col1, а не оригинальному col1. Результат: col1 и col2 имеют то же самое значение. Это поведение отличается от стандартного SQL.
UPDATE t1 SET col1 = col1 + 1, col2 = col1;
Однотабличный UPDATE вообще оценен слева направо. Для многотабличных обновлений нет никакой гарантии, что назначения выполнены в любом особом порядке.

Если Вы устанавливаете столбец в значение, которое он в настоящее время имеет, MySQL замечает это и не обновляет его.

Если Вы обновляете столбец, который был объявлен NOT NULL, устанавливая в NULL, ошибка происходит если строгий режим SQL включен, иначе столбец установлен в неявное значение по умолчанию для типа данных столбца, и количество предупреждений увеличено. Неявное значение по умолчанию 0 для числовых типов, пустая строка ('') для строковых типов и нулевое значение для типов времени и даты. См. раздел 12.7.

Если произведенный столбец обновлен явно, единственное разрешенное значение DEFAULT. Для информации о произведенных столбцах см. раздел 14.1.15.5.

UPDATE возвращает число строк, которые были фактически изменены. mysql_info() в C API возвращает число строк, которые были соответствующими и обновлены и число предупреждений, которые произошли во время UPDATE.

Вы можете использовать LIMIT row_count, чтобы ограничить контекст UPDATE. LIMIT ограничение соответствующих строк. Запрос останавливается, как только он нашел row_count строк, которые удовлетворяют WHERE, неважно, были ли они фактически изменены.

Если UPDATE запрос включает ORDER BY, строки обновлены в порядке, определенном параметром. Это может быть полезно в определенных ситуациях, которые могли бы иначе привести к ошибке. Предположите что таблица t содержит столбец id, у которого есть уникальный индекс. Следующий запрос может потерпеть неудачу с ошибкой дубликата ключа, в зависимости от порядка, в котором обновлены строки:

UPDATE t SET id = id + 1;
Например, если таблица содержит 1 и 2 в столбце id и 1 обновлен к 2 прежде, чем 2 будет обновлен к 3, ошибка происходит. Чтобы избежать этой проблемы, добавьте ORDER BY, чтобы строки с большим id были обновлены перед теми с меньшими значениями:
UPDATE t SET id = id + 1 ORDER BY id DESC;
Вы можете также использовать UPDATE , покрывающий много таблиц. Однако, Вы не можете использовать ORDER BY или LIMIT с многотабличным UPDATE. table_references перечисляет таблицы, вовлеченные в соединение. Его синтаксис описан в разделе 14.2.9.2:
UPDATE items,month SET items.price=month.price
       WHERE items.id=month.id;
Предыдущий пример показывает внутреннее соединение, которое использует оператор запятой, но многотабличный UPDATE может использовать любой тип соединения, разрешенного в SELECT, например, LEFT JOIN .

Если Вы используете многотабличный UPDATE с таблицами, для которых есть ограничения внешнего ключа, оптимизатор MySQL мог бы обработать таблицы в порядке, который отличается от нужного из их родительских/дочерних отношений. В этом случае запрос терпит неудачу и откатывается. Вместо этого обновите единственную таблицу и положитесь на ON UPDATE, который обеспечивает InnoDB , чтобы заставить другие таблицы быть измененными соответственно. См. раздел 16.8.6.

Вы не можете обновить таблицу и выбрать из той же самой таблицы в подзапросе.

В MySQL 8.0 UPDATE на разделенной таблице, используя механизм хранения с блокировками на уровне таблицы, блокирует только раздел, содержащий строки, которые соответствуют UPDATE WHERE, пока ни один из столбцов раздела не обновлен. См. Partitioning and Locking.

14.3. Транзакционные и блокирующие запросы

MySQLподдерживает местные транзакции (в пределах данного сеанса клиента) через запросы SET autocommit, START TRANSACTION, COMMIT и ROLLBACK. См раздел 14.3.1. Операционная поддержка XA позволяет MySQL участвовать в распределенных транзакциях также. См. раздел 14.3.7.

14.3.1. START TRANSACTION, COMMIT и ROLLBACK

START TRANSACTION
[transaction_characteristic [, transaction_characteristic] ...]

transaction_characteristic:
WITH CONSISTENT SNAPSHOT
  | READ WRITE
  | READ ONLY

BEGIN [WORK]
COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
SET autocommit = {0 | 1}
Эти запросы обеспечивают управление использованием транзакциями:

  • START TRANSACTION или BEGIN запустит новую транзакцию.

  • COMMIT передает текущую транзакцию, производя ее постоянные изменения.
  • ROLLBACK удаляет текущую транзакцию, отменяя ее изменения.
  • SET autocommit отключает или включает режим автозавершения транзакций для текущего сеанса.

По умолчанию MySQL выполняется с включенным autocommit. Это означает, что как только Вы выполняете запрос, который обновляет (изменяет) таблицу, MySQL хранит обновление на диске, чтобы сделать это постоянным. Изменение не может быть удалено до прежнего уровня.

Чтобы отключить режим неявно для единственного ряда запросов, используют START TRANSACTION:

START TRANSACTION;
SELECT @A:=SUM(salary) FROM table1 WHERE type=1;
UPDATE table2 SET summary=@A WHERE type=1;
COMMIT;
С START TRANSACTION autocommit остается отключенным, пока Вы не заканчиваете транзакцию COMMIT или ROLLBACK. Режим autocommit тогда возвращается в его предыдущий статус.

START TRANSACTION разрешает несколько модификаторов. Чтобы определить много модификаторов, отделите их запятыми.

  • WITH CONSISTENT SNAPSHOT запускает последовательное чтение для механизмов хранения, которые способны к нему. Это применяется только к InnoDB. Эффект тот же самый, как START TRANSACTION, сопровождаемый SELECT из любой таблицы InnoDB, см. раздел 16.5.2.3. WITH CONSISTENT SNAPSHOT не изменяет текущий операционный уровень изоляции, таким образом, это обеспечивает последовательный снимок, только если текущий уровень изоляции разрешает последовательное чтение. Единственный уровень изоляции, который разрешает последовательное чтение, это REPEATABLE READ . Для всех других уровней изоляции WITH CONSISTENT SNAPSHOT проигнорирован. Предупреждение произведено, когда WITH CONSISTENT SNAPSHOT проигнорирован.

  • READ WRITE и READ ONLY устанавливают операционный режим доступа. Они разрешают или запрещают изменения таблиц, используемых в транзакции. READ ONLY ограничение препятствует тому, чтобы транзакция изменила или заблокировала транзакционные и нетранзакционные таблицы, которые видимы другим транзакциям. Транзакция может все еще изменить или заблокировать временные таблицы.

    MySQL включает дополнительную оптимизацию для запросов на InnoDB, когда транзакция, как известно, только для чтения. Определение READ ONLY гарантирует, что эта оптимизация применена в случаях, где состояние только для чтения не может быть определено автоматически. См. раздел 9.5.3.

    Если никакой режим доступа не определен, режим по умолчанию применяется. Если значение по умолчанию не было изменено, это чтение-запись. Не разрешено определять сразу READ WRITE и READ ONLY.

    В режиме только для чтения остается возможным изменить таблицы, составленные с TEMPORARY, используя запросы DML. Изменения, произведенные запросами DDL, не разрешены, так же, как с постоянными таблицами.

    Подробности в разделе 14.3.6.

    Если включена read_only , явно запуская транзакцию с START TRANSACTION READ WRITE Вы должны иметь привилегию SUPER.

Многие API для того, чтобы написать приложения-клиенты MySQL (такие, как JDBC), обеспечивают их собственные методы для того, чтобы они начали транзакции, которые могут (и иногда должны) использоваться вместо того, чтобы послать START TRANSACTION. См. главу 25 .

Чтобы отключить режим явно:

SET autocommit=0;
После отключения autocommit установкой переменной autocommit в 0, изменения безопасных от транзакции таблиц (таких, как InnoDB или NDB) не сделаны постоянными немедленно. Вы должны использовать COMMIT, чтобы сохранить Ваши изменения нв диск, или ROLLBACK, чтобы проигнорировать все изменения.

autocommit переменная сеанса и должна быть установлена для каждого сеанса. Чтобы отключить режим для каждого нового соединения, см. описание переменной autocommit в разделе 6.1.5.

BEGIN и BEGIN WORK поддержаны как псевдонимы START TRANSACTION, который является стандартным синтаксисом SQL, рекомендуемым способ запустить транзакцию, и разрешает модификаторы, которые в BEGIN отсутствуют.

BEGIN отличается от использования ключевого слова BEGIN, которое запускает BEGIN ... END. Последний не начинает транзакцию. См. раздел 14.6.1.

В пределах всех сохраненных программ (хранимые процедуры и функции, триггеры и события), анализатор обрабатывает BEGIN [WORK] как начало BEGIN ... END. Начните транзакцию в этом контексте с START TRANSACTION.

WORK поддержано для COMMIT и ROLLBACK, как CHAIN и RELEASE. CHAIN и RELEASE могут использоваться для дополнительного управления операционным завершением. Значение переменной completion_type определяет поведение завершения по умолчанию. См. раздел 6.1.5.

AND CHAIN заставляет новую транзакцию начинаться, как только текущяя заканчивается, и у новой транзакции будет тот же самый уровень изоляции, как у только что законченной транзакции. RELEASE заставляет сервер разъединять текущий сеанс клиента после завершения текущей транзакции. Включение ключевого слова NO подавляет завершение CHAIN или RELEASE, которое может быть полезным, если переменная completion_type установлена, чтобы вызвать завершение объединения в цепочку или выпуска по умолчанию.

Начало транзакции заставляет любую транзакцию на ожидании быть переданной. См. раздел 14.3.3.

Начало транзакции также снимает табличные блокировки, приобретенные с LOCK TABLES, как если бы Вы выполнили UNLOCK TABLES. Начало транзакции не снимает глобальную блокировку чтения, приобретенную с FLUSH TABLES WITH READ LOCK.

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

  • Если Вы используете таблицы больше чем от одного безопасного для транзакции механизма хранения (такого, как InnoDB), и операционный уровень изоляции не SERIALIZABLE, возможно, что, когда одна транзакция передает, другая продолжающаяся транзакция, которая использует те же самые таблицы, будет видеть только некоторые из изменений, произведенные первой. Таким образом, валентность транзакций не гарантируется со смешанными механизмами, и могут быть несогласованности. Если транзакции смешанного механизма являются нечастыми, Вы можете использовать SET TRANSACTION ISOLATION LEVEL, чтобы установить уровень изоляции в SERIALIZABLE на основе транзакции по мере необходимости.

  • Если Вы используете таблицы, которые не безопасны для транзакции в пределах транзакции, изменения тех таблиц сохранены сразу, независимо от состояния режима autocommit.
  • Если Вы используете ROLLBACK после обновления нетранзакционной таблицы в пределах транзакции, будет предупреждение ER_WARNING_NOT_COMPLETE_ROLLBACK. Изменения безопасных для транзакции таблиц откатываются до прежнего уровня, но небезопасные для транзакции таблицы не изменяются.

Каждая транзакция сохранена в двоичном журнале в одном куске на COMMIT. Ттранзакции, которые откатились, не зарегистрированы. Исключение: Модификации нетранзакционных таблиц не могут быть отменены. Если транзакция, которая откачена, включает модификации нетранзакционных таблиц, вся транзакция зарегистрирована с ROLLBACK в конце, чтобы гарантировать, что модификации к нетранзакционным таблицам копируются. См. раздел 6.4.4.

Вы можете изменить уровень изоляции или режим доступа для транзакций с SET TRANSACTION. См. раздел 14.3.6.

Откатывание назад может быть медленной работой, которая может произойти неявно без пользователя, явно просившего этого (например, когда ошибка происходит). Из-за этого SHOW PROCESSLIST показывает Rolling back в столбце State для сеанса, не только для явных отмен, выполненных с ROLLBACK, но также и для неявных.

В MySQL 8.0 BEGIN, COMMIT и ROLLBACK не затронуты правилами --replicate-do-db или --replicate-ignore-db.

14.3.2. Запросы, которые не могут быть отменены

Некоторые запросы не могут быть отменены. Вообще, они включают язык определения данных (DDL), такие запросы, как те, которые создают или удаляют базы данных, те, которые создают, удаляют или изменяют таблицы или сохраненные подпрограммы.

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

14.3.3. Запросы, которые неявно закрывают транзакцию

Запросы, перечисленные в этом разделе (и любые синонимы для них) неявно заканчивают любую транзакцию, активную в текущем сеансе, как будто Вы сделали COMMIT прежде, чем выполнить запрос.

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

  • Запросы Data definition language (DDL), которые определяют или изменяют объекты базы данных. ALTER EVENT, ALTER FUNCTION, ALTER PROCEDURE, ALTER SERVER, ALTER TABLE, ALTER VIEW, CREATE DATABASE, CREATE EVENT, CREATE FUNCTION, CREATE INDEX, CREATE PROCEDURE, CREATE ROLE, CREATE SERVER, CREATE TABLE, CREATE TRIGGER, CREATE VIEW, DROP DATABASE, DROP EVENT, DROP FUNCTION, DROP INDEX, DROP PROCEDURE, DROP ROLE, DROP SERVER, DROP TABLE, DROP TRIGGER, DROP VIEW, INSTALL PLUGIN, RENAME TABLE, TRUNCATE TABLE и UNINSTALL PLUGIN.

    CREATE TABLE и DROP TABLE не передают транзакцию, если ключевое слово TEMPORARY используется. Это не относится к другим операциям на временных таблицах, например, ALTER TABLE и CREATE INDEX, которые действительно закрывают транзакцию. Однако, хотя не происходит неявное завершение, ни один запрос не может быть удален, что означает, что использование таких запросов заставляет транзакционную валентность быть нарушенной. Например, если Вы используете CREATE TEMPORARY TABLE, а затем отмените транзакцию, таблица остается существующей.

    CREATE TABLE в InnoDB обработан как единственная транзакция. Это означает, что ROLLBACK от пользователя не отменяет CREATE TABLE, сделанные во время этой транзакции.

    CREATE TABLE ... SELECT неявно передает прежде и после выполнения запроса, когда Вы составляете невременные таблицы. Этого не происходит для CREATE TEMPORARY TABLE ... SELECT. Это должно предотвратить проблему при репликации, где таблица могла быть составлена на ведущем устройстве после отката, но не зарегистрирована в двоичном журнале, а поэтому не копируется к ведомому устройству.

  • Запросы, которые неявно используют или изменяют таблицы в базе данных mysql. ALTER USER, CREATE USER, DROP USER, GRANT, RENAME USER, REVOKE и SET PASSWORD.
  • Операционное управление и запросы блокировки. BEGIN, LOCK TABLES, SET autocommit = 1 (если значение еще не 1), START TRANSACTION и UNLOCK TABLES.

    UNLOCK TABLES передает транзакцию, только если любые таблицы в настоящее время блокировались с LOCK TABLES, чтобы приобретать нетранзакционные табличные блокировки. Этого не происходит для UNLOCK TABLES с FLUSH TABLES WITH READ LOCK, потому что последний запрос не приобретает блокировки на уровне таблицы.

    Транзакции не могут быть вложены. Это последствие неявного закрытия, выполненного для любой текущей транзакции, когда Вы выполняете START TRANSACTION или один из его синонимов.

    Запросы, которые вызывают неявное закрытие, не могут использоваться в транзакции XA в то время, как транзакция находится в состоянии ACTIVE.

    BEGIN отличается от использования ключевого слова BEGIN, которое начинает блок BEGIN ... END. Последний не вызывает неявное закрытие. См. раздел 14.6.1.

  • Запросы загрузки данных. LOAD DATA INFILE. LOAD DATA INFILE неявно передают только для таблиц, использующих механизм хранения NDB.
  • Административные запросы. ANALYZE TABLE, CACHE INDEX, CHECK TABLE, FLUSH, LOAD INDEX INTO CACHE, OPTIMIZE TABLE, REPAIR TABLE и RESET.
  • Управление репликацией. START SLAVE, STOP SLAVE, RESET SLAVE и CHANGE MASTER TO.

14.3.4. SAVEPOINT, ROLLBACK TO SAVEPOINT и RELEASE SAVEPOINT

SAVEPOINT identifier
ROLLBACK [WORK] TO [SAVEPOINT] identifier
RELEASE SAVEPOINT identifier
InnoDB поддерживает запросы SQL SAVEPOINT, ROLLBACK TO SAVEPOINT, RELEASE SAVEPOINT и дополнительное ключевое слово WORK для ROLLBACK.

SAVEPOINT устанавливает точку сохранения с именем identifier. Если у текущей транзакции есть точка сохранения с тем же самым именем, старая удалена, новая установлена.

ROLLBACK TO SAVEPOINT откатывает транзакцию на точку сохранения, не заканчивая транзакцию. Модификации, которые текущая транзакция сделала со строками после точки сохранения, отменены, но InnoDB не снимает блокировки строки, которые были сохранены в памяти после точки. Для новой вставленной строки информацию о блокировке переносит операционное ID, сохраненное в строке, блокировка не сохранена отдельно в памяти. В этом случае блокировка строки снята при отмене. Точки, которые были установлены в более позднее время, чем названная, удалены.

Если ROLLBACK TO SAVEPOINT возвращает следующую ошибку, это означает, что никакой точки с указанным именем не существует:

ERROR 1305 (42000): SAVEPOINT identifier does not exist
RELEASE SAVEPOINT удаляет названную точку из набора точек текущей транзакции. Завершение или отмена не происходят. Это ошибка, если точка не существует.

Все точки текущей транзакции удалены, если Вы выполняете COMMIT или ROLLBACK, который не называет точку.

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

14.3.5. LOCK TABLES и UNLOCK TABLES

LOCK TABLES
tbl_name [[AS] alias] lock_type
[, tbl_name [[AS] alias] lock_type] ...
lock_type:
READ [LOCAL]
  | [LOW_PRIORITY] WRITE
UNLOCK TABLES
MySQL позволяет сеансам клиента приобрести табличные блокировки явно с целью сотрудничества с другими сеансами для доступа к таблицам, или препятствовать тому, чтобы другие сеансы изменили таблицы во время периодов, когда сеанс требует эксклюзивного доступа к ним. Сеанс может приобрести или выпустить блокировки только для себя. Один сеанс не может приобрести блокировки за другой сеанс или выпустить блокировки, проводимые другим сеансом.

Блокировки могут использоваться, чтобы подражать транзакциям или получить больше скорости, обновляя таблицы. Это объяснено более подробно позже в этом разделе.

LOCK TABLES явно приобретает табличные блокировки. Табличные блокировки могут быть приобретены для базовых таблиц или представлений. Вы должны иметь привилегии LOCK TABLES и SELECT для каждого объекта, который будет заблокирован.

Для блокировки представления LOCK TABLES добавляет все базовые таблицы, используемые в представлении, и блокирует их автоматически. Если Вы блокируете таблицу явно с LOCK TABLES, любые таблицы, используемые в триггерах, также заблокированы неявно, как описано в разделе 14.3.5.2.

UNLOCK TABLES явно снимает любые табличные блокировки текущего сеанса. LOCK TABLES неявно снимает любые табличные блокировки, проводимые текущим сеансом прежде, чем приобрести новые блокировки.

Другое использование UNLOCK TABLES должно выпустить глобальную блокировку чтения, приобретенную с запросом FLUSH TABLES WITH READ LOCK, что позволяет Вам заблокировать все таблицы во всех базах данных. См. раздел 14.7.6.3. Это очень удобный способ получить резервные копии, если у Вас есть файловая система, такая как Veritas, которая может взять снимки вовремя.

Табличная блокировка защищает только от несоответствующих чтений или записей другими сеансами. Сеанс, держащий блокировку WRITE, может выполнить на уровне таблицы такие операции, как DROP TABLE или TRUNCATE TABLE. Для сеансов, держащих блокировку READ, операции DROP TABLE и TRUNCATE TABLE не разрешены.

Следующее обсуждение применяется только к таблицам не-TEMPORARY. LOCK TABLES разрешен (но проигнорирован) для TEMPORARY. К таблице может получить доступ свободно сеанс, в пределах которого она создавалась, независимо от того, чем другая блокировка может быть в действительности. Никакая блокировка не необходима, потому что никакой другой сеанс не может видеть таблицу.

Правила для приобретения блокировки

Чтобы приобрести табличные блокировки в пределах текущего сеанса, используйте LOCK TABLES. Следующие типы блокировки доступны:

READ [LOCAL]:

  • Сеанс, который держит блокировку, может читать таблицу (но не писать ее).

  • Многократные сеансы могут приобрести блокировку READ для таблицы в то же самое время.
  • Другие сеансы могут читать таблицу, явно не приобретая блокировку READ.
  • Модификатор LOCAL позволяет не находиться в противоречии с INSERT (параллельные вставки) с другими сеансами в то время, как блокировка проводится. См. раздел 9.11.3. Однако, READ LOCAL не может использоваться, если Вы собираетесь управлять процессами использования базы данных, внешними к серверу, в то время как Вы держите блокировку. Для InnoDB READ LOCAL то же самое, что и READ.

[LOW_PRIORITY] WRITE:

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

  • Только сеанс, который держит блокировку, может получить доступ к таблице. Никакой другой сеанс не может получить доступ к этому, пока блокировка не выпущена.
  • Запрос блокировки для таблицы другим сеансом блокируется в то время, как блокировка WRITE проводится.
  • LOW_PRIORITY не имеет никакого эффекта. В предыдущих версиях MySQL это затрагивало поведение блокировки, но это больше не так. Это теперь устарело, и его использование производит предупреждение. Используйте WRITE без LOW_PRIORITY.

Если LOCK TABLES должно ждать из-за блокировок, проводимых другими сеансами на любой из таблиц, он блокируется, пока все блокировки не могут быть приобретены.

Сеанс, который требует блокировок, должен приобрести все блокировки, которые требуются в одном запросе LOCK TABLES. В то время как блокировки, полученные таким образом, проводятся, сеанс может получить доступ только к заблокированным таблицам. Например, в следующей последовательности запросов, ошибка происходит для попытки получить доступ к t2, потому что это не было заблокировано LOCK TABLES:

mysql> LOCK TABLES t1 READ;
mysql> SELECT COUNT(*) FROM t1;
+----------+
| COUNT(*) |
+----------+
| 3        |
+----------+
mysql> SELECT COUNT(*) FROM t2;
ERROR 1100 (HY000): Table 't2' was not locked with LOCK TABLES
Таблицы в INFORMATION_SCHEMA это исключение. К ним можно получить доступ, не будучи заблокированным явно даже в то время, как сеанс считает табличные блокировки полученными LOCK TABLES.

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

mysql> LOCK TABLE t WRITE, t AS t1 READ;
mysql> INSERT INTO t SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> INSERT INTO t SELECT * FROM t AS t1;
Ошибка происходит для первого INSERT ? потому что есть две ссылки на то же самое название заблокированной таблицы. Второq INSERT преуспевает, потому что ссылки на таблицу используют различные имена.

Если Ваши запросы относятся к таблице посредством псевдонима, Вы должны заблокировать таблицу, используя тот же самый псевдоним. Это не работает, чтобы заблокировать таблицу, не определяя псевдоним:

mysql> LOCK TABLE t READ;
mysql> SELECT * FROM t AS myalias;
ERROR 1100: Table 'myalias' was not locked with LOCK TABLES
Наоборот, если Вы блокируете таблицу, используя псевдоним, Вы должны обратиться к этому в Ваших запросах, используя тот псевдоним:
mysql> LOCK TABLE t AS myalias READ;
mysql> SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> SELECT * FROM t AS myalias;
Блокировка WRITE обычно имеет более высокий приоритет, чем READ, чтобы гарантировать, что обновления обработаны как можно скорее. Это означает, что если один сеанс получает блокировку READ, а затем другой сеанс просит WRITE, последующая READ ждет, пока сеанс, который просил WRITE получит блокировку и выпустит ее.

LOCK TABLES приобретает блокировки следующим образом:

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

  2. Если таблица должна быть заблокирована с блокировкой чтения и записи, поместит запрос блокировки записи перед запросом блокировки чтения.
  3. Заблокирует одну таблицу за один раз, пока сеанс не получает все блокировки.

Эта политика гарантирует, что табличная блокировка свободна от тупика.

LOCK TABLES или UNLOCK TABLES, когда относится к разделенной таблице, всегда блокирует всю таблицу, эти запросы не поддерживают блокировку разделов. См. Partitioning and Locking.

Правила для снятия блокировки

Когда табличные блокировки, проводимые сеансом, выпущены, они все освобождены в то же самое время. Сеанс может выпустить свои блокировки явно, или блокировки могут быть выпущены неявно при определенных условиях.

  • Сеанс может выпустить свои блокировки явно с UNLOCK TABLES.

  • Если сеанс сделал запрос LOCK TABLES, чтобы приобрести блокировку в то время, как имеет существующие блокировки, они выпущены неявно прежде, чем новые блокировки предоставляются.
  • Если сеанс начинает транзакцию (например, с START TRANSACTION), неявный UNLOCK TABLES выполнен, который заставляет существующие блокировки быть выпущенными. Для дополнительной информации о взаимодействии между табличной блокировкой и транзакциями см. раздел 14.3.5.1.

Если соединение для сеанса клиента заканчивается, сервер неявно выпускает все табличные блокировки, проводимые сеансом. Если клиент повторно соединится, то блокировок больше не будет. Кроме того, если у клиента была активная транзакция, сервер откатывает ее при разъединии, и если повторно соединяются, новый сеанс начинается, с включенным autocommit. Поэтому клиенты могут хотеть отключить автоатическое пересоединение. С auto-reconnect клиент не уведомлен, если повторно соединяется, но любые табличные блокировки или текущая транзакция будет потеряна. При выключенном auto-reconnect, если соединение удаляется, ошибка происходит для следующего сделанного запроса. Клиент может обнаружить ошибку и принять соответствующие меры, такие как переприобретение блокировок или восстановление транзакции. См. раздел 25.8.16.

Если Вы используете ALTER TABLE на заблокированной таблице, она может разблокироваться. Например, если Вы делаете попытку второго ALTER TABLE , результат может быть ошибкой Table 'tbl_name' was not locked with LOCK TABLES. Чтобы обработать это, заблокируйте таблицу снова до второго изменения. См. также раздел B.5.6.1.

14.3.5.1. Взаимодействие табличной блокировки и транзакций

LOCK TABLES и UNLOCK TABLES взаимодействуют с использованием транзакций следующим образом:

  • LOCK TABLES не безопасно для транзакции и неявно передает любую активную транзакцию прежде, чем попытаться заблокировать таблицы.

  • UNLOCK TABLES неявно передает любую активную транзакцию, но только если LOCK TABLES использовался, чтобы приобрести табличные блокировки. Например, в следующем наборе запросов UNLOCK TABLES выпускает глобальную блокировку чтения, но не передает транзакцию, потому что никакие табличные блокировки не работают:
    FLUSH TABLES WITH READ LOCK;
    START TRANSACTION;
    SELECT ... ;
    UNLOCK TABLES;
    
  • Начало транзакции (например, с START TRANSACTION) неявно передает любую текущую транзакцию и выпускает существующие табличные блокировки.
  • FLUSH TABLES WITH READ LOCK приобретает глобальную блокировку чтения и не приобретает табличные блокировки, таким образом, это не подвергается тому же самому поведению, как LOCK TABLES и UNLOCK TABLES относительно табличной блокировки и неявного закрытия транзакций. Например, START TRANSACTION не выпускает глобальную блокировку чтения. См. раздел 14.7.6.3.
  • Другие запросы, которые неявно заставляют транзакции быть переданными, не выпускают существующие табличные блокировки. Для списка таких запросов см. such statements, see раздел 14.3.3.
  • Правильный способ использовать LOCK TABLES и UNLOCK TABLES с транзакционными таблицами это начать транзакцию с SET autocommit = 0 (не START TRANSACTION) вместе с LOCK TABLES и не вызывать UNLOCK TABLES пока Вы не передаете транзакцию явно. Например, если Вы должны написать в таблицу t1 и читать из таблицы t2:
    SET autocommit=0;
    LOCK TABLES t1 WRITE, t2 READ, ...;
    ... do something with tables t1 and t2 here ...
    COMMIT;
    UNLOCK TABLES;
    
    Когда Вы вызываете LOCK TABLES , InnoDB внутренне берет его собственную табличную блокировку, и MySQL берет свою собственную табличную блокировку. InnoDB выпускает его внутреннюю табличную блокировку в следующей передаче транзакции, но для MySQL, чтобы выпустить его табличную блокировку, Вы должны вызвать UNLOCK TABLES . Вы не должны иметь autocommit = 1, потому что тогда InnoDB немедленно выпускает внутреннюю табличную блокировку после вызова LOCK TABLES, и тупики могут очень легко произойти. InnoDB не приобретает внутреннюю табличную блокировку вообще, если autocommit = 1, чтобы помочь старым приложениям избежать ненужных тупиков.
  • ROLLBACK не выпускает табличные блокировки.

14.3.5.2. LOCK TABLES и триггеры

Если Вы блокируете таблицу явно с LOCK TABLES, любые таблицы, используемые в триггерах, также заблокированы неявно:

  • Блокировки взяты в то же самое время, как приобретенные явно с LOCK TABLES.

  • Блокировка на таблице, используемой в триггере, зависит от того, используется ли таблица только для того, чтобы читать. Если так, блокировка чтения достаточна. Иначе используется блокировка записи.
  • Если таблица заблокирована явно для того, чтобы читать с LOCK TABLES, но надо заблокировать для записи, потому что это могло бы быть изменено в пределах триггера, блокировка записи, а не блокировка чтения реально взята. Таким образом, неявная блокировка записи необходимая из-за таблицы в пределах триггера, заставляет явный запрос блокировки чтения быть преобразованным в запрос блокировки записи.

Предположите, что Вы блокируете две таблицы, t1 и t2, с использованием этого запроса:

LOCK TABLES t1 WRITE, t2 READ;
Если t1 или t2 имеют любые триггеры, таблицы, используемые в пределах триггеров, будут также заблокированы. Предположите, что t1 имеет триггер:
CREATE TRIGGER t1_a_ins AFTER INSERT ON t1 FOR EACH ROW
BEGIN
  UPDATE t4 SET count = count+1
  WHERE id = NEW.id AND EXISTS (SELECT a FROM t3);
  INSERT INTO t2 VALUES(1, 2);
END;
Результат LOCK TABLES: t1 и t2 заблокированы, потому что они появляются в запросе, а t3 и t4 заблокированы, потому что они используются в пределах триггера:

  • t1 заблокирована для того, чтобы записать.

  • t2 заблокирована для записи, даже при том, что запрос для блокировки READ. Это происходит потому, что t2 вставлена в пределах триггера, таким образом, запрос READ преобразован в запрос WRITE.
  • t3 заблокирована для того, чтобы читать, потому что это только считано изнутри триггера.
  • t4 заблокирован для того, чтобы записать, потому что это могло бы быть обновлено в пределах триггера.

14.3.5.3. Блокирующие таблицу ограничения и условия

Вы можете безопасно использовать KILL , чтобы закончить сеанс, который ждет табличной блокировки. См. раздел 14.7.6.4.

LOCK TABLES и UNLOCK TABLES не может использоваться в пределах сохраненных программ.

Таблица в performance_schema не может быть заблокирована с LOCK TABLES, кроме таблиц setup_xxx.

Следующие запросы запрещены в то время, как LOCK TABLES работает: CREATE TABLE, CREATE TABLE ... LIKE, CREATE VIEW, DROP VIEW и запросы DDL о сохраненных функциях, процедурах и событиях.

Для некоторых операций нужно получить доступ к системным таблицам в базе данных mysql. Например, HELP требует содержания серверных таблиц справки, и CONVERT_TZ(), возможно, должен был бы считать таблицы часового пояса. Сервер неявно блокирует системные таблицы для того, чтобы читать по мере необходимости так, чтобы Вы не заблокировали их явно. Эти таблицы обработаны так:

mysql.help_category
mysql.help_keyword
mysql.help_relation
mysql.help_topic
mysql.proc
mysql.time_zone
mysql.time_zone_leap_second
mysql.time_zone_name
mysql.time_zone_transition
mysql.time_zone_transition_type
Если Вы хотите явно поместить блокировку WRITE блокируйте любую из тех таблиц с LOCK TABLES, таблица должна быть единственной заблокированной, никакая другая таблица не может быть заблокирована с тем же самым запросом.

Обычно Вы не должны заблокировать таблицы, потому что весь UPDATE атомный, никакой другой сеанс не может вмешаться ни в какой другой в настоящее время выполняющийся запрос SQL. Однако, есть несколько случаев, когда блокировка таблиц может обеспечить преимущество:

  • Если Вы собираетесь выполнить много операций на ряде таблиц MyISAM, намного быстрее заблокировать таблицы, которые Вы собираетесь использовать. Блокировка MyISAM ускоряют вставку, обновление или удаление на них, потому что MySQL не сбрасывает ключевой кэш для заблокированных таблиц до UNLOCK TABLES. Обычно ключевой кэш сбрасывается после каждого запроса SQL.

    Никакой сеанс не может обновить заблокированную как READ таблица (включая тот, который держит блокировку), и никакой сеанс не может получить доступ к заблокированной как WRITE таблице кроме держащего блокировку.

  • Если Вы используете таблицы для нетранзакционного механизма хранения, Вы должны использовать LOCK TABLES , если Вы хотите гарантировать, что никакой другой сеанс не изменяет таблицы между SELECT и UPDATE. Пример, показанный здесь, требует LOCK TABLES, чтобы выполнять безопасно:
    LOCK TABLES trans READ, customer WRITE;
    SELECT SUM(value) FROM trans WHERE customer_id=some_id;
    UPDATE customer SET total_value=sum_from_previous_statement
           WHERE customer_id=some_id;
    UNLOCK TABLES;
    
    Без LOCK TABLES возможно, что другой сеанс мог бы вставить новую строку в таблицу trans между SELECT и UPDATE.

Вы можете избегать использования LOCK TABLES во многих случаях при использовании относительных обновлений (UPDATE customer SET value=value+ new_value) или функции LAST_INSERT_ID() .

Вы можете также избежать блокировать таблицы в некоторых случаях при использовании консультативных функций блокировки на уровне пользователя GET_LOCK() и RELEASE_LOCK(). Эти блокировки сохранены в хэш-таблице в сервере и осуществлены с pthread_mutex_lock() и pthread_mutex_unlock(), см. раздел 13.18.

См. раздел 9.11.1.

14.3.6. SET TRANSACTION

SET [GLOBAL | SESSION] TRANSACTION
transaction_characteristic [, transaction_characteristic] ...

transaction_characteristic:
ISOLATION LEVEL level
  | READ WRITE
  | READ ONLY

level:
REPEATABLE READ
   | READ COMMITTED
   | READ UNCOMMITTED
   | SERIALIZABLE
Это запрос определяет параметры транзакции. Это берет список из одного или более значений, отделенных запятыми. Эти характеристики устанавливают операционный уровень изоляции или режим доступа. Уровень изоляции используется для операций на InnoDB. Режим доступа может быть определен относительно того, работают ли транзакции в чтении-записи или режиме только для чтения.

Кроме того, SET TRANSACTION может включать дополнительный параметр GLOBAL или SESSION, чтобы указать на контекст запроса.

Контекст операционных характеристик

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

  • С GLOBAL запрос применяется глобально для всех последующих сеансов. Существующие сеансы не затронуты.

  • С SESSION запрос относится ко всем последующим транзакциям, выполненным в пределах текущего сеанса.
  • Без SESSION или GLOBAL запрос относится к следующей транзакции, выполненной в пределах текущего сеанса. Последующие транзакции возвращаются к использованию уровня изоляции SESSION.

Глобальное изменение операционных характеристик требует привилегии SUPER. Любой сеанс свободен изменить свои характеристики сеанса (даже в середине транзакции) или характеристики для следующей транзакции.

SET TRANSACTION без GLOBAL или SESSION не разрешен, в то время как есть активная транзакция:

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.02 sec)

mysql> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ERROR 1568 (25001): Transaction characteristics can't be changed
while a transaction is in progress
Чтобы установить глобальный уровень изоляции по умолчанию при запуске сервера, используйте опцию --transaction-isolation=level для mysqld в командной строке или в файле опции. Значения level для этой опции используют тире, а не пробелы, таким образом, допустимые значения READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ или SERIALIZABLE . Например, чтобы установить уровень изоляции по умолчанию в REPEATABLE READ , используйте эти строки в разделе [mysqld] файла опций:
[mysqld]
transaction-isolation = REPEATABLE-READ
Возможно проверить или установить глобальные и операционные уровни изоляции сеанса во времени выполнения при использовании tx_isolation:
SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
SET GLOBAL tx_isolation='REPEATABLE-READ';
SET SESSION tx_isolation='SERIALIZABLE';
Точно так же, чтобы установить операционный режим доступа при запуске сервера или во время выполнения, используйте --transaction-read-only или tx_read_only. По умолчанию они OFF (режим чтение-запись), но могут быть установлен в ON для режима по умолчанию только для чтения.

Установка глобального значения или значения сеанса tx_isolation или tx_read_only эквивалентно установке уровня изоляции или режима доступа с SET GLOBAL TRANSACTION или SET SESSION TRANSACTION.

Операционные уровни изоляции

См. раздел 16.5.2.1.

Операционный режим доступа

Операционный режим доступа может быть определен с SET TRANSACTION. По умолчанию, транзакция имеет место в режиме чтения-записи с чтениями и записями, разрешенными для таблиц, используемых в транзакции. Этот режим может быть определен, явно используя режим доступа READ WRITE.

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

Не разрешено определить в том же самом запросе READ WRITE и READ ONLY.

В режиме только для чтения остается возможным изменить таблицы, составленные с TEMPORARY, используя запросы DML. Изменения, произведенные с запросами DDL, не разрешены, так же, как с постоянными таблицами.

READ WRITE и READ ONLY также могут быть определены для отдельной транзакции, используя START TRANSACTION.

14.3.7. Транзакции XA

Поддержка транзакций XA доступна для InnoDB. MySQL XA основан на X/Open CAE Distributed Transaction Processing: The XA Specification. Этот документ издан The Open Group и доступен на http://www.opengroup.org/public/pubs/catalog/c193.htm. Ограничения текущего выполнения XA описаны в раздел C.6.

На стороне клиента нет никаких особых требований. Интерфейс XA к серверу MySQL состоит из запросов SQL, которые начинаются с XA. Программы клиента MySQL должны быть в состоянии послать запросы SQL и понять семантику интерфейса запросов XA.

Среди MySQL Connectors, MySQL Connector/J 5.0.0 и выше понимает XA непосредственно, посредством интерфейса класса, который обрабатывает интерфейс XA SQL для Вас.

XA поддерживает распределенные транзакции, то есть, способность разрешить многократным отдельным транзакционным ресурсам участвовать в глобальной транзакции. Транзакционные ресурсы часто RDBMS, но могут быть другими видами ресурсов.

Глобальная транзакция вовлекает несколько действий, которые являются транзакционными в себе, но что все должны завершиться успешно как группа или все быть откаченными как группа. В основном это расширяет свойства ACID так, чтобы многократные транзакции могли быть выполнены как компоненты глобальной работы, у которой также есть свойства ACID. Как с нераспределенными транзакциями, SERIALIZABLE может быть предпочтен, если Ваши приложения чувствительны, чтобы считать явления. REPEATABLE READ , возможно, не достаточно для распределенных транзакций.

Некоторые примеры распределенных транзакций:

  • Приложение может действовать как инструмент интеграции, который комбинирует службу обмена сообщениями с RDBMS. Приложение удостоверяется, что транзакции, имеющие дело с посылкой сообщения, извлечением и обработкой, которые также вовлекают транзакционную базу данных, все происходят в глобальной транзакции. Вы можете думать об этом как о транзакционной email.

  • Приложение выполняет действия, которые вовлекают различные серверы базы данных, такие как сервер MySQL и сервер Oracle (или несколько серверов MySQL), где действия, которые вовлекают многократные серверы, должны произойти как часть глобальной транзакции, а не как отдельные транзакции, местные для каждого сервера.
  • Банк хранит информацию учетной записи в RDBMS, распределяет и получает деньги через банкоматы (торговые автоматы). Необходимо гарантировать, что действия торгового автомата правильно отражены в учетных записях, но это не может быть сделано с один RDBMS. Глобальный менеджер по транзакции объединяет торговый автомат и ресурсы базы данных, чтобы гарантировать полную последовательность финансовых операций.

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

  • Resource Manager (RM) обеспечивает доступ к транзакционным ресурсам. Сервер базы данных это один вид распорядителя ресурсов. Должно быть возможно передать или удалить транзакции, которыми управляет RM.

  • Transaction Manager (TM) координирует транзакции, которые являются частью глобальной транзакции. Это общается с RM, которые обрабатывают каждую из этих транзакций. Отдельные транзакции в пределах глобальной транзакции это части глобальной транзакции. Глобальные транзакции и их ответвления идентифицированы схемой именования, описанной позже.

Выполнение MySQL XA позволяет серверу MySQL действовать как Resource Manager, который обрабатывает транзакции XA в пределах глобальной транзакции. Программа клиента, которая соединяется с действиями сервера MySQL как менеджер по транзакции.

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

Процесс для того, чтобы выполнить глобальную транзакцию использует двухфазовую передачу (2PC). Это имеет место после того, как действия, выполненные ответвлениями глобальной транзакции, были выполнены.

  1. В первой фазе подготовлены все ответвления. Таким образом, им говорит ТМ подготовиться передавать. Как правило, это означает каждый RM, который справляется, ответвление делает запись действий для ответвления в устойчивом хранении. Ответвления указывают, в состоянии ли они сделать это, и эти результаты используются для второй фазы.

  2. Во второй фазе ТМ говорит RM передать или откатиться. Если все ответвления указали, когда они были подготовлены, что они будут в состоянии передать, всем ответвлениям говорят передать. Если какое-либо ответвление указало, когда оно было подготовлено, что оно не будет в состоянии передать, всем ответвлениям говорят откатиться.

В некоторых случаях глобальная транзакция могла бы использовать одну фазу передачи (1PC). Например, когда менеджер по транзакции находит, что глобальная транзакция состоит только из одного транзакционного ресурса (то есть, единственное ответвление), ресурсу можно сказать подготовить и передать в то же самое время.

14.3.7.1. Синтаксис XA SQL

Чтобы выполнить транзакции XA в MySQL, используйте следующие запросы:

XA {START|BEGIN} xid [JOIN|RESUME]
XA END xid [SUSPEND [FOR MIGRATE]]
XA PREPARE xid
XA COMMIT xid [ONE PHASE]
XA ROLLBACK xid
XA RECOVER [CONVERT XID]
Для XA START JOIN и RESUME не поддержаны.

Для XA END SUSPEND [FOR MIGRATE] не поддержан.

Каждый запрос XA начинается XA и большинство из них требуют значения xid. xid это операционный идентификатор XA. Это указывает, к какой транзакции запрос относится. xid поставляются клиентом или произведены сервером MySQL. xid имеет от одной до трех частей:

xid: gtrid [,
bqual [, formatID ]]
gtrid это глобальный операционный идентификатор, bqual спецификатор ответвления, и formatID число, которое идентифицирует формат, используемый gtrid и bqual. Как обозначено синтаксисом, bqual и formatID являются дополнительными. Значение по умолчанию bqual '', если не дано. Значение по умолчанию formatID 1, если не дано.

gtrid и bqual должны быть строками, каждая до 64 байтов (не символов). gtrid и bqual может быть определен несколькими способами. Вы можете использовать заключенную в кавычки строку ('ab'), шестнадцатеричную строку (X'6162', 0x6162) или битовое значение (b'nnnn').

formatID unsigned integer.

gtrid и bqual интерпретируются в байтах основными подпрограммами поддержки XA сервера MySQL. Однако, в то время, как запрос SQL, содержащмй запрос XA, разбирается, сервер работает с некоторым определенным набором символов. Чтобы быть безопасным, пишите gtrid и bqual как шестнадцатеричные строки.

xid, как правило, производятся менеджером по транзакции. Значения, произведенные одним ТМ, должны отличаться от значений, произведенных другими ТМ. Данный ТМ должен быть в состоянии признать свой собственный xid в списке значений, возвращенных XA RECOVER.

Для XA START xid запускает транзакцию XA с данным значением xid. У каждой транзакции XA должно быть уникальное значение xid, таким образом, значение не должно в настоящее время использоваться другой транзакцией XA. Уникальность оценена, используя gtrid и bqual. Все последующие запросы XA для транзакции XA должны быть определены, используя то же самое значение XA START. Если Вы используете какое-либо из тех запросов, но определяете xid, которое не соответствует некоторой существующей транзакции XA, ошибка происходит.

Одна или более транзакций XA могут быть частью той же самой глобальной транзакции. Все транзакции XA в пределах данной глобальной транзакции должны использовать то же самое значение gtrid в xid. Поэтому значения gtrid должны быть глобально уникальными так, чтобы не было никакой двусмысленности. bqual часть xid должна отличаться для каждой транзакции XA в пределах глобальной транзакции. Требование, что значения bqual должны отличаться, является ограничением текущего MySQL-выполнения XA. Это не часть спецификации XA.

XA RECOVER возвращает информацию для тех транзакций XA на сервере MySQL, которые находятся в состоянии PREPARED, см. раздел 14.3.7.2. Вывод включает строку для каждой такой транзакции XA на сервере, независимо от того, который клиент запустил это.

XA RECOVER выходные строки похожи на это (для примера xid состоит из частей 'abc', 'def' и 7):

mysql> XA RECOVER;
+----------+--------------+--------------+--------+
| formatID | gtrid_length | bqual_length | data   |
+----------+--------------+--------------+--------+
| 7        | 3            | 3            | abcdef |
+----------+--------------+--------------+--------+
У выходных столбцов есть следующие значения:

  • formatID часть formatID xid транзакции.

  • gtrid_length длина в байтах gtrid.
  • bqual_length длина в байтах bqual.
  • data конкатенация gtrid и bqual.

XID могут содержать непригодные для печати символы. XA RECOVER разрешает дополнительный параметр CONVERT XID так, чтобы клиенты могли просить значения XID в шестнадцатеричном виде.

14.3.7.2. Операционные состояния XA

Транзакция XA прогрессирует через следующие состояния:

  1. Используйте XA START, чтобы запустить транзакцию XA и перевести в статус ACTIVE.

  2. Для ACTIVE транзакций XA сделайте запросы SQL, которые составляют транзакцию, а затем XA END. XA END отправит транзакцию в состояние IDLE.
  3. Для IDLE транзакций XA Вы можете скомандовать XA PREPARE или XA COMMIT ... ONE PHASE:

    • XA PREPARE отправит транзакцию в состояние PREPARED. XA RECOVER будет включать xid транзакции в его выводе, потому что XA RECOVER перечисляет все транзакции XA, которые находятся в состоянии PREPARED.

    • XA COMMIT ... ONE PHASE готовит и передает транзакцию. xid не будет перечислено XA RECOVER потому что транзакция заканчивается.

  4. Для PREPARED XA транзакций Вы можете скомандовать XA COMMIT, чтобы передать и закончить транзакцию, или XA ROLLBACK для отката.

Вот простая транзакция XA, которая вставляет строку в таблицу как часть глобальной транзакции:

mysql> XA START 'xatest';
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO mytable (i) VALUES(10);
Query OK, 1 row affected (0.04 sec)

mysql> XA END 'xatest';
Query OK, 0 rows affected (0.00 sec)

mysql> XA PREPARE 'xatest';
Query OK, 0 rows affected (0.00 sec)

mysql> XA COMMIT 'xatest';
Query OK, 0 rows affected (0.00 sec)
В пределах контекста данного соединения клиента транзакции XA и местные транзакции (не-XA) являются взаимоисключающими. Например, если XA START выпущен, чтобы начать транзакцию XA, местная транзакция не может быть запущена, пока транзакция XA не была передана или отменена. Наоборот, если местная транзакция была запущена с START TRANSACTION, никакие запросы XA не могут использоваться, пока транзакция не была передана или отменена.

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

ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed
when global transaction is in the ACTIVE state
Запросы, к которым применяется предыдущее замечание, перечислены в разделе 14.3.3.

14.4. Запросы репликации

Репликацией можно управлять через интерфейс SQL, используя запросы, описанные в этом разделе. Запросы разделены на группу, которая управляет главными серверами, группу, которая управляет ведомыми серверами, и группу, которая может быть применена к любым серверам.

14.4.1. Запросы SQL для управления главными серверами

Этот раздел обсуждает запросы для основных серверов.

В дополнение к запросым, описанным здесь, запросы SHOW используются с главными серверами. Для информации об этих запросах см. раздел 14.7.5.

14.4.1.1. PURGE BINARY LOGS

PURGE { BINARY | MASTER } LOGS
{ TO 'log_name' | BEFORE datetime_expr }
Двоичный журнал это ряд файлов, которые содержат информацию о модификациях данных, сделанных сервером MySQL. Журнал состоит из ряда двоичных файлов системного журнала плюс индексный файл (см. раздел 6.4.4).

PURGE BINARY LOGS удаляет все двоичные файлы системного журнала, перечисленные в индексном файле журнала до указанного имени файла системного журнала или даты. BINARY и MASTER синонимы. Удаленные файлы системного журнала также удалены из списка, зарегистрированного в индексном файле, так, чтобы данный файл системного журнала стал первым в списке.

Этот запрос не имеет никакого эффекта, если сервер не был запущен с опцией --log-bin.

Примеры:

PURGE BINARY LOGS TO 'mysql-bin.010';
PURGE BINARY LOGS BEFORE '2008-04-02 22:46:26';
BEFORE разновидность параметра datetime_expr должен оцениваться к значению DATETIME (значение в формате 'YYYY-MM-DD hh:mm:ss').

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

Чтобы безопасно произвести чистку двоичных файлов системного журнала, следуйте за этой процедурой:

  1. На каждом ведомом сервере надо использовать SHOW SLAVE STATUS, чтобы проверить, какой файл системного журнала это читает.

  2. Получите перечисление двоичных файлов системного журнала на главном сервере с помощью SHOW BINARY LOGS .
  3. Определите самый ранний файл системного журнала среди всех ведомых устройств. Это конечный файл. Если все ведомые устройства современны, это последний файл системного журнала в списке.
  4. Сделайте резервное копирование всех файлов системного журнала, которые Вы собираетесь удалить. Этот шаг является дополнительным, но всегда желательным.
  5. Произведите чистку всех файлов системного журнала до, но не включая конечный файл.

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

PURGE BINARY LOGS TO и PURGE BINARY LOGS BEFORE оба терпят неудачу с ошибкой, когда двоичные файлы системного журнала, перечисленные в файле .index, были удалены из системы некоторыми другими средствами (такими, как использование rm в Linux) (Bug #18199, Bug #18453). Чтобы обработать такие ошибки, редактируйте файл .index (который является простым текстовым файлом) вручную, чтобы гарантировать, что он перечисляет только двоичные файлы системного журнала, которые фактически присутствуют, затем выполните снова PURGE BINARY LOGS.

14.4.1.2. RESET MASTER

RESET MASTER
Удаляет все двоичные файлы системного журнала, перечисленные в индексном файле, сбрасывает двоичной индексный файл журнала и создает новый двоичной файл системного журнала.

RESET MASTER также очищает значения gtid_purged так же как глобальное значение gtid_executed (но не ее значение сеанса), то есть, выполнение этого запроса устанавливает каждое из этих значений к пустой строке (''). Этот запрос также очищает таблицу mysql.gtid_executed (см. mysql.gtid_executed Table).

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

Эффекты RESET MASTER отличаются от таковых в PURGE BINARY LOGS:

  1. RESET MASTER удаляет все двоичные файлы системного журнала, которые перечислены в индексном файле, оставляя только единственный пустой двоичной файл системного журнала с числовым суффиксом .000001, тогда как нумерация не сброшена PURGE BINARY LOGS.

  2. RESET MASTER не предназначен, чтобы использоваться, в то время как любые ведомые устройства работают. Поведение RESET MASTER когда используется в то время, как ведомые устройства работают, неопределено (и таким образом неподдержано), тогда как PURGE BINARY LOGS может безопасно использоваться в то время, как ведомые устройства работают.

См. раздел 14.4.1.1.

RESET MASTER может оказаться полезным, когда Вы сначала настраиваете ведущее и ведомое устройства, чтобы Вы могли проверить установку следующим образом:

  1. Запустите ведущее и ведомое устройства и запустите репликацию (см. раздел 19.1.2).

  2. Выполните несколько испытательных запросов на ведущем устройстве.
  3. Проверьте, что запросы копировались к ведомому устройству.
  4. Когда репликация работает правильно, скомандуйте STOP SLAVE и RESET SLAVE на ведомом устройстве, затем проверьте, что любые нежелательные данные больше не существуют на ведомом устройстве.
  5. Скомандуйте RESET MASTER на ведущем устройстве, чтобы очистить испытательные запросы.

После подтверждения установки и избавления от файлов системного журнала, произведенных в ходе проверки, Вы можете запустить ведомое устройство и начать копировать.

14.4.1.3. SET sql_log_bin

SET sql_log_bin = {0|1}
sql_log_bin управляет, сделано ли журналирование к двоичному журналу. Значение по умолчанию 1 (сделано журналирование). Чтобы изменить журналирование для текущего сеанса, измените значение этой переменной. Пользователь сеанса должен иметь привилегию SUPER , чтобы установить эту переменную. Установите эту переменную в 0 для сеанса, чтобы временно отключить двоичное журналирование, производя изменения в ведущем устройстве, которые Вы не хотите копировать к ведомому устройству.

С MySQL 5.5 sql_log_bin может быть установлен как глобальная переменная или переменная сеанса. Установка sql_log_bin глобально обнаружена только, когда новый сеанс запущен. На любые ранее работающие сеансы глобальная установка не воздействует.

Неправильное использование sql_log_bin с глобальными средствами контекста любые изменения, произведенные в уже рабочем сеансе все еще регистрируются в двоичном журнале и поэтому копируются. Это может вызвать неожиданные результаты, включая отказ репликации.

В MySQL 5.7 невозможно установить @@session.sql_log_bin в пределах транзакции или подзапроса (Bug #53437).

14.4.2. Запросы SQL для управления ведомыми серверами

В дополнение к запросам, описанным здесь, SHOW SLAVE STATUS и SHOW RELAYLOG EVENTS также используются с ведомыми устройствами ответа. Для информации об этих запросах см. разделы 14.7.5.34 и 14.7.5.32.

14.4.2.1. CHANGE MASTER TO

CHANGE MASTER TO option [, option]
       ... [ channel_option ]
option:
MASTER_BIND = 'interface_name'
  | MASTER_HOST = 'host_name'
  | MASTER_USER = 'user_name'
  | MASTER_PASSWORD = 'password'
  | MASTER_PORT = port_num
  | MASTER_CONNECT_RETRY = interval
  | MASTER_RETRY_COUNT = count
  | MASTER_DELAY = interval
  | MASTER_HEARTBEAT_PERIOD = interval
  | MASTER_LOG_FILE = 'master_log_name'
  | MASTER_LOG_POS = master_log_pos
  | MASTER_AUTO_POSITION = {0|1}
  | RELAY_LOG_FILE = 'relay_log_name'
  | RELAY_LOG_POS = relay_log_pos
  | MASTER_SSL = {0|1}
  | MASTER_SSL_CA = 'ca_file_name'
  | MASTER_SSL_CAPATH = 'ca_directory_name'
  | MASTER_SSL_CERT = 'cert_file_name'
  | MASTER_SSL_CRL = 'crl_file_name'
  | MASTER_SSL_CRLPATH = 'crl_directory_name'
  | MASTER_SSL_KEY = 'key_file_name'
  | MASTER_SSL_CIPHER = 'cipher_list'
  | MASTER_SSL_VERIFY_SERVER_CERT = {0|1}
  | MASTER_TLS_VERSION = 'protocol_list'
  | IGNORE_SERVER_IDS = (server_id_list)

channel_option:
FOR CHANNEL channel

server_id_list:
[server_id [, server_id] ... ]
CHANGE MASTER TO изменяет параметры, которые ведомый сервер использует для того, чтобы соединиться с главным сервером, для того, чтобы считать основной двоичной журнал и считать ведомый журнал. Это также обновляет содержание основной информации и репозитариев информации журнала (см. раздел 19.2.4).

Можно использовать CHANGE MASTER TO запрос о рабочем ведомом устройстве без остановки этого, в зависимости от статуса ведомого потока SQL и ведомого потока ввода/вывода. Правила, управляющие таким использованием, обеспечены позже в этом разделе.

Используя мультипоточное ведомое устройство (другими словами, slave_parallel_workers больше 0), остановка ведомого устройства может вызвать промежутки в последовательности транзакций, которые были выполнены от журнала, независимо от того, было ли ведомое устройство остановлено преднамеренно или нет. Когда такие промежутки существуют, CHANGE MASTER TO терпит неудачу. Решение в этой ситуации состоит в том, чтобы вызвать START SLAVE UNTIL SQL_AFTER_MTS_GAPS , который гарантирует, что разрывы преодолены.

FOR CHANNEL channel позволяет Вам выбрать, к которому каналу ответа относится запрос. Если никакой пункт не установлен, и никакие дополнительные каналы не существуют, запрос относится к каналу значения по умолчанию и ведет себя как версии MySQL до 5.7.6. Обеспечение FOR CHANNEL channel применяет CHANGE MASTER TO к определенному каналу ответа и используется, чтобы добавить новый канал или изменить существующий канал. Например, чтобы добавить новый канал, названный channel2:

CHANGE MASTER TO MASTER_NAME=host1, MASTER_PORT=3002 FOR CHANNEL channel2
Используя многократные каналы ответа, если у CHANGE MASTER TO нет определенного использования канала FOR CHANNEL channel , получите ошибку. См. раздел 19.2.3.

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

MASTER_HOST, MASTER_USER, MASTER_PASSWORD и MASTER_PORT предоставляют информацию ведомому устройству о том, как соединиться с его ведущим устройством:

  • MASTER_HOST и MASTER_PORT имя хоста (или IP-адрес) основного узла и его порта TCP/IP.

    Репликация не может использовать файлы сокета Unix. Вы должны быть в состоянии соединиться с сервером ведущего устройства, используя TCP/IP.

    Если Вы определяете MASTER_HOST или MASTER_PORT, ведомое устройство предполагает, что главный сервер отличается (даже если значение опции то же самое, как текущее). В этом случае старые значения для имени файла основного двоичного системного журнала и позиции больше не считают применимыми, так, если Вы не определяете MASTER_LOG_FILE и MASTER_LOG_POS в команде, MASTER_LOG_FILE='' и MASTER_LOG_POS=4 тихо приложены к этому.

    Установка MASTER_HOST='' (то есть, устанавливая его значение явно в пустую строку) не то же самое, как не установка MASTER_HOST вообще. Начиная с MySQL 5.5, попытка установить MASTER_HOST к пустой строке терпит неудачу с ошибкой. Ранее установка MASTER_HOST к пустой строке вызывала впоследствии сбой START SLAVE (Bug #28796).

    Значения, используемые для MASTER_HOST и других опций CHANGE MASTER TO проверены на перевод строки (\n или 0x0A), присутствие таких символов в этих значениях заставляет запрос терпеть неудачу с ER_MASTER_INFO (Bug #11758581, Bug #50801).

  • MASTER_USER и MASTER_PASSWORD имя пользователя и пароль учетной записи, чтобы использовать для того, чтобы соединиться с ведущим устройством.

    MASTER_USER не может быть сделан пустым, установка MASTER_USER = '' вызывает ошибку (Bug #13427949).

    Пароль используется для ведомой учетной записи MySQL Replication в CHANGE MASTER TO ограничен 32 символами в длину, попытка использовать пароль больше 32 символов приведет к сбою CHANGE MASTER TO.

    До MySQL 5.7.5, если пароль был более длинным, запрос работал, но любые лишние символы было тихо усечены.

    Текст выполнения CHANGE MASTER TO, включая значения для MASTER_USER и MASTER_PASSWORD, может быть виден в выводе параллельного SHOW PROCESSLIST. Полный текст START SLAVE также видим в SHOW PROCESSLIST .

Опции MASTER_SSL_xxx предоставляют информацию об использовании SSL для соединения. Они соответствуют опциям --ssl-xxx, описанным в разделах 7.4.5 и 19.3.9. Эти опции могут быть изменены даже на ведомых устройствах, которые собраны без поддержки SSL. Они сохранены к основному репозитарию информации, но проигнорированы, если у ведомого устройства нет поддержки SSL.

MASTER_SSL=1 является предписывающим, не консультативным. Когда дано, соединение с ведущим устройством должно использовать SSL, или попытка соединения терпит неудачу.

MASTER_TLS_VERSION определяет протоколы шифрования, разрешенные ведущим устройством для ведомых соединений. Значение походит на это для tls_version: список разделенных запятой значений, содержащий одно или более имен протокола. Протоколы, которые могут быть названы в этой опции, зависят от библиотеки SSL, использовавшейся, чтобы собрать MySQL. Для деталей см. раздел 7.4.3.

MASTER_CONNECT_RETRY определяет, сколько секунд ждать между повторениями соединения. Значение по умолчанию 60.

MASTER_RETRY_COUNT ограничивает number число попыток пересоединения и обновляет значение столбца Master_Retry_Count в выводе SHOW SLAVE STATUS. Значение по умолчанию 24 * 3600 = 86400. MASTER_RETRY_COUNT предназначена, чтобы заменить более старую опцию --master-retry-count и является теперь привилегированным методом для того, чтобы установить этот предел. Лучше не использовать --master-retry-count в новых приложениях и, обновляясь до MySQL 8.0, обновить любые существующие приложения, которые полагаются на это, так, чтобы они использовали CHANGE MASTER TO ... MASTER_RETRY_COUNT.

MASTER_DELAY определяет, на сколько секунд от ведущего устройства ведомое устройство должно отстать. Событие от ведущего устройства не запущено, по крайней мере, interval секунд. Значение по умолчанию 0. Ошибка происходит, если interval не неотрицательное целое число в диапазоне от 0 до 231-1. См. раздел 19.3.11.

CHANGE MASTER TO, использующий опцию MASTER_DELAY может быть выполнен на рабочем ведомом устройстве, когда ведомый поток SQL остановлен.

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

Адрес, сконфигурированный с этой опцией, если таковой вообще имеется, может быть найден в столбце Master_Bind вывода SHOW SLAVE STATUS. Если Вы используете ведомые таблицы журнала состояния (сервер запускался с --master-info-repository=TABLE), значение может также быть найдено как столбец Master_bind таблицы mysql.slave_master_info .

MASTER_HEARTBEAT_PERIOD устанавливает интервал в секундах между тактами репликации. Всякий раз, когда двоичной журнал ведущего устройства обновлен, время ожидания для следующего такта сброшено. interval это десятичное значение, имеющее диапазон от 0 до 4294967 секунд и разрешение в миллисекунду, самое маленькое ненулевое значение 0.001. Такты посылает ведущее устройство, только если нет никаких непосланных событий в двоичном файле системного журнала в течение периода дольше interval.

Если Вы регистрируете основную информацию о соединении к таблицам, MASTER_HEARTBEAT_PERIOD может быть замечен как значение столбца Heartbeat таблицы mysql.slave_master_info.

Установка interval к 0 отключает такты вообще. Значение по умолчанию для interval равно значению slave_net_timeout , разделенному на 2.

Установка @@global.slave_net_timeout к значению меньше текущего интервала приводит к предупреждению. Эффект RESET SLAVE на интервал должен сбросить это к значению по умолчанию.

MASTER_LOG_FILE и MASTER_LOG_POS координаты, в которых ведомый поток ввода/вывода должен начать читать от ведущего устройства в следующий раз, когда поток запускается. RELAY_LOG_FILE и RELAY_LOG_POS координаты, в которых ведомый поток SQL должен начать читать из журнала реле в следующий раз, когда поток запускается. Если Вы определяете любой из MASTER_LOG_FILE или MASTER_LOG_POS, Вы не можете определить RELAY_LOG_FILE или RELAY_LOG_POS. Если Вы определяете любой из MASTER_LOG_FILE или MASTER_LOG_POS, Вы также не можете определить MASTER_AUTO_POSITION = 1 (описан позже в этом разделе). Если ни один из MASTER_LOG_FILE или MASTER_LOG_POS не определен, ведомое устройство использует последние координаты ведомого потока SQL перед CHANGE MASTER TO. Это гарантирует, что нет никакой неоднородности в ответе, даже если ведомый поток SQL был позже по сравнению с ведомым потоком ввода/вывода, когда Вы просто хотите изменить, скажем, пароль.

CHANGE MASTER TO, использующий опции RELAY_LOG_FILE, RELAY_LOG_POS или обе сразу, может быть выполнен на рабочем ведомом устройстве, когда ведомый поток SQL остановлен.

Если MASTER_AUTO_POSITION = 1 с CHANGE MASTER TO , ведомое устройство пытается соединиться с ведущим устройством, использующим протокол GTID. Эта опция может использоваться CHANGE MASTER TO только, если ведомый SQL и ведомые потоки ввода/вывода остановлены.

Используя GTID, ведомое устройство говорит ведущему устройству, какие транзакции это уже приняло, выполнило или то и другое. Чтобы вычислить этот набор, это читает глобальное значение gtid_executed и значение столбца Retrieved_gtid_set из SHOW SLAVE STATUS. Так как GTID последней переданной транзакции включен в Retrieved_gtid_set, даже если транзакция была только частично передана, последний полученный GTID вычтен из этого набора. Таким образом, ведомое устройство вычисляет следующий набор:

UNION(@@global.gtid_executed, Retrieved_gtid_set-last_received_GTID)
Этот набор посылают ведущему устройству как часть начального квитирования, а ведущее устройство отсылает назад все транзакции, которые выполнило, но которые не являются частью набора. Если какая-либо из этих транзакций была уже удалена из двоичного журнала ведущего устройства, ведущее устройство посылает ошибку ER_MASTER_HAS_PURGED_REQUIRED_GTIDS, и репликация не запускается.

Когда GTID-репликация используется, координаты, представленные MASTER_LOG_FILE и MASTER_LOG_POS не используются, и глобальные операционные идентификаторы используются вместо этого. Таким образом использование обеих опций вместе с MASTER_AUTO_POSITION будет ошибкой.

Вы можете видеть, работает ли ответ с автопозиционированием, проверяя вывод SHOW SLAVE STATUS.

gtid_mode должен также быть включен перед CHANGE MASTER TO ... MASTER_AUTO_POSITION = 1. Иначе запрос терпит неудачу с ошибкой.

Чтобы вернуться к более старому основанному на файле протоколу после использования GTID, Вы можете скомандовать CHANGE MASTER TO, который определяет MASTER_AUTO_POSITION = 0, так же как по крайней мере один из MASTER_LOG_FILE или MASTER_LOG_POSITION.

Журналы реле сохранены, когда ни ведомый поток SQL, ни ведомый поток ввода/вывода не остановлены, если оба потока остановлены, все файлы системного журнала реле не удалены, если Вы указали по крайней мере одну из опций RELAY_LOG_FILE или RELAY_LOG_POS.

RELAY_LOG_FILE может использовать абсолютный или относительный путь, и использует то же самое базовое имя, как MASTER_LOG_FILE (Bug #12190).

IGNORE_SERVER_IDS берет список разделенных запятой значений из 0 или больше ID сервера. События, происходящие из соответствующих серверов, проигнорированы, за исключением событий ротации и удаления журнала, которые все еще зарегистрированы в журнале реле.

В круговой репликации оригинальный сервер обычно действует как разделитель его собственных событий, чтобы они не были применены не раз. Таким образом, эта опция полезна в круговой рпликации, когда один из серверов удален. Предположите, что у Вас есть круговая установка репликации с 4 серверами, ID 1, 2, 3 и 4, а сервер 3 упал. Соединяя промежуток, запуская репликацию с сервера 2 на сервер 4, Вы можете включить IGNORE_SERVER_IDS = (3) в CHANGE MASTER TO на сервере 4, чтобы сказать этому использовать сервер 2 в качестве его ведущего устройства вместо сервера 3. Это причина проигнорировать, а не размножить любые запросы, которые произошли с сервером, который больше не находится в использовании.

Если CHANGE MASTER TO без IGNORE_SERVER_IDS, любой существующий список сохранен. Чтобы очистить список проигнорированных серверов, необходимо использовать опцию с пустым списком:

CHANGE MASTER TO IGNORE_SERVER_IDS = ();
RESET SLAVE ALL очищает IGNORE_SERVER_IDS. До MySQL 5.7 это не сделано.

Если IGNORE_SERVER_IDS содержит ID сервера, и сервер был запущен с --replicate-same-server-id, будет ошибка.

В MySQL 8.0 основной репозитарий информации и вывод SHOW SLAVE STATUS обеспечивает список серверов, которые в настоящее время игнорируются. Для получения дополнительной информации см. разделы 19.2.4.2 и 14.7.5.34.

В MySQL 8.0 вызов CHANGE MASTER TO вызывает запись предыдущих значений MASTER_HOST, MASTER_PORT, MASTER_LOG_FILE и MASTER_LOG_POS в журнал ошибок, наряду с другой информацией о статусе ведомого устройства до выполнения.

В MySQL 8.0 CHANGE MASTER TO неявно закрывает продолжающиеся транзакции. См. раздел 14.3.3.

Строгое требование, чтобы выполнить STOP SLAVE до любого CHANGE MASTER TOSTART SLAVE позже) удалено. Вместо этого, в зависимости от того, остановлено ли ведомое устройство, логика CHANGE MASTER TO зависит от статуса ведомого потока SQL и ведомых потоков ввода/вывода, какой из этих потоков остановлен или работает, теперь определяют опции, которые могут или не могут использоваться с CHANGE MASTER TO в данном моменте времени. Правила для того, чтобы сделать это определение перечислены здесь:

  • Если поток SQL остановлен, Вы можете выполнить CHANGE MASTER TO с использованием любой комбинации, которая допускается RELAY_LOG_FILE, RELAY_LOG_POS и MASTER_DELAY, даже если ведомый поток ввода/вывода работает. Никакие другие опции не могут использоваться с этим запросом, когда поток ввода/вывода работает.

  • Если поток ввода/вывода остановлен, Вы можете выполнить CHANGE MASTER TO с использованием любой из опций для этого запросы (в любой позволенной комбинации) кроме RELAY_LOG_FILE, RELAY_LOG_POS или MASTER_DELAY, даже когда поток SQL работает. Эти три опции не могут использоваться, когда поток ввода/вывода работает.
  • Поток SQL и поток ввода/вывода должны быть остановлены прежде, чем скомандовать CHANGE MASTER TO, который использует MASTER_AUTO_POSITION = 1.

Вы можете проверить текущее состояние ведомого SQL и потоков ввода/вывода с использованием SHOW SLAVE STATUS.

См. раздел 19.3.8.

Если Вы используете основанную на запросе репликацию и временные таблицы, это возможно для CHANGE MASTER TO после STOP SLAVE оставить позади временные таблицы на ведомом устройстве. Предупреждение (ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO ) теперь выпущено всякий раз, когда это происходит. Вы можете избежать этого удостоверяясь, что значение Slave_open_temp_tables = 0 до выполнения такого CHANGE MASTER TO.

CHANGE MASTER TO полезно для установки ведомого устройства, когда Вы имеете снимок ведущего устройства и сделали запись основных двоичных координат журнала, соответствующих времени снимка. После загрузки снимка в ведомое устройство, чтобы синхронизировать это с ведущим устройством, Вы можете выполнить CHANGE MASTER TO MASTER_LOG_FILE='log_name', MASTER_LOG_POS=log_pos на ведомом устройстве, чтобы определить координаты, в которых ведомое устройство должно начать читать основной двоичной журнал.

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

CHANGE MASTER TO MASTER_HOST='master2.mycompany.com',
       MASTER_USER='replication', MASTER_PASSWORD='bigs3cret',
       MASTER_PORT=3306, MASTER_LOG_FILE='master2-bin.001',
       MASTER_LOG_POS=4, MASTER_CONNECT_RETRY=10;
Следующий пример показывает работу, которая менее часто используется. Это используется, когда у ведомого устройства есть файлы системного журнала реле, которые Вы хотите, чтобы это выполнило снова по некоторым причинам. Вы должны использовать только CHANGE MASTER TO и запустите поток SQL (START SLAVE SQL_THREAD ):
CHANGE MASTER TO RELAY_LOG_FILE='slave-relay-bin.006',
       RELAY_LOG_POS=4025;
Вы можете даже использовать вторую операцию в установке без репликации с автономным, неведомым, сервером для восстановления после катастрофического отказа. Предположите, что Ваш сервер отказал, и Вы восстановили его из резервной копии. Вы хотите переиграть собственные двоичные файлы системного журнала сервера (не файлы системного журнала реле, а регулярные двоичные файлы системного журнала), названные (например) myhost-bin.*. Во-первых, сделайте резервную копию этих двоичных файлов системного журнала в некотором безопасном месте, в случае, если Вы точно не следуете за процедурой ниже и случайно имеете чистку двоичного журнала сервера. Используйте SET GLOBAL relay_log_purge=0 для дополнительной безопасности. Тогда запустите сервер без опции --log-bin, вместо этого используйте --replicate-same-server-id, --relay-log=myhost-bin (чтобы заставить сервер полагать, что эти регулярные двоичные файлы системного журнала это файлы системного журнала реле), и --skip-slave-start. После того, как сервер запускается, сделайте эти запросы:
CHANGE MASTER TO RELAY_LOG_FILE='myhost-bin.153',
       RELAY_LOG_POS=410, MASTER_HOST='some_dummy_string';
       START SLAVE SQL_THREAD;
Сервер читает и выполняет свои собственные двоичные файлы системного журнала, таким образом достигая восстановления катастрофического отказа. Как только восстановление закончено, выполните STOP SLAVE, закройте сервер, очистите основную информацию и репозитарии информации журнала реле, и перезапустите сервер с его оригинальными опциями.

Определение MASTER_HOST (даже с фиктивным значением) обязано заставлять сервер думать, что это ведомое устройство.

Следующая таблица показывает максимальную допустимую длину строк опций.

ОпцияМаксимальная длина
MASTER_HOST60
MASTER_USER16
MASTER_PASSWORD32
MASTER_LOG_FILE255
RELAY_LOG_FILE255
MASTER_SSL_CA255
MASTER_SSL_CAPATH255
MASTER_SSL_CERT255
MASTER_SSL_CRL255
MASTER_SSL_CRLPATH255
MASTER_SSL_KEY255
MASTER_SSL_CIPHER511

14.4.2.2. CHANGE REPLICATION FILTER

CHANGE REPLICATION FILTER filter[, filter][, ...]
filter:
REPLICATE_DO_DB = (db_list)
  | REPLICATE_IGNORE_DB = (db_list)
  | REPLICATE_DO_TABLE = (tbl_list)
  | REPLICATE_IGNORE_TABLE = (tbl_list)
  | REPLICATE_WILD_DO_TABLE = (wild_tbl_list)
  | REPLICATE_WILD_IGNORE_TABLE = (wild_tbl_list)
  | REPLICATE_REWRITE_DB = (db_pair_list)
db_list:
db_name[, db_name][, ...]
tbl_list:
db_name.table_name[, db_table_name][, ...]
wild_tbl_list:
'db_pattern.table_pattern'[, 'db_pattern.table_pattern'][, ...]
db_pair_list:
(db_pair)[, (db_pair)][, ...]
db_pair:
from_db, to_db
CHANGE REPLICATION FILTER определяет один или более фильтров на ведомом устройстве таким же образом, как при запуске ведомого устройства mysqld с опциями фильтрации --replicate-do-db или --replicate-wild-ignore-table. В отличие от случая с параметрами сервера, этот запрос не требует перезапуска сервера, чтобы вступить в силу, только чтобы ведомый поток SQL был остановлен, используя STOP SLAVE SQL_THREAD (и перезапущен через START SLAVE SQL_THREAD).

Следующий список показывает опции CHANGE REPLICATION FILTER, и как они касаются параметров сервера --replicate-*:

  • REPLICATE_DO_DB: Включить обновления, основанные на имени базы данных. Эквивалент --replicate-do-db.

  • REPLICATE_IGNORE_DB: Исключить обновления, основанные на имени базы данных. Эквивалент --replicate-ignore-db.
  • REPLICATE_DO_TABLE: Включить обновления, основанные на имени таблицы. Эквивалент --replicate-do-table.
  • REPLICATE_IGNORE_TABLE: Исключить обновления, основанные на имени таблицы. Эквивалент --replicate-ignore-table.
  • REPLICATE_WILD_DO_TABLE: Включить обновления, основанные на на подстановочном образце, соответствующем имени таблицы. Эквивалент --replicate-wild-do-table.
  • REPLICATE_WILD_IGNORE_TABLE: Исключить обновления, основанные на на подстановочном образце, соответствующем имени таблицы. Эквивалент --replicate-wild-ignore-table.
  • REPLICATE_REWRITE_DB: Выполнить обновления на ведомом устройстве после замены новым именем на ведомом устройстве для указанной базы данных по ведущему устройству. Эквивалент --replicate-rewrite-db.

Точные эффекты REPLICATE_DO_DB и REPLICATE_IGNORE_DB зависят от того, основана репликация на запросе или на строке в действительности. См. раздел 19.2.5 .

Многократные правила фильтрации ответа могут быть созданы в одном запросе CHANGE REPLICATION FILTER , отделяя правила запятыми, как показано здесь:

CHANGE REPLICATION FILTER
       REPLICATE_DO_DB = (d1), REPLICATE_IGNORE_DB = (d2);
Это эквивалентно запуску ведомого устройства mysqld с опциями --replicate-do-db=d1 и --replicate-ignore-db=d2.

Если то же самое правило фильтрации определено многократно, только последнее такое правило фактически используется. Например, эти два запросы, показанные здесь, имеют точно тот же самый эффект, потому что первое правило REPLICATE_DO_DB в первом запросе проигнорировано:

CHANGE REPLICATION FILTER
       REPLICATE_DO_DB = (db1, db2), REPLICATE_DO_DB = (db3, db4);
CHANGE REPLICATION FILTER REPLICATE_DO_DB = (db3,db4);

Это поведение отличается от поведения из опции фильтра --replicate-*, где определение той же самой опции много раз вызывает создание многократных правил фильтра.

Названия таблиц и базы данных, не содержащих любых специальных символов, не должны быть заключены в кавычки. Значения, используемые с REPLICATION_WILD_TABLE и REPLICATION_WILD_IGNORE_TABLE это строковые выражения, возможно, содержащие (специальные) подстановочные символы, и должны быть заключены в кавычки. Это показывают в следующих запросах в качестве примера:

CHANGE REPLICATION FILTER REPLICATE_WILD_DO_TABLE = ('db1.old%');
CHANGE REPLICATION FILTER
       REPLICATE_WILD_IGNORE_TABLE = ('db1.new%', 'db2.new%');
Значения, используемые с REPLICATE_REWRITE_DB это пары имен базы данных, каждое такое значение должно быть приложено в круглых скобках. Следующий запрос переписывает запросы, происходящие в базе данных dbA в базу данных dbB:
CHANGE REPLICATION FILTER REPLICATE_REWRITE_DB = ((db1, db2));
Запрос содержит два набора круглых скобок, один включает пару имен базы данных, другой весь список. Это более легко видно в следующем примере, который создает два правила rewrite-db, одно переписывает база данных dbA в dbB, второе переписывает базу данных dbC в dbD:
CHANGE REPLICATION FILTER
       REPLICATE_REWRITE_DB = ((dbA, dbB), (dbC, dbD));
Этот запрос оставляет любые существующие правила фильтрации неизменными, чтобы сбросить все фильтры данного типа, установите значение фильтра в явно пустой список, как показано в этом примере, который удаляет все существующие правила REPLICATE_DO_DB и REPLICATE_IGNORE_DB:
CHANGE REPLICATION FILTER
       REPLICATE_DO_DB = (), REPLICATE_IGNORE_DB = ();
Установка фильтра таким образом удаляет все существующие правила, не создает новых и не восстанавливает набор правил при использовании запуска mysqld с опциями --replicate-*.

Значения, используемые с REPLICATE_WILD_DO_TABLE и REPLICATE_WILD_IGNORE_TABLE, должны быть в формате db_name.tbl_name.

См. раздел 19.2.5.

14.4.2.3. MASTER_POS_WAIT()

SELECT MASTER_POS_WAIT('master_log_file',
master_log_pos [, timeout][,
channel])
Это фактически функция, не запрос. Это используется, чтобы гарантировать, что ведомое устройство считало и запустило события до данной позиции в двоичном журнале ведущего устройства. См. раздел 13.18.

14.4.2.4. RESET SLAVE

RESET SLAVE [ALL] [channel_option]
channel_option:
FOR CHANNEL channel
RESET SLAVE заставляет ведомое устройство забыть свою позицию в двоичном журнале ведущего устройства. Этот запрос предназначается для чистого запуска: это очищает основную информацию и репозитарии информации журнала реле, удаляет все файлы системного журнала реле и запускает новый файл системного журнала реле. Это также сбрасывает к 0 задержку, определенную опцией MASTER_DELAY в CHANGE MASTER TO. Чтобы использовать RESET SLAVE, ведомые потоки должны быть остановлены (с использованием STOP SLAVE в случае необходимости).

Все файлы системного журнала реле удалены, даже если они не были полностью выполнены ведомым потоком SQL. Это условие, чтобы существовать на ведомом устройстве ответа, если Вы выполнили STOP SLAVE или если ведомое устройство чрезвычайно загружено.

Опция FOR CHANNEL channel позволяет Вам выбрать, к которому каналу ответа относится запрос. Если никакой пункт не установлен, и никакие дополнительные каналы не существуют, запрос относится к каналу по умолчанию и ведет себя как версии MySQL до 5.7.6. Обеспечение FOR CHANNEL channel применяет RESET SLAVE к определенному каналу. Объединение FOR CHANNEL channel с опцией ALL удаляет указанный канал. RESET SLAVE ALL без FOR CHANNEL channel, когда многократные каналы существуют, удаляет все каналы и обновляет только канал по умолчанию. См. раздел 19.2.3.

RESET SLAVE не изменяет параметров соединения, таких как основной узел, порт, пользователь или пароль, которые сохранены в памяти. Это означает, что START SLAVE может быть выпущен, не требуя CHANGE MASTER TO с RESET SLAVE.

Параметры соединения сброшены RESET SLAVE ALL. RESET SLAVE сопровождаемый перезапуском ведомого устройства mysqld также делает это.

В MySQL 8.0 RESET SLAVE неявно закрывает транзакции. См. раздел 14.3.3.

Если ведомый поток SQL был в середине мультиплицирования временных таблиц, когда это было остановлено, и RESET SLAVE выпущен, эти копируемые временные таблицы удалены на ведомом устройстве.

До MySQL 5.7.5 RESET SLAVE также имеет эффект сброса обоих периодов такта ( Slave_heartbeat_period) и SSL_VERIFY_SERVER_CERT. Эта проблема исправлена в MySQL 5.7.5 и позже (Bug #18777899, Bug #18778485).

RESET SLAVE ALL очищает список IGNORE_SERVER_IDS, установленный CHANGE MASTER TO.

14.4.2.5. SET GLOBAL sql_slave_skip_counter

SET GLOBAL sql_slave_skip_counter = N
Этот запрос пропускает следующие N событий от ведущего устройства. Это полезно для восстановления от остановок, вызванных запросом.

Этот запрос допустим только, когда ведомые потоки не работают. Иначе это производит ошибку.

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

  • Для транзакционных таблиц группа событий соответствует транзакции.

  • Для нетранзакционных таблиц группа событий соответствует единственному запросу SQL.

Единственная транзакция может содержать изменения транзакционных и нетранзакционных таблиц.

Когда Вы используете SET GLOBAL sql_slave_skip_counter, чтобы пропускать события, и результат находится в середине группы, ведомое устройство продолжает пропускать события, пока это не достигает конца группы. Выполнение тогда запускается со следующей группы событий.

14.4.2.6. START SLAVE

START SLAVE [thread_types] [until_option]
[connection_options] [channel_option]
thread_types:
[thread_type [, thread_type] ... ]
thread_type:
IO_THREAD | SQL_THREAD
until_option:
UNTIL {{SQL_BEFORE_GTIDS | SQL_AFTER_GTIDS} = gtid_set
  |  MASTER_LOG_FILE = 'log_name', MASTER_LOG_POS = log_pos
  |  RELAY_LOG_FILE = 'log_name', RELAY_LOG_POS = log_pos
  |  SQL_AFTER_MTS_GAPS  }

connection_options:
[USER='user_name'] [PASSWORD='user_pass']
[DEFAULT_AUTH='plugin_name']
[PLUGIN_DIR='plugin_dir']
channel_option:
FOR CHANNEL channel
gtid_set:
uuid_set [, uuid_set] ... | ''
uuid_set:
uuid:interval[:interval]...
uuid:
hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh
h: [0-9,A-F]
interval:
n[-n]
(n >= 1)
START SLAVE без thread_type запускает оба ведомых потока. Поток ввода/вывода читает события из главного сервера и хранит их в журнале реле. Поток событий SQL читает из журнала реле и выполняет их. START SLAVE требует привилегии SUPER.

Если START SLAVE преуспевает в том, чтобы запустить ведомые потоки, это возвращается без ошибки. Однако, даже в этом случае, могло бы случиться так, что ведомые потоки запускаются и затем останавливаются позже (например, потому что им не удается соединиться с ведущим устройством или считать двоичной журнал). START SLAVE не предупреждает Вас об этом. Вы должны проверить журнал ошибок ведомого устройства на сообщения об ошибках, произведенные ведомыми потоками, или проверить, что они работают удовлетворительно с помощью SHOW SLAVE STATUS.

START SLAVE неявно передает продолжающиеся транзакции. См. раздел 14.3.3.

gtid_next должен быть установлен в AUTOMATIC прежде, чем сделать этот запрос.

FOR CHANNEL channel позволяет Вам выбрать, к которому каналу ответа относится запрос. Если не установлен, и никакие дополнительные каналы не существуют, запрос относится к каналу по умолчанию и ведет себя как MySQL до 5.7.6. Обеспечение FOR CHANNEL channel применяет START SLAVE к определенному каналу. Если START SLAVE не определяли канал, используя многократные каналы, это запрос запускает указанные потоки для всех каналов. Этот запрос отвергнут для канала group_replication_recovery. См. раздел 19.2.3.

MySQL 8.0 поддерживает аутентификацию пользовательского пароля с START SLAVE с параметрами USER, PASSWORD, DEFAULT_AUTH и PLUGIN_DIR, как описано в следующем списке:

  • USER: Имя пользователя. Не может быть установлено в пустую строку, если использован PASSWORD.

  • PASSWORD: Пароль.
  • DEFAULT_AUTH: Имя плагина, по умолчанию это встроенная аутентификация MySQL.
  • PLUGIN_DIR: Местонахождение плагина.

Вы не можете использовать SQL_THREAD, определяя любой из параметров USER, PASSWORD, DEFAULT_AUTH или PLUGIN_DIR, если IO_THREAD также предоставлена.

См. раздел 7.3.9.

Если опасное соединение используется с какими-либо этими опциями, сервер выдает предупреждение Sending passwords in plain text without SSL/TLS is extremely insecure.

START SLAVE ... UNTIL поддерживает две дополнительных опции для использования с глобальными операционными идентификаторами (GTID) (см. раздел 19.1.3). Каждая из них берет один или более глобальных операционных идентификаторов gtid_set как аргумент.

Когда не определен thread_type, START SLAVE UNTIL SQL_BEFORE_GTIDS заставляет ведомый поток SQL обрабатывать транзакции, пока он не достигнет первой транзакции, GTID которой перечислен в gtid_set. START SLAVE UNTIL SQL_AFTER_GTIDS заставляет ведомые потоки обрабатывать все транзакции до последней транзакции в gtid_set. Другими словами, START SLAVE UNTIL SQL_BEFORE_GTIDS заставляет ведомый поток SQL обрабатывать все транзакции, происходящие перед первым GTID в gtid_set, а START SLAVE UNTIL SQL_AFTER_GTIDS заставляет ведомые потоки обрабатывать все транзакции, включая те, GTID которых найдены в gtid_set, пока не столкнутся с транзакцией, GTID которой не часть набора. SQL_BEFORE_GTIDS и SQL_AFTER_GTIDS поддерживают опции SQL_THREAD и IO_THREAD, хотя использование IO_THREAD с ними в настоящее время не имеет никакого эффекта.

Например, START SLAVE SQL_THREAD UNTIL SQL_BEFORE_GTIDS = 3E11FA47-71CA-11E1-9E33-C80AA9429562:11-56 заставляет ведомый поток SQL обрабатывать все транзакции, происходящие от ведущего устройства, чей server_uuid 3E11FA47-71CA-11E1-9E33-C80AA9429562, пока это не сталкивается с транзакцией, имеющей порядковый номер 11, это тогда останавливается, не обрабатывая эту транзакцию. Другими словами, все транзакции до и включая транзакцию с порядковым номером 10 обработаны. Выполнение START SLAVE SQL_THREAD UNTIL SQL_AFTER_GTIDS = 3E11FA47-71CA-11E1-9E33-C80AA9429562:11-56 с другой стороны заставил бы ведомый поток SQL получать все транзакции от ведущего устройства, включая все транзакции, имеющие порядковые номера 11-56, а затем останавливаться, не обрабатывая дополнительных транзакций, то есть, транзакция, имеющая порядковый номер 56, была бы последней транзакцией, принесенной ведомым потоком SQL.

Используя мультипоточное ведомое устройство, есть шанс промежутков в последовательности транзакций, которые выполнены от реле. Это следующие случаи:

  • Уничтожение потока координатора.

  • После того, как ошибка происходит в рабочих потоках.
  • mysqld закрывается неожиданно.

Используйте START SLAVE UNTIL SQL_AFTER_MTS_GAPS, чтобы заставить потоки мультипоточного ведомого устройства работать только до промежутков в журнале реле, и затем остановиться. Этот запрос может взять опцию SQL_THREAD, но эффект запроса остается неизменным. Это не имеет никакого эффекта на ведомый поток ввода/вывода (и не может использоваться с IO_THREAD).

START SLAVE на мультипоточном ведомом устройстве с промежутками в последовательности транзакций, выполненных от журнала, производит предупреждение. В такой ситуации решение состоит в том, чтобы использовать START SLAVE UNTIL SQL_AFTER_MTS_GAPS, затем RESET SLAVE, чтобы удалить любые остающиеся журналы реле. См. раздел 19.4.1.34.

Чтобы изменить неудавшееся мультипоточное ведомое устройство единственного дерева сообщений, Вы можете выпустить следующий ряд запросов в показанном порядке:

START SLAVE UNTIL SQL_AFTER_MTS_GAPS;
SET @@GLOBAL.slave_parallel_workers = 0;
START SLAVE SQL_THREAD;

Возможно рассмотреть весь текст выполнения START SLAVE ..., включая любые значения USER или PASSWORD, в выводе SHOW PROCESSLIST. Это также верно для текста выполнения CHANGE MASTER TO, включая любые значения MASTER_USER или MASTER_PASSWORD.

START SLAVE посылает признание пользователю после того, как поток ввода/вывода и поток SQL запустились. Однако, поток ввода/вывода еще, возможно, не соединился. Поэтому успешный START SLAVE показывает в SHOW SLAVE STATUS Slave_SQL_Running=Yes, но это не гарантирует, что Slave_IO_Running=Yes (поскольку Slave_IO_Running=Yes только, если поток ввода/вывода работает и соединен). Для получения дополнительной информации см. разделы 14.7.5.34 и 19.1.7.1.

Вы можете добавить опции IO_THREAD и SQL_THREAD, чтобы назвать, который из потоков запустить. Опция SQL_THREAD отвергнута, определяя любой из параметров USER, PASSWORD, DEFAULT_AUTH или PLUGIN_DIR, если опция IO_THREAD задана.

UNTIL (until_option в предыдущей грамматике) может быть добавлен, чтобы определить, что ведомое устройство должно запуститься и работать, пока поток SQL не достигает данной точки в основном двоичном журнале, определенной опциями MASTER_LOG_POS и MASTER_LOG_FILE, или пункта в ведомом журнале реле, обозначенного опциями RELAY_LOG_POS и RELAY_LOG_FILE. Когда поток SQL достигает определенной точки, это останавливается. Если опция SQL_THREAD определена в запросе, она запускает только поток SQL. Иначе, это запускает оба ведомых потока. Если поток SQL работает, UNTIL проигнорирован, и предупреждение выпущено. Вы не можете использовать UNTIL с опцией IO_THREAD.

Также возможно с START SLAVE UNTIL определить остановку относительно данного GTID или набора GTID с использованием одной из опций SQL_BEFORE_GTIDS или SQL_AFTER_GTIDS, как объяснено ранее в этом разделе. Используя одну из этих опций, Вы можете определить SQL_THREAD, IO_THREAD, оба из них, или ни один из них. Если Вы определяете только SQL_THREAD, тогда только ведомый поток SQL затронут запросом, если только IO_THREAD используется, тогда только ведомый поток ввода/вывода затронут. Если используются оба SQL_THREAD и IO_THREAD , или если ни один из них не используется, то потоки SQL и ввода/вывода затронуты запросом.

UNTIL не поддержан для мультипоточных ведомых устройств кроме тех случаев, когда также используется SQL_AFTER_MTS_GAPS.

Для UNTIL Вы должны определить любое из следующего:

  • Имя файла системного журнала и позицию в этом файле.

  • SQL_BEFORE_GTIDS или SQL_AFTER_GTIDS.
  • SQL_AFTER_MTS_GAPS

Не смешивайте ведущее устройство и опции журнала реле. Не смешивайте опции файла системного журнала с опциями GTID.

Любое условие UNTIL сброшено последующим STOP SLAVE, START SLAVE, который не включает UNTIL, или перезапуском сервера.

Определяя файл системного журнала и позицию, Вы можете использовать IO_THREAD с START SLAVE ... UNTIL даже при том, что только поток SQL затронут этим запросом. Опция IO_THREAD проигнорирована в таких случаях. Предыдущее ограничение не применяется, используя одну из опций GTID (SQL_BEFORE_GTIDS и SQL_AFTER_GTIDS), опции GTID поддерживают обоих SQL_THREAD и IO_THREAD, как объяснено ранее в этом разделе.

UNTIL может быть полезным для того, чтобы отладить репликацию. Например, если неблагоразумный DROP TABLE был выполнен на ведущем устройстве, Вы можете использовать UNTIL, чтобы сказать ведомому устройству выполнять до того пункта, но не дальше. Чтобы найти событие, используйте mysqlbinlog с основным двоичным журналом или ведомым журналом реле, или используйте SHOW BINLOG EVENTS.

Если Вы используете UNTIL, чтобы ведомый процесс копировал запросы в разделах, рекомендуется, чтобы Вы запустили ведомое устройство с опцией --skip-slave-start , чтобы препятствовать тому, чтобы поток SQL работал, когда ведомый сервер запускается. Вероятно, лучше использовать эту опцию в файле опций, а не в командной строке, чтобы неожиданный перезапуск сервера не заставил это забыть.

SHOW SLAVE STATUS включает выходные поля, которые выводят на экран текущее значение UNTIL.

В очень старых версиях MySQL (перед 4.0.5) этот запрос назывался SLAVE START. В MySQL 8.0 этот синтаксис производит ошибку.

14.4.2.7. STOP SLAVE

STOP SLAVE [thread_types]
thread_types:
[thread_type [, thread_type] ... ]
thread_type: IO_THREAD | SQL_THREAD
channel_option:
FOR CHANNEL channel
Останавливает ведомые потоки. STOP SLAVE требует привилегию SUPER. Рекомендуемая практика должна выполнить STOP SLAVE на ведомом устройстве прежде, чем остановить ведомый сервер (см. раздел 6.1.12.

Используя основанный на строке формат журналирования : Вы должны выполнить STOP SLAVE или STOP SLAVE SQL_THREAD на ведомом устройстве до закрытия ведомого сервера, если Вы копируете какие-либо таблицы, которые используют нетранзакционной механизм хранения.

Как START SLAVE, этот запрос может использоваться с IO_THREAD и SQL_THREAD, чтобы назвать поток или потоки, которые будут остановлены.

В MySQL 8.0 STOP SLAVE неявно передает продолжающиеся транзакции. См. раздел 14.3.3.

gtid_next должен быть установлен в AUTOMATIC прежде, чем сделать это запрос.

Вы можете управлять, сколько времени STOP SLAVE ждет перед синхронизацией, устанавливая rpl_stop_slave_timeout. Это может использоваться, чтобы избежать тупиков между STOP SLAVE и другими ведомыми запросами SQL, используя различные соединения клиента с ведомым устройством.

Некоторые запросы CHANGE MASTER TO позволены в то время, как ведомое устройство работает, в зависимости от статуса ведомого SQL и потоков ввода/вывода. Однако, использование STOP SLAVE до выполнения CHANGE MASTER TO в таких случаях все еще поддержано. См. разделы 14.4.2.1 и 19.3.8.

FOR CHANNEL channel позволяет Вам выбрать, к которому каналу относится запрос. Если никакой пункт не установлен, и никакие дополнительные каналы не существуют, запрос относится к каналу по умолчанию и ведет себя как версии MySQL до 5.7. Обеспечение FOR CHANNEL channel применяет STOP SLAVE к определенному каналу. Если STOP SLAVE не определяли канал, используя многократные каналы, этот запрос останавливает указанные потоки для всех каналов. Этот запрос не может использоваться с каналом group_replication_recovery. См. раздел 19.2.3.

Используя основанную на запросе репликацию: изменение ведущего устройства, в то время как у этого есть открытые временные таблицы, потенциально опасно. Это одна из причин, почему основанная на запросе репликация временных таблиц не рекомендуется. Вы можете узнать, есть ли какие-либо временные таблицы на ведомом устройстве, проверяя значение Slave_open_temp_tables, используя основанную на запросе репликацию, это значение должно быть 0 перед выполнением CHANGE MASTER TO. Если есть какие-либо временные таблицы, открытые на ведомом устройстве, CHANGE MASTER TO после STOP SLAVE вызовет предупреждение ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO.

Используя мультипоточное ведомое устройство ( slave_parallel_workers не 0), любые разрывы в последовательности транзакций, выполненных от журнала реле, преодолены как часть остановки рабочего потока. Если ведомое устройство неожиданно остановлено (например из-за ошибки в рабочем потоке) в то время, как STOP SLAVE выполняется, последовательность выполненных транзакций от журнала реле может стать непоследовательной. См. раздел 19.4.1.34.

В MySQL 8.0 STOP SLAVE ждет, пока текущая группа событий, затрагивающая одну или более нетранзакционных таблиц, не закончит выполняться (если есть какая-либо такая группа) или не будет команды KILL QUERY или KILL CONNECTION (Bug #319, Bug #38205).

14.4.3. Запросы SQL для управления группами репликации

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

14.4.3.1. START GROUP_REPLICATION

START GROUP_REPLICATION
Запускает группу репликации.

14.4.3.2. STOP GROUP_REPLICATION

STOP GROUP_REPLICATION
Останваливает группу репликации.

14.5. Подготовленные запросы SQL

MySQL 8.0 оказывает поддержку для подготовленных запросов стороны сервера. Эта поддержка использует эффективный протокол двоичной синхронной передачи данных клиент-сервер. Использование готовые запросы с заполнителями для параметра значения обладает следующими преимуществами:

  • Меньше издержек, чтобы разобрать запрос каждый раз. Как правило, приложения базы данных обрабатывают большие объемы почти идентичных запросов только изменениями с переменных значений в таких пунктах, как WHERE для запросов и удалений и VALUES для вставок.

  • Защита от атак с использованием кода на SQL. Значения параметра могут содержать неоставленную кавычку SQL и символы-разделители.

Готовые запросы в приложениях

Вы можете использовать подготовленные запросы стороны сервера через клиента, программирующего интерфейсы, включая MySQL C API client library или MySQL Connector/C для C-программ, MySQL Connector/J для Java и MySQL Connector/Net для .NET. Например, C API обеспечивает ряд вызовов функций, которые составляют готовый запрос API. См. раздел 25.8.8. Другие языковые интерфейсы могут оказать поддержку для готовых запросов, которые используют протокол двоичной синхронной передачи данных в библиотеке клиента C, один пример, mysqli extension, доступен в PHP 5.0 и выше.

Готовые запросы в скриптах SQL

Альтернативный интерфейс SQL к готовым запросам доступен. Этот интерфейс не столь же эффективен, как использование протокола двоичной синхронной передачи данных через готовый запрос, но не требует никакого программирования, потому что это доступно непосредственно на уровне SQL:

  • Вы можете использовать это, когда никакой программный интерфейс не доступен Вам.

  • Вы можете использовать это из любой программы, которая может послать запрос SQL серверу, который будет выполнен, такие как mysql.
  • Вы можете использовать это, даже если клиент использует старую версию библиотеки клиента, пока Вы соединяетесь с выполнением сервера MySQL 4.1 или выше.

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

  • Проверить, как готовые запросы работают в Вашем приложении прежде, чем кодировать это.

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

PREPARE, EXECUTE и DEALLOCATE PREPARE

Синтаксис SQL для готовых запросов основан на трех запросах SQL:

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

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

mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2)+POW(?,2)) AS hypotenuse';
mysql> SET @a = 3;
mysql> SET @b = 4;
mysql> EXECUTE stmt1 USING @a, @b;
+------------+
| hypotenuse |
+------------+
|  5         |
+------------+
mysql> DEALLOCATE PREPARE stmt1;
Второй пример подобен, но поставляет текст запроса как пользовательскую переменную:
mysql> SET @s = 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> PREPARE stmt2 FROM @s;
mysql> SET @a = 6;
mysql> SET @b = 8;
mysql> EXECUTE stmt2 USING @a, @b;
+------------+
| hypotenuse |
+------------+
| 10         |
+------------+
mysql> DEALLOCATE PREPARE stmt2;
Вот дополнительный пример, который демонстрирует, как выбрать таблицу, на которой можно выполнить запрос во время выполнения, храня название таблицы как пользовательскую переменную:
mysql> USE test;
mysql> CREATE TABLE t1 (a INT NOT NULL);
mysql> INSERT INTO t1 VALUES (4), (8), (11), (32), (80);
mysql> SET @table = 't1';
mysql> SET @s = CONCAT('SELECT * FROM ', @table);
mysql> PREPARE stmt3 FROM @s;
mysql> EXECUTE stmt3;
+----+
| a  |
+----+
|  4 |
|  8 |
| 11 |
| 32 |
| 80 |
+----+
mysql> DEALLOCATE PREPARE stmt3;
Готовый запрос является определенным для сеанса, в котором он создавался. Если Вы заканчиваете сеанс, не освобождая ранее готовый запрос, сервер освобождает это автоматически.

Готовый запрос также глобален для сеанса. Если Вы создаете готовый запрос в пределах сохраненной подпрограммы, это не освобождено, когда сохраненная подпрограмма заканчивается.

Чтобы принять меры против слишком многих готовых запросов, создаваемых одновременно, установите max_prepared_stmt_count. Чтобы предотвратить использование готовых запросов, установите значение в 0.

Синтаксис SQL, позволенный в готовых запросах

Следующие запросы SQL могут использоваться в качестве подготовленных запросов:

ALTER TABLE
ALTER USER
ANALYZE TABLE
CACHE INDEX
CALL
CHANGE MASTER
CHECKSUM {TABLE | TABLES}
COMMIT
{CREATE | DROP} INDEX
{CREATE | RENAME | DROP} DATABASE
{CREATE | DROP} TABLE
{CREATE | RENAME | DROP} USER
{CREATE | DROP} VIEW
DELETE
DO
FLUSH {TABLE | TABLES | TABLES WITH READ LOCK | HOSTS | PRIVILEGES
  | LOGS | STATUS | MASTER | SLAVE | DES_KEY_FILE | USER_RESOURCES}
GRANT
INSERT
INSTALL PLUGIN
KILL
LOAD INDEX INTO CACHE
OPTIMIZE TABLE
RENAME TABLE
REPAIR TABLE
REPLACE
RESET {MASTER | SLAVE | QUERY CACHE}
REVOKE
SELECT
SET
SHOW {WARNINGS | ERRORS}
SHOW BINLOG EVENTS
SHOW CREATE {PROCEDURE | FUNCTION | EVENT | TABLE | VIEW}
SHOW {MASTER | BINARY} LOGS
SHOW {MASTER | SLAVE} STATUS
SLAVE {START | STOP}
TRUNCATE TABLE
UNINSTALL PLUGIN
UPDATE
Для согласия со стандартом SQL, который заявляет, что запросы диагностики не могут быть предварительно подготовленными, MySQL не поддерживает следующие запросы как подготовленные:

  • SHOW WARNINGS, SHOW COUNT(*) WARNINGS

  • SHOW ERRORS, SHOW COUNT(*) ERRORS
  • Запросы, содержащие любую ссылку на warning_count или error_count.

Другие запросы не поддержаны в MySQL 8.0.

Вообще, запросы, не разрешенные в подготовленных запросах SQL, также не разрешены в сохраненных программах. Исключения отмечены в разделе C.1.

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

Заполнители могут использоваться для параметров LIMIT, используя подготовленные запросы. См. раздел 14.2.9 .

В готовом CALL, используемом с PREPARE и EXECUTE, поддержка заполнителя параметров OUT и INOUT доступна, начиная с MySQL 8.0. См. раздел 14.2.1 для примера и обходного решения для более ранних версий. Заполнители могут использоваться для IN независимо от версии.

Синтаксис SQL для готовых запросов не может использоваться вложенным способом. Таким образом, запрос для PREPARE не может самостоятельно быть PREPARE, EXECUTE или DEALLOCATE PREPARE.

Синтаксис SQL для готовых запросов отличен от использования готового вызова API. Например, Вы не можете использовать C API mysql_stmt_prepare(), чтобы подготовить PREPARE, EXECUTE или DEALLOCATE PREPARE.

Синтаксис SQL для готовых запросов может использоваться в пределах хранимых процедур, но не в сохраненных функциях или триггерах. Однако, курсор не может использоваться для динамического запроса, который подготовлен и ыполнен с PREPARE и EXECUTE. Запрос для курсора проверено во время создания курсора, таким образом, запрос не может быть динамическим.

Синтаксис SQL для готовых запросов не поддерживает мультизапросы (то есть, много запросов в пределах единственной строки, отделенных ;).

Готовые запросы используют кэш запроса при условиях, описанных в described in разделе 9.10.3.1.

Чтобы писать программы на C, которые используют CALL, чтобы выполнить хранимые процедуры, которые содержат готовые запросы, флаг CLIENT_MULTI_RESULTS должен быть включен. Это потому, что каждый CALL возвращает результат, чтобы указать на состояние требования, в дополнение к любым наборам результатов, которые могли бы быть возвращены запросами в пределах процедуры.

CLIENT_MULTI_RESULTS может быть включен, когда Вы вызываете mysql_real_connect() , явно, передавая флаг CLIENT_MULTI_RESULTS, или неявно, передавая CLIENT_MULTI_STATEMENTS (который также включает CLIENT_MULTI_RESULTS). См. раздел 14.2.1 .

14.5.1. PREPARE

PREPARE stmt_name FROM preparable_stmt
PREPARE готовит запрос SQL и назначает ему имя stmt_name, которым можно сослаться на запрос позже. Готовый запрос выполнен с EXECUTE и выпущен с DEALLOCATE PREPARE. См. раздел 14.5.

Имена запросов не являются чувствительными к регистру. preparable_stmt буквальная строка или пользовательская переменная, которая содержит текст запроса SQL. Текст должен представить единственный запрос, не многократные запросы. В пределах запроса символы ? могут использоваться в качестве маркеров параметра, чтобы указать, где значения данных должны быть связаны с запросом позже, когда Вы выполняете его. Символы ? не должны быть приложены в пределах кавычек, даже если Вы намереваетесь обязать их представлять значения в виде строки. Маркеры параметра могут использоваться только там, где значения данных должны появиться, не для ключевых слов SQL, идентификаторов и т.д.

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

Контекст готового запроса это сеанс, в пределах которого он создается, это имеет несколько значений:

  • Готовый запрос, создаваемый в одном сеансе, недоступен другим сеансам.

  • Когда сеанс заканчивается, его готовые запросы больше не существуют. Если auto-reconnect включен, клиент не уведомлен, что соединение было потеряно. Поэтому клиенты могут хотеть отключить auto-reconnect. См. раздел 25.8.16.
  • Готовый запрос, создаваемый в пределах сохраненной программы, продолжает существовать после того, как программа заканчивает выполняться и может быть выполнен вне программы позже.
  • Запрос, подготовленный в контексте сохраненной программы, не может сослаться на хранимую процедуру, функциональные параметры или местные переменные, потому что они выходят из контекста, когда программа заканчивается и были бы недоступны, позже вне программы. Как обходное решение, обратитесь вместо этого к определяемым пользователем переменным, у которых также есть контекст сеанса, см. раздел 10.4.

14.5.2. EXECUTE

EXECUTE stmt_name
[USING @var_name [, @var_name] ...]
После подготовки запроса с PREPARE Вы выполняете это с EXECUTE, который относится к имени готового запроса. Если готовый запрос содержит какие-либо маркеры параметра, Вы должны поставлять USING, который перечисляет пользовательские переменные, содержащие значения, которые будут связаны с параметрами. Значения параметра могут поставляться только пользовательскими переменными, и USING должен назвать точно столько переменных, как число маркеров параметра в запросе.

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

См. раздел 14.5.

14.5.3. DEALLOCATE PREPARE

{DEALLOCATE | DROP} PREPARE stmt_name
Чтобы освободить готовый запрос, произведенный с PREPARE, используйте DEALLOCATE PREPARE, который относится к готовому имени запроса. Попытка выполнить готовый запрос после освобождения приводит к ошибке. Если слишком много готовых запросов создаются и не освобождаются DEALLOCATE PREPARE или концом сеанса, Вы могли бы столкнуться с верхним пределом, проведенным в жизнь max_prepared_stmt_count.

См. раздел 14.5.

14.6. Синтаксис составного запроса

Этот раздел описывает синтаксис для составного запроса BEGIN ... END и другие запросы, которые могут использоваться в теле сохраненных программ: хранимые процедуры и функции, триггеры и события. Эти объекты определены с точки зрения кода SQL, который сохранен на сервере для более позднего неспешного потребления (см. главу 21).

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

14.6.1. BEGIN ... END

[begin_label:] BEGIN
[statement_list]
END [end_label]
BEGIN ... END используется для того, чтобы написать составные запросы, которые могут появиться в пределах сохраненных программ (хранимые процедуры и функции, триггеры и события). Составной запрос может содержать многократные запросы в BEGIN и END. statement_list представляет список из одного или более запросов, каждый закончен точкой с запятой (;). statement_list непосредственно является дополнительным, таким образом, пустой составной запрос (BEGIN END) допустим.

BEGIN ... END могут быть вложены.

Использование многократных запросов требует, чтобы клиент был в состоянии послать строки запроса, содержащие разделитель ;. В mysql это обработано командой delimiter. Изменение разделителя конца запроса ; (например, на //) позволяет ; использоваться в теле программы. Для примера см. раздел 21.1.

Блок BEGIN ... END может быть маркирован. См. раздел 14.6.2 .

[NOT] ATOMIC не поддержан. Это означает, что никакая транзакционная точка восстановления не установлена в начале блока инструкций, и BEGIN, используемый в этом контексте, не имеет никакого эффекта на текущую транзакцию.

В пределах всех сохраненных программ анализатор обрабатывает BEGIN [WORK] как начало BEGIN ... END. Чтобы начать транзакцию в этом контексте, надо использовать START TRANSACTION.

14.6.2. Метки запросов

[begin_label:] BEGIN
[statement_list]
END [end_label]

[begin_label:] LOOP
statement_list
END LOOP [end_label]

[begin_label:] REPEAT
statement_list
UNTIL search_condition
END REPEAT [end_label]

[begin_label:] WHILE search_condition DO
statement_list
END WHILE [end_label]
Для меток разрешают BEGIN ... END блоки, а также команды LOOP, REPEAT и WHILE. Использование метки для тех запросов следует этим правилам:

  • begin_label должен сопровождаться двоеточием.

  • begin_label можно дать без end_label. Если дано end_label, это должно быть то же самое, как begin_label.
  • end_label нельзя дать без begin_label.
  • Метки на том же самом уровне вложенности должны быть отличными.
  • Метки могут быть до 16 символов в длину.

Чтобы обратиться к метке в пределах маркированной конструкции, используйте ITERATE или LEAVE. Следующий пример использует те запросы, чтобы продолжить повторять или заканчивать цикл:

CREATE PROCEDURE doiterate(p1 INT)
BEGIN
  label1: LOOP
SET p1 = p1 + 1;
IF p1 < 10 THEN ITERATE label1; END IF;
LEAVE label1;
  END LOOP label1;
END;
Контекст метки блока не включает код для обработчиков, объявленных в пределах блока. Для деталей см. раздел 14.6.7.2.

14.6.3. DECLARE

DECLARE используется, чтобы определить различные элементы, местные для программы:

DECLARE разрешен только внутри BEGIN ... END и должен быть в его начале перед любыми другими запросыми.

Декларации должны следовать в определенном порядке. Декларации курсора должны появиться перед декларациями обработчика. Переменная и декларации условия должны появиться перед декларациями обработчика или курсором.

14.6.4. Переменные в сохраненных программах

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

См. раздел 14.6.4.2.

Не разрешено назначить значение DEFAULT местным переменным в хранимой процедуре или функциональным параметрам (например, с SET var_name = DEFAULT). В MySQL 8.0 это приводит к синтаксической ошибке.

14.6.4.1. Местная переменная DECLARE

DECLARE var_name [, var_name] ...
type [DEFAULT value]
Этот запрос объявляет местные переменные в пределах сохраненных программ. Чтобы обеспечить значение по умолчанию для переменной, включайте DEFAULT. Значение может быть определено как выражение, это не должна быть константа. Если DEFAULT нет, начальное значение NULL.

Местные переменные обработаны как сохраненные обычные параметры относительно проверки переполнения и типа данных. См. раздел 14.1.13.

Переменные декларации должны появиться перед декларациями обработчика или курсора.

Местные имена переменной не являются чувствительными к регистру. Допустимые символы и правила заключения в кавычки те же самое, что касаются других идентификаторов, как описано в разделе 10.2.

Контекст местной переменной это блок BEGIN ... END в пределах которого это объявлено. Переменная может быть упомянута в блоках, вложенных в пределах блока объявления, кроме тех блоков, которые объявляют переменную с тем же самым именем.

См. раздел 14.6.4.2.

14.6.4.2. Местный контекст и разрешение переменных

Контекст местной переменной это блок BEGIN ... END в пределах которого это объявлено. Переменная может быть упомянута в блоках, вложенных в пределах блока объявления, кроме тех блоков, которые объявляют переменную с тем же самым именем.

Поскольку местные переменные находятся в контексте только во время выполнения сохраненной программы, ссылки на них не разрешены в готовых запросах, создаваемых в пределах сохраненной программы. Контекст готового запроса это текущий сеанс, а не сохраненная программа, таким образом, запрос может быть выполнен после конца программы, а тогда переменные больше не будут в контексте. Например, SELECT ... INTO local_var не может использоваться в качестве готового запроса. Это ограничение также относится к хранимой процедуре и функциональным параметрам. См. раздел 14.5.1.

У местной переменной не должно быть того же самого имени как у столбца таблицы. Если запрос SQL, например, SELECT ... INTO, содержит ссылку на столбец и заявленную местную переменную с тем же самым именем, MySQL в настоящее время интерпретирует ссылку как название переменной. Рассмотрите следующее определение процедуры:

CREATE PROCEDURE sp1 (x VARCHAR(5))
BEGIN
  DECLARE xname VARCHAR(5) DEFAULT 'bob';
  DECLARE newname VARCHAR(5);
  DECLARE xid INT;
  SELECT xname, id INTO newname, xid FROM table1 WHERE xname = xname;
  SELECT newname;
END;
MySQL понимает xname в SELECT как ссылку на переменную xname, а не на столбец xname. Следовательно, когда процедура sp1() вызвана, переменная newname возвращает значение 'bob' независимо от значения table1.xname.

Точно так же определение курсора в следующей процедуре содержит SELECT, который относится к xname. MySQL интерпретирует это как ссылку на переменную, а не на столбец.

CREATE PROCEDURE sp2 (x VARCHAR(5))
BEGIN
  DECLARE xname VARCHAR(5) DEFAULT 'bob';
  DECLARE newname VARCHAR(5);
  DECLARE xid INT;
  DECLARE done TINYINT DEFAULT 0;
  DECLARE cur1 CURSOR FOR SELECT xname, id FROM table1;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
  OPEN cur1;
  read_loop: LOOP
    FETCH FROM cur1 INTO newname, xid;
    IF done THEN
       LEAVE read_loop;
    END IF;
    SELECT newname;
  END LOOP;
  CLOSE cur1;
END;
См. раздел C.1.

14.6.5. Запросы управления потоками

MySQL поддерживает конструкции IF, CASE, ITERATE, LEAVE LOOP, WHILE и REPEAT для управления потоками в пределах сохраненных программ. Это также поддерживает RETURN в пределах сохраненных функций.

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

MySQL не поддерживает циклы FOR.

14.6.5.1. CASE

CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list] ...
[ELSE statement_list]
END CASE
Или:
CASE
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list]
END CASE
CASE для сохраненных программ осуществляет сложную условную конструкцию.

Есть также CASE expression, который отличается от CASE statement, описанного здесь. См. раздел 13.4 . CASE не может иметь ELSE NULL и это закончено с END CASE вместо END.

Для первого синтаксиса case_value является выражением. Это значение сравнивается с when_value в каждом WHEN до равенства одному из них. Когда равное when_value найдено, соответствующий THEN statement_list выполнен. Если нет равного when_value, выполнен ELSE statement_list, если есть. Если его нет, то не выполнено ничего.

Этот синтаксис не может использоваться, чтобы проверить на равенство с NULL, так как NULL = NULL будет false. См. раздел 4.3.4.6.

Для второго синтаксиса каждый WHEN search_condition оценено, пока не истина, в какой THEN statement_list передать выполнение. Если нет равного when_value, выполнен ELSE statement_list, если есть. Если его нет, то не выполнено ничего.

Если нет when_value или search_condition, которое соответствует проверенному значению, и CASE не содержит ELSE, будет ошибка Case not found for CASE statement.

Каждый statement_list состоит из одного или более запросов SQL, пустой statement_list запрещен.

Чтобы обработать ситуации, где никакое значение не является соответствующим WHEN, используйте ELSE, содержащий пустой блок BEGIN ... END.

DELIMITER |

CREATE PROCEDURE p()
BEGIN
  DECLARE v INT DEFAULT 1;

  CASE v
    WHEN 2 THEN SELECT v;
    WHEN 3 THEN SELECT 0;
    ELSE BEGIN
    END;
  END CASE;
END;
|

14.6.5.2. IF

IF search_condition THEN statement_list
[ELSEIF search_condition THEN statement_list] ...
[ELSE statement_list]
END IF
IF для сохраненных программ осуществляет основную условную конструкцию.

Есть также функция IF(), которая отличается от запроса IF. См. раздел 13.4. Запрос IF может иметь THEN, ELSE и ELSEIF, и это закончено с END IF.

Если search_condition true, соответствующий THEN или ELSEIF statement_list выполняется. Если нет подходящего search_condition, выполнен ELSE statement_list.

Каждый statement_list состоит из одного или более запросов SQL: пустой statement_list запрещен.

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

DELIMITER //

CREATE FUNCTION SimpleCompare(n INT, m INT)
  RETURNS VARCHAR(20)
  BEGIN
    DECLARE s VARCHAR(20);
    IF n > m THEN SET s = '>';
       ELSEIF n = m THEN SET s = '=';
       ELSE SET s = '<';
    END IF;
    SET s = CONCAT(n, ' ', s, ' ', m);
    RETURN s;
  END //

DELIMITER ;
Как с другими конструкциями управления потоками, блоки IF ... END IF могут быть вложены в пределах других конструкций управления потоками, включая другой запрос IF. Каждый IF должен быть закончен его собственным END IF и точкой с запятой. Вы можете использовать углубление, чтобы сделать вложенные блоки управления потоками более легко читаемыми людьми (хотя это не требуется MySQL), как показано здесь:
DELIMITER //

CREATE FUNCTION VerboseCompare (n INT, m INT)
  RETURNS VARCHAR(50)
  BEGIN
    DECLARE s VARCHAR(50);
    IF n = m THEN SET s = 'equals';
    ELSE
      IF n > m THEN SET s = 'greater';
      ELSE SET s = 'less';
      END IF;
      SET s = CONCAT('is ', s, ' than');
    END IF;
    SET s = CONCAT(n, ' ', s, ' ', m, '.');
  RETURN s;
  END //

DELIMITER ;
В этом примере внутренний IF оценен только, если n не равно m.

14.6.5.3. ITERATE

ITERATE label
ITERATE может появиться только в пределах LOOP, REPEAT и WHILE. ITERATE значит запустить повтор цикла.

См. раздел 14.6.5.5.

14.6.5.4. LEAVE

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

LEAVE может использоваться в пределах BEGIN ... END или конструкции цикла (LOOP, REPEAT, WHILE).

См. раздел 14.6.5.5.

14.6.5.5. LOOP

[begin_label:] LOOP
statement_list
END LOOP [end_label]
LOOP осуществляет простую конструкцию цикла, включая повторное выполнение списка запросов, который состоит из одного или более запросов, каждый завершенный точкой с запятой (;). Ззапросы повторены, пока цикл не закончен. Обычно это достигнуто с помощью LEAVE . В пределах сохраненной функции RETURN может также использоваться, чтобы выйти из функции полностью.

Если не включать запрос завершения цикла, цикл станет бесконечным.

LOOP может быть маркирован. Для правил относительно использования меток см. раздел 14.6.2.

Пример:

CREATE PROCEDURE doiterate(p1 INT)
BEGIN
  label1: LOOP
    SET p1 = p1 + 1;
    IF p1 < 10 THEN ITERATE label1;
    END IF;
    LEAVE label1;
  END LOOP label1;
  SET @x = p1;
END;

14.6.5.6. REPEAT

[begin_label:] REPEAT
statement_list
UNTIL search_condition
END REPEAT [end_label]
Список запросов в пределах REPEAT повторено, пока выражение search_condition не станет истиной. Таким образом, REPEAT всегда вводит цикл, по крайней мере, однажды. statement_list состоит из одного или более запросов, каждый закрыт точкой с запятой (;).

REPEAT может быть маркирован. Для правил относительно использования меток см. раздел 14.6.2.

Пример:

mysql> delimiter //

mysql> CREATE PROCEDURE dorepeat(p1 INT)
    -> BEGIN
    ->   SET @x = 0;
    ->   REPEAT
    -> SET @x = @x + 1;
    ->   UNTIL @x > p1 END REPEAT;
    -> END
    -> //
Query OK, 0 rows affected (0.00 sec)

mysql> CALL dorepeat(1000)//
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @x//
+------+
| @x   |
+------+
| 1001 |
+------+
1 row in set (0.00 sec)

14.6.5.7. RETURN

RETURN expr
RETURN заканчивает выполнение сохраненной функции и возвращает значение expr вызвавшему. Должен быть по крайней мере один RETURN в сохраненной функции. Может быть больше, чем один, если у функции есть много пунктов выхода.

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

14.6.5.8. WHILE

[begin_label:] WHILE search_condition DO
statement_list
END WHILE [end_label]
Список запросов в пределах WHILE повторен, пока search_condition true. statement_list состоит из одного или более запросов SQL, каждый закончен точкой с запятой (;).

WHILE может быть маркирован. Для правил относительно использования меток см. раздел 14.6.2.

Пример:

CREATE PROCEDURE dowhile()
BEGIN
  DECLARE v1 INT DEFAULT 5;
  WHILE v1 > 0 DO
    ...
    SET v1 = v1 - 1;
  END WHILE;
END;

14.6.6. Курсоры

MySQL поддерживает курсоры в сохраненных программах. Синтаксис как во встроенном SQL. У курсоров есть эти свойства:

  • Asensitive: сервер может или, возможно, не делает копию своей таблицы результата.

  • Только для чтения: Не обновляемые.
  • Nonscrollable: Может быть просмотрен только в одном направлении и не может пропустить строки.

Декларации курсора должны появиться перед декларациями обработчика и после деклараций условия и переменной.

Пример:

CREATE PROCEDURE curdemo()
BEGIN
  DECLARE done INT DEFAULT FALSE;
  DECLARE a CHAR(16);
  DECLARE b, c INT;
  DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1;
  DECLARE cur2 CURSOR FOR SELECT i FROM test.t2;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
  OPEN cur1;
  OPEN cur2;
  read_loop: LOOP
    FETCH cur1 INTO a, b;
    FETCH cur2 INTO c;
    IF done THEN LEAVE read_loop;
    END IF;
    IF b < c THEN
       INSERT INTO test.t3 VALUES (a,b);
       ELSE INSERT INTO test.t3 VALUES (a,c);
    END IF;
  END LOOP;
  CLOSE cur1;
  CLOSE cur2;
END;

14.6.6.1. Курсор CLOSE

CLOSE cursor_name
Закрывает ранее открытый курсор. Для примера см. раздел 14.6.6.

Ошибка происходит, если курсор не открыт.

Если не закрыт явно, курсор закрыт в конце блока BEGIN ... END, в котором это было объявлено.

14.6.6.2. Курсор DECLARE

DECLARE cursor_name CURSOR FOR select_statement
Этот запрос объявляет курсор и связывает с SELECT, который получает строки, которые будут пересечены курсором. Чтобы принести строки позже, используйте FETCH. Число столбцов, полученных SELECT, должно соответствовать числу выходных переменных, определенных в FETCH.

SELECT не может иметь INTO.

Декларации курсора должны появиться перед декларациями обработчика и после деклараций условия и переменной.

Сохраненная программа может содержать многократные декларации курсора, но у каждого курсора, объявленного в данном блоке, должно быть уникальное имя. Для примера см. раздел 14.6.6.

Для информации, доступной через SHOW, возможно во многих случаях получить эквивалентную информацию при использовании курсора с таблицей INFORMATION_SCHEMA.

14.6.6.3. Курсор FETCH

FETCH [[NEXT] FROM] cursor_name INTO
var_name [, var_name] ...
Этоn запрос приносит следующую строку для SELECT, связанным с указанным курсором (который должен быть открыт) и обновляет указатель курсора. Если строка существует, принесенные столбцы сохранены в названных переменных. Число столбцов, полученных SELECT, должно соответствовать числу выходных переменных, определенных в FETCH.

Если больше строк не доступно, происходит состояние No Data condition с SQLSTATE value '02000'. Чтобы обнаружить это условие, Вы можете настроить обработчик для этого (или для условия NOT FOUND ). См. раздел 14.6.6.

Знайте, что другая работа, такая как SELECT или другой FETCH, может также заставить обработчик выполняться, поднимая то же самое условие. Если необходимо различить, какая работа подняла условие, поместите работу в пределах его собственного блока BEGIN ... END, чтобы это могло быть связано с собственным обработчиком.

14.6.6.4. Курсор OPEN

OPEN cursor_name
Этот запрос открывает ранее заявленный курсор. Для примера см. раздел 14.6.6.

14.6.7. Обработка условия

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

Чтобы назвать условие, используйте DECLARE ... CONDITION. Чтобы объявить обработчик, используйте DECLARE ... HANDLER. См. разделы 14.6.7.1 и раздел 14.6.7.2.

Чтобы поднять условие, используйте SIGNAL. Чтобы изменить информацию об условии в пределах обработчика условия, надо использовать RESIGNAL. См. разделы 14.6.7.1 и 14.6.7.2.

Чтобы получить информацию из области диагностики, используйте GET DIAGNOSTICS (см. раздел 14.6.7.3). Для информации об области диагностики см. раздел 14.6.7.7.

14.6.7.1. DECLARE ... CONDITION

DECLARE condition_name CONDITION FOR condition_value
condition_value:
mysql_error_code
  | SQLSTATE [VALUE] sqlstate_value
DECLARE ... CONDITION объявляет названное состояние ошибки, связывая имя с условием, которое нуждается в определенной обработке. Имя может быть упомянуто в последующем DECLARE ... HANDLER (см. раздел 14.6.7.2).

Декларации условия должны появиться перед декларациями обработчика или курсором.

condition_value для DECLARE ... CONDITION указывает на особое условие или класс условий, связанный с именем условия. Это может принять следующие формы:

  • mysql_error_code: Целое число, указание на код ошибки MySQL.

    Не используйте код ошибки MySQL 0, потому что это указывает на успех, а не состояние ошибки. Для списка кодов ошибок MySQL см. раздел B.3.

  • SQLSTATE [VALUE] sqlstate_value: 5-символьная строка, указание на значение SQLSTATE.

    Не используйте значения SQLSTATE, которые начинаются на '00', потому что те указывают на успех, а не на состояние ошибки. Для списка значений SQLSTATE см. раздел B.3 .

Имена условия, упомянутые в SIGNAL или RESIGNAL, должны быть связаны со значениями SQLSTATE, а не кодами ошибки MySQL.

Использование названия условий может помочь сделать код программы более ясным. Например, этот обработчик относится к попыткам удалить несуществующую таблицу, но это очевидно, только если Вы знаете, что 1051 это код ошибки MySQL для unknown table:

DECLARE CONTINUE HANDLER FOR 1051
  BEGIN
-- body of handler
  END;
Объявляя название условия, цель обработчика замечена с большей точностью:
DECLARE no_such_table CONDITION FOR 1051;
DECLARE CONTINUE HANDLER FOR no_such_table
  BEGIN
-- body of handler
  END;
Вот названное условие для того же самого условия, но основанное на соответствующем значении SQLSTATE, а не коде ошибки MySQL:
DECLARE no_such_table CONDITION FOR SQLSTATE '42S02';
DECLARE CONTINUE HANDLER FOR no_such_table
  BEGIN
-- body of handler
  END;

14.6.7.2. DECLARE ... HANDLER

DECLARE handler_action HANDLER
FOR condition_value [, condition_value] ...
statement

handler_action:
CONTINUE
  | EXIT
  | UNDO

condition_value:
mysql_error_code
  | SQLSTATE [VALUE] sqlstate_value
  | condition_name
  | SQLWARNING
  | NOT FOUND
  | SQLEXCEPTION
DECLARE ... HANDLER определяет обработчик, который имеет дело с одним или более условиями. Если одно из этих условий происходит, указанный statement выполнится. statement может быть простым запросом таким, как SET var_name = value, или составным запросом из BEGIN и END (см. раздел 14.6.1).

Декларации обработчика должны появиться после деклараций условия или переменной.

handler_action указывает на то, что обработчик предпринимает после выполнения запроса обработчика:

  • CONTINUE: Выполнение текущей программы продолжается.

  • EXIT: Выполнение заканчивается для BEGIN ... END, в котором объявлен обработчик. Это истина, даже если условие происходит во внутреннем блоке.
  • UNDO: Не поддержано.

condition_value для DECLARE ... HANDLER указывает на особое условие или класс условий, который активирует обработчик. Это может принять следующие формы:

  • mysql_error_code: Целое число, указание на код ошибки MySQL, такой как 1051, определяющий unknown table:

    DECLARE CONTINUE HANDLER FOR 1051
      BEGIN
    -- body of handler
      END;
    
    Не используйте код ошибки MySQL 0, потому что это указывает на успех, а не на состояние ошибки. Для списка кодов ошибки MySQL см. раздел B.3.
  • SQLSTATE [VALUE] sqlstate_value: 5-символьная строка, указание на значение SQLSTATE, такое как '42S01', определяющее unknown table:
    DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
      BEGIN
    -- body of handler
      END;
    
    Не используйте значения SQLSTATE, которые начинаются с '00', потому что те указывают на успех, а не на состояние ошибки. Для списка значений SQLSTATE см. раздел B.3 .
  • condition_name: Имя условия, ранее определенное с DECLARE ... CONDITION. Имя условия может быть связано с кодом ошибки MySQL или значением SQLSTATE. См. раздел 14.6.7.1.
  • SQLWARNING: Сокращение для класса значений SQLSTATE, которые начинаются с '01'.
    DECLARE CONTINUE HANDLER FOR SQLWARNING
      BEGIN
    -- body of handler
      END;
    
  • NOT FOUND: Сокращение для класса значений SQLSTATE, которые начинаются с '02'. Это релевантно в пределах контекста курсоров и используется, чтобы управлять тем, что происходит, когда курсор достигает конца набора данных. Если больше строк не доступно, No Data condition происходит со значением SQLSTATE '02000'. Чтобы обнаружить это условие, Вы можете настроить обработчик для этого или для NOT FOUND.
    DECLARE CONTINUE HANDLER FOR NOT FOUND
      BEGIN
    -- body of handler
      END;
    
    См. раздел 14.6.6. Условие NOT FOUND также происходит для SELECT ... INTO var_list , которые не получают строк.
  • SQLEXCEPTION: Сокращение для класса значений SQLSTATE, которые НЕ начинаются с '00', '01' или '02'.
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
      BEGIN
    -- body of handler
      END;
    

См. раздел 14.6.7.6.

Если условие происходит, для которого не был объявлен обработчик, предпринятые меры зависят от класса условия:

  • SQLEXCEPTION: сохраненная программа заканчивается в запросе, который поднял условие, как будто был EXIT. Если программу вызвала другая сохраненная программа, дескрипторы программы запроса, условие относится к своим собственным обработчикам.

  • SQLWARNING: программа продолжает выполняться, как будто был CONTINUE.
  • NOT FOUND: если условие поднимается обычным порядком, действие CONTINUE. Если условие поднимается SIGNAL или RESIGNAL, то действие EXIT.

Следующий пример использует обработчик для SQLSTATE '23000', который происходит для дублирования ключа:

mysql> CREATE TABLE test.t (s1 INT, PRIMARY KEY (s1));
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter //
mysql> CREATE PROCEDURE handlerdemo ()
    -> BEGIN
    ->   DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
    ->   SET @x = 1;
    ->   INSERT INTO test.t VALUES (1);
    ->   SET @x = 2;
    ->   INSERT INTO test.t VALUES (1);
    ->   SET @x = 3;
    -> END;
    -> //
Query OK, 0 rows affected (0.00 sec)

mysql> CALL handlerdemo()//
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @x//
+----+
| @x |
+----+
| 3  |
+----+
1 row in set (0.00 sec)
Заметьте, что @x = 3 после того, как процедура выполняется, что показывает, что выполнение продолжалось до конца процедуры после ошибки. Если DECLARE ... HANDLER не присутствовало, MySQL предпримет меры по умолчанию (EXIT) после второго INSERT неудавшегося из-за PRIMARY KEY и SELECT @x возвратил бы 2.

Чтобы проигнорировать условие, объявите обработчик CONTINUE для этого и свяжите его с пустым блоком. Например:

DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;
Контекст метки блока не включает код для обработчиков, объявленных в пределах блока. Поэтому, запрос, связанный с обработчиком, не может использовать ITERATE или LEAVE, чтобы обратиться к меткам для блоков, которые прилагают декларацию обработчика. Рассмотрите следующий пример, где у блока REPEAT есть метка retry:
CREATE PROCEDURE p ()
BEGIN
  DECLARE i INT DEFAULT 3;
retry:
  REPEAT BEGIN
    DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN
      ITERATE retry;    # illegal
    END;
    IF i < 0 THEN
       LEAVE retry;# legal
    END IF;
    SET i = i - 1;
  END;
  UNTIL FALSE END REPEAT;
END;
Метка retry находится в контексте IF в пределах блока. Это не находится в контексте для обработчика CONTINUE , таким образом, ссылка там недопустима и приводит к ошибке:
ERROR 1308 (42000): LEAVE with no matching label: retry
Чтобы избежать ссылок на внешние метки в обработчиках, используйте одну из этих стратегий:

  • Чтобы оставить блок, используйте EXIT. Если никакая уборка блока не требуется, BEGIN ... END может быть пустым:

    DECLARE EXIT HANDLER FOR SQLWARNING BEGIN END;
    
    Иначе, поместите запросы уборки в обработчик:
    DECLARE EXIT HANDLER FOR SQLWARNING
    BEGIN
      block cleanup statements
    END;
    
  • Чтобы продолжить выполнение, установите переменную состояния в обработчик CONTINUE, который может быть проверен в блоке приложения, чтобы определить, был ли обработчик вызван. Следующий пример использует переменную done с этой целью:
    CREATE PROCEDURE p ()
    BEGIN
      DECLARE i INT DEFAULT 3;
      DECLARE done INT DEFAULT FALSE;
    retry:
      REPEAT BEGIN
        DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN
          SET done = TRUE;
        END;
        IF done OR i < 0 THEN
           LEAVE retry;
        END IF;
        SET i = i - 1;
      END;
      UNTIL FALSE END REPEAT;
    END;
    

14.6.7.3. GET DIAGNOSTICS

GET [CURRENT | STACKED] DIAGNOSTICS
{
statement_information_item
[, statement_information_item] ...
  | CONDITION condition_number
condition_information_item
[, condition_information_item] ...
}

statement_information_item:
target = statement_information_item_name
condition_information_item:
target = condition_information_item_name

statement_information_item_name:
NUMBER
  | ROW_COUNT

condition_information_item_name:
CLASS_ORIGIN
  | SUBCLASS_ORIGIN
  | RETURNED_SQLSTATE
  | MESSAGE_TEXT
  | MYSQL_ERRNO
  | CONSTRAINT_CATALOG
  | CONSTRAINT_SCHEMA
  | CONSTRAINT_NAME
  | CATALOG_NAME
  | SCHEMA_NAME
  | TABLE_NAME
  | COLUMN_NAME
  | CURSOR_NAME

condition_number, target:
(see following discussion)
Запросы SQL производят диагностическую информацию, которая заполняет область диагностики. GET DIAGNOSTICS позволяет приложениям смотреть эту информацию. Вы можете также использовать SHOW WARNINGS или SHOW ERRORS, чтобы видеть условия или ошибки.

Никакие специальные привилегии не нужны для GET DIAGNOSTICS.

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

GET DIAGNOSTICS, как правило, используется в обработчике в пределах сохраненной программы. Это расширение MySQL, для GET [CURRENT] DIAGNOSTICS разрешен внешний контекст обработчика, чтобы проверить выполнение любого запроса SQL. Например, если Вы вызываете mysql, Вы можете ввести эти запросы:

mysql> DROP TABLE test.no_such_table;
ERROR 1051 (42S02): Unknown table 'test.no_such_table'
mysql> GET DIAGNOSTICS CONDITION 1
    ->     @p1 = RETURNED_SQLSTATE, @p2 = MESSAGE_TEXT;
mysql> SELECT @p1, @p2;
+-------+------------------------------------+
| @p1   | @p2                                |
+-------+------------------------------------+
| 42S02 | Unknown table 'test.no_such_table' |
+-------+------------------------------------+
Это расширение применяется только к текущей области диагностики. Это не относится к второй области диагностики потому, что GET STACKED DIAGNOSTICS разрешен, только если текущий контекст обработчик условия. Если это не так, происходит ошибка GET STACKED DIAGNOSTICS when handler not active.

См. раздел 14.6.7.7. Кратко, это содержит два вида информации:

  • Информация о запросе, такая как число условий или количество затронутых строк.

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

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

Statement information:
  row count
  ... other statement information items ...
Condition area list:
  Condition area 1:
error code for condition 1
error message for condition 1
... other condition information items ...
  Condition area 2:
error code for condition 2:
error message for condition 2
... other condition information items ...
  Condition area 3:
error code for condition 3
error message for condition 3
... other condition information items ...
GET DIAGNOSTICS может получить запрос или информацию об условии, но не обоих в том же самом запросе:

  • Чтобы получить информацию о запросе, получите желаемые элементы запросов в целевые переменные. Этот GET DIAGNOSTICS назначает число доступных условий и количество затронутых строк к пользовательским переменным @p1 и @p2:

    GET DIAGNOSTICS @p1 = NUMBER, @p2 = ROW_COUNT;
    
  • Чтобы получить информацию об условии, определите номер условия и получите желаемые элементы условия в целевые переменные. Этот GET DIAGNOSTICS назначает значение SQLSTATE и сообщение об ошибке пользовательским переменным @p3 и @p4:
    GET DIAGNOSTICS CONDITION 1
        @p3 = RETURNED_SQLSTATE, @p4 = MESSAGE_TEXT;
    

Список извлечения определяет один или больше target = item_name, отделенных запятыми. Каждое назначение называет целевую переменную и любой указатель statement_information_item_name или condition_information_item_name, в зависимости от того, получает ли запрос информацию об условии или запрос.

Допустимые указатели target для того, чтобы хранить информацию элемента могут быть хранимой процедурой или функциональными параметрами, местными переменными, объявленными с DECLARE, или определяемыми пользователем переменными.

Допустимые указатели condition_number могут быть хранимой процедурой или функциональными параметрами, местными перемеными, объявленными с DECLARE , определяемыми пользователем переменными, системными переменными или литералами. Символьный литерал может включать _charset. Предупреждение происходит, если номер условия не находится в диапазоне от 1 до числа областей условия, у которых есть информация. В этом случае предупреждение добавлено к области диагностики, не очищая ее.

Когда условие происходит, MySQL не заполняет все элементы условия, признанные GET DIAGNOSTICS:

mysql> GET DIAGNOSTICS CONDITION 1
    ->     @p5 = SCHEMA_NAME, @p6 = TABLE_NAME;
mysql> SELECT @p5, @p6;
+-----+-----+
| @p5 | @p6 |
+-----+-----+
|     |     |
+-----+-----+
В стандартном SQL, если есть многократные условия, первое условие касается SQLSTATE для предыдущего запроса SQL. В MySQL это не гарантируется. Чтобы получить основную ошибку, Вы не можете сделать этого:
GET DIAGNOSTICS CONDITION 1 @errno = MYSQL_ERRNO;
Вместо этого получите количество условий сначала, затем используйте это, чтобы определить, которое условие смотреть:
GET DIAGNOSTICS @cno = NUMBER;
GET DIAGNOSTICS CONDITION @cno @errno = MYSQL_ERRNO;
См. раздел 14.6.7.7.2 .

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

CREATE PROCEDURE do_insert(value INT)
BEGIN
  -- Declare variables to hold diagnostics area information
  DECLARE code CHAR(5) DEFAULT '00000';
  DECLARE msg TEXT;
  DECLARE rows INT;
  DECLARE result TEXT;
  -- Declare exception handler for failed insert
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
  GET DIAGNOSTICS CONDITION 1
  code = RETURNED_SQLSTATE, msg = MESSAGE_TEXT;
END;
  -- Perform the insert
  INSERT INTO t1 (int_col) VALUES(value);
  -- Check whether the insert was successful
  IF code = '00000' THEN
     GET DIAGNOSTICS rows = ROW_COUNT;
     SET result = CONCAT('insert succeeded, row count = ',rows);
  ELSE
    SET result = CONCAT('insert failed, error = ',code,', message = ',msg);
  END IF;
  -- Say what happened
  SELECT result;
END;
Предположите, что t1.int_col столбец целого числа, который объявлен как NOT NULL. Процедура приводит к этим результатам когда вызвана, чтобы вставить значения не-NULL и NULL, соответственно:
mysql> CALL do_insert(1);
+---------------------------------+
| result                          |
+---------------------------------+
| insert succeeded, row count = 1 |
+---------------------------------+

mysql> CALL do_insert(NULL);
+-------------------------------------------------------------------------+
| result                                                                  |
+-------------------------------------------------------------------------+
| insert failed, error = 23000, message = Column 'int_col' cannot be null |
+-------------------------------------------------------------------------+
Когда обработчик условия активируется, обращение к стеку области диагностики происходит:

  • Первая (текущая) область диагностики становится второй областью диагностики, и новая текущая область диагностики создается как копия этого.

  • GET [CURRENT] DIAGNOSTICS и GET STACKED DIAGNOSTICS может использоваться в пределах обработчика, чтобы получить доступ к содержанию областей диагностики.
  • Первоначально, обе области диагностики возвращают тот же самый результат, таким образом, возможно получить информацию из текущей области диагностики об условии, которое активировало обработчик, пока Вы не выполняете запросов в пределах обработчика, которые изменяют его текущую область диагностики.
  • Однако, выполнение запросов в пределах обработчика может изменить текущую область диагностики, очищая и устанавливая ее содержание согласно нормальным правилам (см. раздел 14.6.7.7.3 ).

    Более надежный способ получить информацию об активирующем обработчик условии состоит в том, чтобы использовать стековую область диагностики, которая не может быть изменена выполнением запросов в пределах обработчика, кроме RESIGNAL. См. раздел 14.6.7.7.

Следующий пример показывает как GET STACKED DIAGNOSTICS может использоваться в пределах обработчика, чтобы получить информацию об обработанном исключении, даже после того, как текущая область диагностики была изменена запросами обработчика.

В пределах хранимой процедуры p() мы пытаемся вставить два значения в таблицу, которая содержит столбец TEXT NOT NULL. Первое значение не-NULL строка, второе NULL. Столбец запрещает NULL, таким образом, первая вставка преуспевает, но вторая дает исключение. Процедура включает обработчик исключения, который отображает попытки вставить NULL:

DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (c1 TEXT NOT NULL);
DROP PROCEDURE IF EXISTS p;
delimiter //
CREATE PROCEDURE p ()
BEGIN
  -- Declare variables to hold diagnostics area information
  DECLARE errcount INT;
  DECLARE errno INT;
  DECLARE msg TEXT;
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
  -- Here the current DA is nonempty because no prior statements
  -- executing within the handler have cleared it
    GET CURRENT DIAGNOSTICS CONDITION 1
    errno = MYSQL_ERRNO, msg = MESSAGE_TEXT;
    SELECT 'current DA before mapped insert' AS op, errno, msg;
    GET STACKED DIAGNOSTICS CONDITION 1
    errno = MYSQL_ERRNO, msg = MESSAGE_TEXT;
    SELECT 'stacked DA before mapped insert' AS op, errno, msg;
    -- Map attempted NULL insert to empty string insert
    INSERT INTO t1 (c1) VALUES('');
    -- Here the current DA should be empty (if the INSERT succeeded),
    -- so check whether there are conditions before attempting to
    -- obtain condition information
    GET CURRENT DIAGNOSTICS errcount = NUMBER;
    IF errcount = 0 THEN
       SELECT 'mapped insert succeeded, current DA is empty' AS op;
    ELSE
      GET CURRENT DIAGNOSTICS CONDITION 1
      errno = MYSQL_ERRNO, msg = MESSAGE_TEXT;
      SELECT 'current DA after mapped insert' AS op, errno, msg;
    END IF;
    GET STACKED DIAGNOSTICS CONDITION 1
    errno = MYSQL_ERRNO, msg = MESSAGE_TEXT;
    SELECT 'stacked DA after mapped insert' AS op, errno, msg;
  END;
  INSERT INTO t1 (c1) VALUES('string 1');
  INSERT INTO t1 (c1) VALUES(NULL);
END;
//
delimiter ;
CALL p();
SELECT * FROM t1;
Когда обработчик активируется, копия текущей области диагностики продвинута к стеку области диагностики. Обработчик показывает содержание текущей и стековой областей диагностики, которые являются тем же самым первоначально:
+---------------------------------+-------+----------------------------+
| op                              | errno | msg                        |
+---------------------------------+-------+----------------------------+
| current DA before mapped insert |  1048 | Column 'c1' cannot be null |
+---------------------------------+-------+----------------------------+

+---------------------------------+-------+----------------------------+
| op                              | errno | msg                        |
+---------------------------------+-------+----------------------------+
| stacked DA before mapped insert |  1048 | Column 'c1' cannot be null |
+---------------------------------+-------+----------------------------+
Запросы, выполняющиеся после GET DIAGNOSTICS, могут сбросить текущую область диагностики. Например, обработчик отображает вставку NULL к пустой строке, вставляет и выводит на экран результат. Новая вставка следует и очищает текущую область диагностики, но стековая область диагностики остается неизменной и все еще содержит информацию об условии, которое активировало обработчик:
+----------------------------------------------+
| op                                           |
+----------------------------------------------+
| mapped insert succeeded, current DA is empty |
+----------------------------------------------+

+--------------------------------+-------+----------------------------+
| op                             | errno | msg                        |
+--------------------------------+-------+----------------------------+
| stacked DA after mapped insert |  1048 | Column 'c1' cannot be null |
+--------------------------------+-------+----------------------------+
Когда обработчик условия заканчивается, его текущая область диагностики убрана из стека, и стековая область диагностики становится текущей областью диагностики в хранимой процедуре.

После возвращений процедуры таблица содержит две строки. Пустая строка следует из попытки вставить NULL, что было отображено на пустую строку:

+----------+
| c1       |
+----------+
| string 1 |
|          |
+----------+
В предыдущем примере первые два GET DIAGNOSTICS в пределах обработчика условия получают информацию из текущей и стековой областей диагностики и возвращают те же самые значения. Это не будет иметь место, если выполняются запросы, которые сбрасывают текущую область диагностики ранее в пределах обработчика. Предположите, что p() переписана, чтобы поместить DECLARE в пределах определения обработчика вместо того, чтобы предшествовать этому:
CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    -- Declare variables to hold diagnostics area information
    DECLARE errcount INT;
    DECLARE errno INT;
    DECLARE msg TEXT;
    GET CURRENT DIAGNOSTICS CONDITION 1
    errno = MYSQL_ERRNO, msg = MESSAGE_TEXT;
    SELECT 'current DA before mapped insert' AS op, errno, msg;
    GET STACKED DIAGNOSTICS CONDITION 1
    errno = MYSQL_ERRNO, msg = MESSAGE_TEXT;
    SELECT 'stacked DA before mapped insert' AS op, errno, msg;
    ...
В этом случае результат зависит от версии:

  • До MySQL 5.7.2 DECLARE не изменяет текущую область диагностики, таким образом, первые два GET DIAGNOSTICS возвращают тот же самый результат, так же, как в оригинальной версии p().

    В MySQL 5.7.2 работа была сделана, чтобы гарантировать, что все недиагностические запросы заполняют область диагностики по стандарту SQL. DECLARE один из них, таким образом, в 5.7.2 и выше выполнение запросов DECLARE в начале обработчика очищает текущую область диагностики и запросы GET DIAGNOSTICS приводят к различным результатам:

    +---------------------------------+-------+------+
    | op                              | errno | msg  |
    +---------------------------------+-------+------+
    | current DA before mapped insert |  NULL | NULL |
    +---------------------------------+-------+------+
    
    +---------------------------------+-------+----------------------------+
    | op                              | errno | msg                        |
    +---------------------------------+-------+----------------------------+
    | stacked DA before mapped insert |  1048 | Column 'c1' cannot be null |
    +---------------------------------+-------+----------------------------+
    

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

14.6.7.4. RESIGNAL

RESIGNAL [condition_value]
[SET signal_information_item
[, signal_information_item] ...]

condition_value:
SQLSTATE [VALUE] sqlstate_value
  | condition_name

signal_information_item:
condition_information_item_name = simple_value_specification

condition_information_item_name:
CLASS_ORIGIN
  | SUBCLASS_ORIGIN
  | MESSAGE_TEXT
  | MYSQL_ERRNO
  | CONSTRAINT_CATALOG
  | CONSTRAINT_SCHEMA
  | CONSTRAINT_NAME
  | CATALOG_NAME
  | SCHEMA_NAME
  | TABLE_NAME
  | COLUMN_NAME
  | CURSOR_NAME

condition_name, simple_value_specification:
(see following discussion)
RESIGNAL передает информацию о состоянии ошибки, которая доступна во время выполнения обработчика условия в пределах составного запроса в хранимой процедуре или функции, триггере или событии. RESIGNAL может изменить некоторую или всю информацию перед передачей этого. RESIGNAL связан с SIGNAL, но вместо того, чтобы породить условие как SIGNAL, RESIGNAL передает существующую информацию об условии, возможно после изменения этого.

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

Никакие специальные привилегии не требуются для RESIGNAL.

Все формы RESIGNAL требуют, чтобы текущий контекст был обработчиком условия. Иначе RESIGNAL будет ошибка RESIGNAL when handler not active.

См. разделы 14.6.7.3 и 14.6.7.7.

Для condition_value и signal_information_item определения и правила как для RESIGNAL и SIGNAL. Например, condition_value может быть SQLSTATE, значение могут указать на ошибки, предупреждения или not found . См. раздел 14.6.7.5.

RESIGNAL берет condition_value и SET, оба являются дополнительными. Это приводит к нескольким возможным применениям:

  • RESIGNAL один:

    RESIGNAL;
    
  • RESIGNAL с новой информацией о сигнале:
    RESIGNAL SET signal_information_item
             [, signal_information_item] ...;
    
  • RESIGNAL со значением условия и возможно новой информацией о сигнале:
    RESIGNAL condition_value
             [SET signal_information_item
             [, signal_information_item] ...];
    

Эти случаи использования изменяют области условия и диагностики:

  • Область диагностики содержит одну или более областей условия.

  • Область условия содержит единицы информации условия, такую как значения SQLSTATE, MYSQL_ERRNO или MESSAGE_TEXT.

Есть стек областей диагностики. Когда обработчик берет на себя управление, он продвигает область диагностики к вершине стека, таким образом во время выполнения обработчика есть две области диагностики:

  • Первая (текущая) область диагностики, которая запускается как копия последней области диагностики, но будет перезаписана первым запросом в обработчике, который изменяет текущую область диагностики.

  • Последняя (область диагностики, у которой есть области условия, которые были настроены перед запуском обработчика.

Максимальное количество областей условия в области диагностики определено значением max_error_count . См. раздел 14.6.7.7.5.

14.6.7.4.1. RESIGNAL

Простой RESIGNAL означает, что передает ошибку без изменений. Это восстанавливает последнюю область диагностики и делает это текущей областью диагностики. Таким образом, это помещает области диагностики в стек.

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

Пример:

DROP TABLE IF EXISTS xx;
delimiter //
CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    SET @error_count = @error_count + 1;
    IF @a = 0 THEN
       RESIGNAL;
    END IF;
  END;
  DROP TABLE xx;
END//
delimiter ;
SET @error_count = 0;
SET @a = 0;
CALL p();
Предположите, что запрос DROP TABLE xx терпит неудачу. Стек области диагностики похож на это:
DA 1. ERROR 1051 (42S02): Unknown table 'xx'
Тогда выполнение вызывает обработчик EXIT. Это запускается, продвигая область диагностики к вершине стека, который теперь похож на это:
DA 1. ERROR 1051 (42S02): Unknown table 'xx'
DA 2. ERROR 1051 (42S02): Unknown table 'xx'
В этом пункте содержание первых (текущих) и вторых областей диагностики то же самое. Первая область диагностики может быть изменена запросами, выполняющимися впоследствии в пределах обработчика.

Обычно запрос процедуры очищает первую область диагностики. BEGIN исключение, это не очищает, это ничего не делает. SET не исключение, это очищает, выполняет работу и приводит к результату success. Стек области диагностики теперь похож на это:

DA 1. ERROR 0000 (00000): Successful operation
DA 2. ERROR 1051 (42S02): Unknown table 'xx'
В этом пункте, если @a = 0, RESIGNAL помещает область диагностики в стек, который теперь похож на это:
DA 1. ERROR 1051 (42S02): Unknown table 'xx'
И именно это видит вызывающий.

Если @a не 0, обработчик просто заканчивается, что означает, что нет больше использования для текущей области диагностики (все обработано). Таким образом, это может быть выброшено, заставляя стековую область диагностики стать текущей областью диагностики снова. Стек области диагностики похож на это:

DA 1. ERROR 0000 (00000): Successful operation
Детали заставляют это выглядеть сложным, но конечный результат довольно полезен: обработчики могут выполниться, не разрушая информацию об условии, которое вызвало активацию обработчика.

14.6.7.4.2. RESIGNAL с новой информацией о сигнале

RESIGNAL с SET предоставляет новую информацию о сигнале, таким образом, запрос означает, что ошибку передают с изменениями:

RESIGNAL SET signal_information_item
         [, signal_information_item] ...;
Как с RESIGNAL идея состоит в том, чтобы вытолкать стек области диагностики так, чтобы оригинальная информация была снаружи. В отличие от простого RESIGNAL, что-либо определенное в SET вносит изменения.

Пример:

DROP TABLE IF EXISTS xx;
delimiter //
CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    SET @error_count = @error_count + 1;
    IF @a = 0 THEN
       RESIGNAL SET MYSQL_ERRNO = 5;
    END IF;
  END;
  DROP TABLE xx;
END//
delimiter ;
SET @error_count = 0;
SET @a = 0;
CALL p();
Помните из предыдущего обсуждения, что RESIGNAL результаты в области диагностики складывает как это:
DA 1. ERROR 1051 (42S02): Unknown table 'xx'
RESIGNAL SET MYSQL_ERRNO = 5 приводит к этому стеку:
DA 1. ERROR 5 (42S02): Unknown table 'xx'
Другими словами, это изменяет код ошибки и ничто иное.

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

14.6.7.4.3. RESIGNAL со значением условия и дополнительной новой информацией о сигнале

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

RESIGNAL condition_value
         [SET signal_information_item
         [, signal_information_item] ...];
Эта форма RESIGNAL восстанавливает последнюю область диагностики и делает это текущей областью диагностики. Таким образом, это поднимает стек области диагностики, который является тем же самым, как в простом RESIGNAL. Однако, это также изменяет область диагностики в зависимости от значения условия или информации о сигнале.

Пример:

DROP TABLE IF EXISTS xx;
delimiter //
CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    SET @error_count = @error_count + 1;
    IF @a = 0 THEN
       RESIGNAL SQLSTATE '45000' SET MYSQL_ERRNO=5;
    END IF;
  END;
  DROP TABLE xx;
END//
delimiter ;
SET @error_count = 0;
SET @a = 0;
SET @@max_error_count = 2;
CALL p();
SHOW ERRORS;
Это подобно предыдущему примеру и эффекты те же самые, за исключением того, что если RESIGNAL происходит, область текущего положения выглядит по-другому в конце. Причина: условие добавляется, а не заменяет существующее значение условия.

RESIGNAL включает значение условия (SQLSTATE '45000'), таким образом, это добавляет новую область условия, приводящую к стеку области диагностики, который похож на это:

DA 1. (condition 2) ERROR 1051 (42S02): Unknown table 'xx'
      (condition 1) ERROR 5 (45000) Unknown table 'xx'
Результат CALL p() и SHOW ERRORS:
mysql> CALL p();
ERROR 5 (45000): Unknown table 'xx'
mysql> SHOW ERRORS;
+-------+------+--------------------+
| Level | Code | Message            |
+-------+------+--------------------+
| Error | 1051 | Unknown table 'xx' |
| Error |    5 | Unknown table 'xx' |
+-------+------+--------------------+
14.6.7.4.4. RESIGNAL требует контекста обработчика условия

Все формы RESIGNAL требуют, чтобы текущий контекст был обработчиком условия. Иначе RESIGNAL происходит ошибка RESIGNAL when handler not active:

mysql> CREATE PROCEDURE p () RESIGNAL;
Query OK, 0 rows affected (0.00 sec)

mysql> CALL p();
ERROR 1645 (0K000): RESIGNAL when handler not active
Here is a more difficult example:
delimiter //
CREATE FUNCTION f () RETURNS INT
BEGIN
  RESIGNAL;
  RETURN 5;
END//

CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @a=f();
  SIGNAL SQLSTATE '55555';
END//
delimiter ;
CALL p();
RESIGNAL происходит в пределах сохраненной функции f(). Хотя f() непосредственно вызван в пределах контекста обработчика EXIT, выполнение в пределах f() имеет его собственный контекст, который не является контекстом обработчика. Таким образом, RESIGNAL в пределах f() приводит к ошибке handler not active.

14.6.7.5. SIGNAL

SIGNAL condition_value
[SET signal_information_item
[, signal_information_item] ...]

condition_value:
SQLSTATE [VALUE] sqlstate_value
  | condition_name

signal_information_item:
condition_information_item_name = simple_value_specification

condition_information_item_name:
CLASS_ORIGIN
  | SUBCLASS_ORIGIN
  | MESSAGE_TEXT
  | MYSQL_ERRNO
  | CONSTRAINT_CATALOG
  | CONSTRAINT_SCHEMA
  | CONSTRAINT_NAME
  | CATALOG_NAME
  | SCHEMA_NAME
  | TABLE_NAME
  | COLUMN_NAME
  | CURSOR_NAME
condition_name, simple_value_specification:
(see following discussion)
SIGNAL это способ вернуть ошибку. SIGNAL предоставляет информацию об ошибке обработчику, внешней части приложения или клиенту. Кроме того, это обеспечивает управление характеристиками ошибки (код ошибки, SQLSTATE, сообщение). Без SIGNAL необходимо обратиться к обходным решениям, таким как преднамеренное обращение к несуществующей таблице, чтобы заставить подпрограмму возвращать ошибку.

condition_value в SIGNAL указывает на ошибочное значение, которое будет возвращено. Это может быть SQLSTATE (5-символьная строка) или condition_name, которое обращается к названному условию, ранее определенному с DECLARE ... CONDITION (см. раздел 14.6.7.1).

SQLSTATE может указать на ошибки, предупреждения или not found. Первые два символа значения указывают на его ошибочный класс, как обсуждено в разделе 14.6.7.5.1. Некоторый сигнал оценивает завершение запроса, см. раздел 14.6.7.5.2.

SQLSTATE для SIGNAL не должно начинаться с '00' потому, что такие значения указывают на успех и недопустимы для того, чтобы сигнализировать ошибку. Это истина для указания SQLSTATE в SIGNAL или в названном условии, упомянутом в запросе. Если значение недопустимо, будет ошибка Bad SQLSTATE.

SIGNAL произвольно включает SET, который содержит многократные элементы сигнала в списке разделенных запятой значений condition_information_item_name = simple_value_specification.

Каждый condition_information_item_name может быть определен только однажды в SET. Иначе будет ошибка Duplicate condition information item.

Допустимые указатели simple_value_specification могут быть определены, используя хранимую процедуру или функциональные параметры, местные переменные, объявленные с DECLARE, определяемые пользователем переменные, системные переменные или литералы. Символьный литерал может включать _charset.

См. раздел 14.6.7.5.1 .

Следующая процедура сигнализирует ошибку или предупреждение в зависимости от значения pval:

CREATE PROCEDURE p (pval INT)
BEGIN
  DECLARE specialty CONDITION FOR SQLSTATE '45000';
  IF pval = 0 THEN SIGNAL SQLSTATE '01000';
  ELSEIF pval = 1 THEN
    SIGNAL SQLSTATE '45000'
    SET MESSAGE_TEXT = 'An error occurred';
  ELSEIF pval = 2 THEN
    SIGNAL specialty
    SET MESSAGE_TEXT = 'An error occurred';
  ELSE
    SIGNAL SQLSTATE '01000'
    SET MESSAGE_TEXT = 'A warning occurred', MYSQL_ERRNO = 1000;
    SIGNAL SQLSTATE '45000'
    SET MESSAGE_TEXT = 'An error occurred', MYSQL_ERRNO = 1001;
  END IF;
END;
Если pval = 0, p() сигнализирует предупреждение, потому что значения SQLSTATE, которые начинаются с '01' это сигналы в классе предупреждения. Предупреждение не заканчивает процедуру, и может быть замечено с SHOW WARNINGS после завершения процедуры.

Если pval = 1, p() сигнализирует ошибку и устанавливает MESSAGE_TEXT. Ошибка заканчивает процедуру, и текст возвращен с информацией об ошибке.

Если pval = 2, та же самая ошибка сообщена, хотя значение SQLSTATE определено, используя названное условие в этом случае.

Если pval что-то другое, p() сначала выдает предупреждение и ставит текст сообщения с кодом ошибки. Это предупреждение не заканчивает процедуру, таким образом, выполнение продолжается и p() сигнализирует ошибку. Ошибка действительно заканчивает процедуру. Текст сообщения и код ошибки, установленный предупреждением, заменены значениями, установленными ошибкой, которые возвращены с информацией об ошибке.

SIGNAL, как правило, используется в пределах сохраненных программ, но это расширение MySQL, потому что этому разрешают внешний контекст обработчика. Например, если Вы вызываете mysql, Вы можете ввести любой из этих запросов при подсказке:

mysql> SIGNAL SQLSTATE '77777';
mysql> CREATE TRIGGER t_bi BEFORE INSERT ON t
    ->        FOR EACH ROW SIGNAL SQLSTATE '77777';
mysql> CREATE EVENT e ON SCHEDULE EVERY 1 SECOND
    ->        DO SIGNAL SQLSTATE '77777';
SIGNAL выполняет согласно следующим правилам:

Если SIGNAL указывает на SQLSTATE, то значение используется, чтобы сигнализировать определенное условие. Пример:

CREATE PROCEDURE p (divisor INT)
BEGIN
  IF divisor = 0 THEN
     SIGNAL SQLSTATE '22012';
  END IF;
END;
Если SIGNAL использует названное условие, это условие должно быть объявлено в некотором контексте, который относится к SIGNAL, и должно быть определено, используя значение SQLSTATE, а не код ошибки MySQL. Пример:
CREATE PROCEDURE p (divisor INT)
BEGIN
  DECLARE divide_by_zero CONDITION FOR SQLSTATE '22012';
  IF divisor = 0 THEN
     SIGNAL divide_by_zero;
  END IF;
END;
Если названное условие не существует в пределах SIGNAL, будет ошибка Undefined CONDITION.

Если SIGNAL обращается к названному условию, которое определено с кодом ошибки MySQL, а не значением SQLSTATE, будет ошибка SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE. Следующие запросы вызывают эту ошибку, потому что названное условие связано с кодом ошибки MySQL:

DECLARE no_such_table CONDITION FOR 1051;
SIGNAL no_such_table;
Если условие с именем объявлено многократно в различных контекстах, декларация с самым местным контекстом применяется. Рассмотрите следующую процедуру:
CREATE PROCEDURE p (divisor INT)
BEGIN
  DECLARE my_error CONDITION FOR SQLSTATE '45000';
  IF divisor = 0 THEN BEGIN
     DECLARE my_error CONDITION FOR SQLSTATE '22012';
     SIGNAL my_error;
  END;
  END IF;
  SIGNAL my_error;
END;
Если divisor = 0, первый SIGNAL выполняется. Самая внутренняя декларация условия my_error применяется, поднимая SQLSTATE '22012'.

Если divisor не 0, второй SIGNAL выполняется. Наиболее удаленная декларация условия my_error применяется, поднимая SQLSTATE '45000'.

См. раздел 14.6.7.6.

Сигналы могут быть подняты в пределах обработчиков исключения:

CREATE PROCEDURE p ()
BEGIN
  DECLARE EXIT HANDLER FOR SQLEXCEPTION
  BEGIN
    SIGNAL SQLSTATE VALUE '99999'
    SET MESSAGE_TEXT = 'An error occurred';
  END;
  DROP TABLE no_such_table;
END;
CALL p() достигает DROP TABLE . Нет никакой таблицы no_such_table, таким образом, ошибочный обработчик активирован. Ошибочный обработчик разрушает оригинальную ошибку (no such table) и делает новую ошибку с SQLSTATE '99999' и сообщением An error occurred.

14.6.7.5.1. Единицы информации условия сигнала

Следующая таблица приводит названия единиц информации условия области диагностики, которые могут быть установлены в SIGNAL (или RESIGNAL). Все элементы стандартный SQL кроме MYSQL_ERRNO, который является расширением MySQL. Для получения дополнительной информации об этих элементах см. раздел 14.6.7.7.

Item Name           Definition
---------           ----------
CLASS_ORIGIN        VARCHAR(64)
SUBCLASS_ORIGIN     VARCHAR(64)
CONSTRAINT_CATALOG  VARCHAR(64)
CONSTRAINT_SCHEMA   VARCHAR(64)
CONSTRAINT_NAME     VARCHAR(64)
CATALOG_NAME        VARCHAR(64)
SCHEMA_NAME         VARCHAR(64)
TABLE_NAME          VARCHAR(64)
COLUMN_NAME         VARCHAR(64)
CURSOR_NAME         VARCHAR(64)
MESSAGE_TEXT        VARCHAR(128)
MYSQL_ERRNO         SMALLINT UNSIGNED
Набор символов для символьных элементов UTF-8.

Незаконно назначить NULL к единице информации условия в SIGNAL.

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

  • Class = '00' (success)

    Незаконный. SQLSTATE, которые начинаются с '00' указывают на успех и недопустимы для SIGNAL.

  • Class = '01' (warning)
    MESSAGE_TEXT = 'Unhandled user-defined warning condition';
    MYSQL_ERRNO = ER_SIGNAL_WARN
    
  • Class = '02' (not found)
    MESSAGE_TEXT = 'Unhandled user-defined not found condition';
    MYSQL_ERRNO = ER_SIGNAL_NOT_FOUND
    
  • Class > '02' (exception)
    MESSAGE_TEXT = 'Unhandled user-defined exception condition';
    MYSQL_ERRNO = ER_SIGNAL_EXCEPTION
    

Для допустимых классов другие единицы информации условия установлены следующим образом:

CLASS_ORIGIN = SUBCLASS_ORIGIN = '';
CONSTRAINT_CATALOG = CONSTRAINT_SCHEMA = CONSTRAINT_NAME = '';
CATALOG_NAME = SCHEMA_NAME = TABLE_NAME = COLUMN_NAME = '';
CURSOR_NAME = '';
Ошибочные значения, которые доступны после выполнения SIGNAL передают значение SQLSTATE, поднятое SIGNAL и его элементы MESSAGE_TEXT и MYSQL_ERRNO. Эти значения доступны из C API:

Из SQL вывод SHOW WARNINGS и SHOW ERRORS указывает значения MYSQL_ERRNO и MESSAGE_TEXT в столбцах Code и Message.

Чтобы получить информацию из области диагностики, используйте GET DIAGNOSTICS (см. раздел 14.6.7.3).

14.6.7.5.2. Эффект сигналов на обработчиках, курсорах и запросах

Сигналы имеют различные эффекты на выполнение запросов в зависимости от класса сигнала. Класс определяет, насколько серьезна ошибка. MySQL игнорирует значение sql_mode, в частности, строгий режим SQL не имеет значения. MySQL также игнорирует IGNORE: SIGNAL должен поднять произведенную пользователем ошибку явно, таким образом, сигнал никогда не игнорируется.

В следующих описаниях unhandled значит, что никакой обработчик для сообщенного SQLSTATE не было определен с DECLARE ... HANDLER.

  • Class = '00' (success)

    Незаконный. SQLSTATE, которые начинаются с '00', указывают на успех и недопустимы для SIGNAL .

  • Class = '01' (warning)

    Значение warning_count увеличивается. SHOW WARNINGS показывает сигнал. SQLWARNING ловит сигнал. Если сигнал не обработан в функции, запросы не заканчиваются.

  • Class = '02' (not found)

    NOT FOUND ловит сигнал. Нет никакого эффекта на курсоры. Если сигнал не обработан в функции, запрос закончен.

  • Class > '02' (exception)

    SQLEXCEPTION ловит сигнал. Если сигнал не обработан в функции, запрос закончен.

  • Class = '40'

    Обработан как обычное исключение.

Пример:

mysql> delimiter //
mysql> CREATE FUNCTION f () RETURNS INT
    -> BEGIN
    ->   SIGNAL SQLSTATE '01234';  -- signal a warning
    ->   RETURN 5;
    -> END//
mysql> delimiter ;
mysql> CREATE TABLE t (s1 INT);
mysql> INSERT INTO t VALUES (f());
Результат состоит в том, что строка, содержащая 5, вставлена в таблицу t. Предупреждение, которое сообщено, может быть рассмотрено с SHOW WARNINGS.

14.6.7.6. Правила контекста для обработчиков

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

  • Обработчик, объявленный в BEGIN ... END, находится в контексте только для запросов SQL после деклараций обработчика в блоке. Если сам обработчик поднимает условие, он не может обработать условие, не могут и любые другие обработчики, объявленные в блоке. В следующем примере обработчики H1 и H2 находятся в контексте для условий, поднятых запросами stmt1 и stmt2. Но ни один из H1 и H2 не находятся в контексте для условий, поднятых в теле H1 или H2.

    BEGIN -- outer block
      DECLARE EXIT HANDLER FOR ...;  -- handler H1
      DECLARE EXIT HANDLER FOR ...;  -- handler H2
      stmt1;
      stmt2;
    END;
    
  • Обработчик находится в контексте только для блока, в котором это объявлено, и не может быть активирован для условий, происходящих вне этого блока. В следующем примере обработчик H1 находится в контексте для stmt1 во внутреннем блоке, но не для stmt2 во внешнем блоке:
    BEGIN -- outer block
      BEGIN -- inner block
        DECLARE EXIT HANDLER FOR ...;  -- handler H1
        stmt1;
      END;
      stmt2;
    END;
    
  • Обработчик может быть определенным или общим. Определенный обработчик для кода ошибки MySQL, значения SQLSTATE или имени условия. Общий обработчик для условия в классе SQLWARNING, SQLEXCEPTION или NOT FOUND. Специфика условия связана с приоритетом условия, как описано позже.

Многократные обработчики могут быть объявлены в различных контекстах и с различными спецификами. Например, мог бы быть определенный обработчик кода ошибки MySQL во внешнем блоке и общий обработчик SQLWARNING во внутреннем блоке. Или могли бы быть обработчики для определенного кода ошибки MySQL и общий для класса SQLWARNING в том же самом блоке.

Активирован ли обработчик, зависит не только от его собственного контекста и значения условия, но и от того, что присутствуют другие обработчики. Когда условие происходит в сохраненной программе, сервер ищет применимые обработчики в текущем контексте (текущем блоке BEGIN ... END). Если нет никаких применимых обработчиков, поиск продолжается направленный наружу с обработчиками в каждом последовательном контексте (блоке). Когда сервер находит один или более применимых обработчиков в данном контексте, он выбирает среди них, исходя из приоритета:

  • Обработчик кода ошибки MySQL имеет приоритет перед SQLSTATE.

  • Обработчик значения SQLSTATE имеет приоритет перед общим обработчиком SQLWARNING, SQLEXCEPTION или NOT FOUND.
  • SQLEXCEPTION имеет приоритет перед SQLWARNING.
  • Возможно иметь несколько применимых обработчиков с тем же самым приоритетом. Например, запрос может произвести многократные предупреждения с различными кодами ошибки, для каждого из которых существует определенный для ошибки обработчик. В этом случае выбор обработчика сервером не определен и может измениться в зависимости от обстоятельств, при которых происходит условие.

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

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

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

  • SQLWARNING: программа продолжает выполняться, как будто был CONTINUE.
  • NOT FOUND: если условие обычно поднималось, действие CONTINUE. Если это было поднято SIGNAL или RESIGNAL, действие EXIT .

Следующие примеры демонстрируют, как MySQL применяет правила выбора обработчика.

Эта процедура содержит два обработчика, один для определенного значения SQLSTATE ('42S02') происходит для попыток удалить несуществующую таблицу, и один для общего класса SQLEXCEPTION:

CREATE PROCEDURE p1()
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
  SELECT 'SQLSTATE handler was activated' AS msg;
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
  SELECT 'SQLEXCEPTION handler was activated' AS msg;
  DROP TABLE test.t;
END;
Оба обработчика объявлены в том же самом блоке и имеют тот же самый контекст. Однако, SQLSTATE имеет приоритет над SQLEXCEPTION, так что, если таблица t не существует, DROP TABLE поднимает условие, которое активируется SQLSTATE:
mysql> CALL p1();
+--------------------------------+
| msg                            |
+--------------------------------+
| SQLSTATE handler was activated |
+--------------------------------+
Эта процедура содержит те же самые два обработчика. Но на сей раз, DROP TABLE и SQLEXCEPTION находятся во внутреннем блоке относительно SQLSTATE:
CREATE PROCEDURE p2()
BEGIN -- outer block
  DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
  SELECT 'SQLSTATE handler was activated' AS msg;
  BEGIN -- inner block
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
    SELECT 'SQLEXCEPTION handler was activated' AS msg;
    DROP TABLE test.t; -- occurs within inner block
  END;
END;
В этом случае обработчик, который является более местным, где условие происходит, имеет приоритет. SQLEXCEPTION активируется, даже при том, что это является более общим, чем SQLSTATE:
mysql> CALL p2();
+------------------------------------+
| msg                                |
+------------------------------------+
| SQLEXCEPTION handler was activated |
+------------------------------------+
В этой процедуре один из обработчиков объявлен в блоке, внутреннем к контексту DROP TABLE:
CREATE PROCEDURE p3()
BEGIN -- outer block
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
  SELECT 'SQLEXCEPTION handler was activated' AS msg;
  BEGIN -- inner block
    DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
    SELECT 'SQLSTATE handler was activated' AS msg;
  END;
  DROP TABLE test.t; -- occurs within outer block
END;
Только SQLEXCEPTION применяется, потому что другой не находится в контексте для условия, поднятого DROP TABLE:
mysql> CALL p3();
+------------------------------------+
| msg                                |
+------------------------------------+
| SQLEXCEPTION handler was activated |
+------------------------------------+
В этой процедуре оба обработчика объявлены в блоке, внутреннем к контексту DROP TABLE:
CREATE PROCEDURE p4()
BEGIN -- outer block
  BEGIN -- inner block
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
    SELECT 'SQLEXCEPTION handler was activated' AS msg;
    DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02'
    SELECT 'SQLSTATE handler was activated' AS msg;
  END;
  DROP TABLE test.t; -- occurs within outer block
END;
Никакой обработчик не применяется, потому что они не находятся в контексте для DROP TABLE. Условие, поднятое запросом, идет необработанное и заканчивает процедуру с ошибкой:
mysql> CALL p4();
ERROR 1051 (42S02): Unknown table 'test.t'

14.6.7.7. Область диагностики MySQL

Запросы SQL производят диагностическую информацию, которая заполняет область диагностики. У стандартного SQL есть стек области диагностики, содержащий область диагностики для каждого вложенного контекста выполнения. Стандартный SQL также поддерживает GET STACKED DIAGNOSTICS для того, чтобы обратиться к второй области диагностики во время выполнения обработчика условия. MySQL поддерживает STACKED с MySQL 5.7.

Этот раздел описывает структуру области диагностики в MySQL, единицы информации, признанные MySQL, как запросы, устанавливает область диагностики и то, как области диагностики продвинуты в стек.

14.6.7.7.1. Структура области диагностики

Область диагностики содержит два вида информации:

  • Информация о запросе, такая как число условий, которые произошли, или количество затронутых строк.

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

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

Statement information:
  row count
  ... other statement information items ...
Condition area list:
  Condition area 1:
error code for condition 1
error message for condition 1
... other condition information items ...
  Condition area 2:
error code for condition 2:
error message for condition 2
... other condition information items ...
  Condition area 3:
error code for condition 3
error message for condition 3
... other condition information items ...
14.6.7.7.2. Элементы информации в области диагностики

Область диагностики содержит единицы информации условия и запрос. Числовые элементы это целые числа. Набор символов для символьных элементов UTF-8. Никакой элемент не может быть NULL. Если элемент запросы или условия не установлены запросом, который заполняет область диагностики, ее значение 0 или пустая строка, в зависимости от типа данных элемента.

Часть информации о запросе области диагностики содержит эти элементы:

  • NUMBER: Целое число, указывающее на число областей условия, у которых есть информация.

  • ROW_COUNT: Целое число, указывающее на число строк, затронутых запросом. ROW_COUNT имеет то же самое значение, как функция ROW_COUNT() (см. раздел 13.14).

Часть информации об условии области диагностики содержит область условия для каждого условия. Области условия пронумерованы от 1 до значения NUMBER. Если NUMBER = 0, нет никаких областей условия.

Каждая область условия содержит элементы в следующем списке. Все элементы из стандарта SQL, кроме MYSQL_ERRNO, который является расширением MySQL. Определения просят условия, произведенные не сигналом (то есть, SIGNAL или RESIGNAL). Для условий не от сигнала MySQL заполняет только те элементы условия, которые не описаны как всегда пустые. Эффекты сигналов на области условия описаны позже.

  • CLASS_ORIGIN: Строка, содержащая класс значения RETURNED_SQLSTATE. Если RETURNED_SQLSTATE начинается со значения класса, определенного в SQL ISO 9075-2 (раздел 24.1), CLASS_ORIGIN = 'ISO 9075'. Иначе CLASS_ORIGIN = 'MySQL'.

  • SUBCLASS_ORIGIN: Строка, содержащая подкласс RETURNED_SQLSTATE. Если CLASS_ORIGIN = 'ISO 9075' или RETURNED_SQLSTATE заканчивается на '000', SUBCLASS_ORIGIN = 'ISO 9075'. Иначе SUBCLASS_ORIGIN = 'MySQL'.
  • RETURNED_SQLSTATE: Строка, которая указывает значение SQLSTATE для условия.
  • MESSAGE_TEXT: Строка, которая указывает на сообщение об ошибке для условия.
  • MYSQL_ERRNO: Целое число, которое указывает на код ошибки MySQL для условия.
  • CONSTRAINT_CATALOG, CONSTRAINT_SCHEMA, CONSTRAINT_NAME: Строки, которые указывают на каталог, схему и название нарушенного ограничения. Они всегда пусты.
  • CATALOG_NAME, SCHEMA_NAME, TABLE_NAME, COLUMN_NAME: Строки, которые указывают на каталог, схему, таблицу и столбец, связанные с условием. Они всегда пусты.
  • CURSOR_NAME: Строка, которая указывает на имя курсора. Это всегда пусто.

Для RETURNED_SQLSTATE, MESSAGE_TEXT и MYSQL_ERRNO для особых ошибок см. раздел B.3.

Если SIGNAL (или RESIGNAL) заполняет область диагностики, SET может назначить любую единицу информации условия, кроме RETURNED_SQLSTATE. SIGNAL также ставит RETURNED_SQLSTATE, но не непосредственно в SET. То значение прибывает из параметра SQLSTATE SIGNAL.

SIGNAL также ставит единицы информации запроса. Если number = 1, то ROW_COUNT = -1 для ошибок и 0 иначе.

14.6.7.7.3. Как заполнена область диагностики

Недиагностические запросы SQL заполняют область диагностики автоматически, ее содержание может быть установлено явно с SIGNAL и RESIGNAL. Область диагностики может быть исследована с GET DIAGNOSTICS, чтобы извлечь определенные элементы, или с SHOW WARNINGS или SHOW ERRORS, чтобы видеть условия или ошибки.

Запросы SQL определяют область диагностики следующим образом:

  • Когда сервер начинает выполнять запрос после парсинга, это очищает область диагностики для недиагностических запросов. Диагностические запросы не очищают область диагностики (SHOW WARNINGS, SHOW ERRORS , GET DIAGNOSTICS).

  • Если запрос поднимает условие, область диагностики очищена от условий, которые принадлежат более ранним запросам. Исключение: условия, поднятые GET DIAGNOSTICS и RESIGNAL добавлены к области диагностики, не очищая ее.

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

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

DROP TABLE очищает область диагностики и заполняет ее, когда условие происходит:

mysql> DROP TABLE IF EXISTS test.no_such_table;
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> SHOW WARNINGS;
+-------+------+------------------------------------+
| Level | Code | Message                            |
+-------+------+------------------------------------+
| Note  | 1051 | Unknown table 'test.no_such_table' |
+-------+------+------------------------------------+
1 row in set (0.00 sec)
SET производит ошибку, таким образом, очищает и заполняет область диагностики:
mysql> SET @x = @@x;
ERROR 1193 (HY000): Unknown system variable 'x'

mysql> SHOW WARNINGS;
+-------+------+-----------------------------+
| Level | Code | Message                     |
+-------+------+-----------------------------+
| Error | 1193 | Unknown system variable 'x' |
+-------+------+-----------------------------+
1 row in set (0.00 sec)
SET произвел единственное условие, таким образом, 1 это единственное допустимое число условий для GET DIAGNOSTICS . Следующий запрос использует число условия 2, которое производит предупреждение, добавленное к области диагностики, не очищая ее:
mysql> GET DIAGNOSTICS CONDITION 2 @p = MESSAGE_TEXT;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> SHOW WARNINGS;
+-------+------+------------------------------+
| Level | Code | Message                      |
+-------+------+------------------------------+
| Error | 1193 | Unknown system variable 'xx' |
| Error | 1753 | Invalid condition number     |
+-------+------+------------------------------+
2 rows in set (0.00 sec)
Теперь есть два условия в области диагностики, таким образом, тот же самый GET DIAGNOSTICS работает:
mysql> GET DIAGNOSTICS CONDITION 2 @p = MESSAGE_TEXT;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @p;
+--------------------------+
| @p                       |
+--------------------------+
| Invalid condition number |
+--------------------------+
1 row in set (0.01 sec)
14.6.7.7.4. Как работает стек области диагностики

Когда происходит помещение области диагностики в стек, первая (текущая) область диагностики становится второй областью диагностики, и новая текущая область диагностики создается как копия этого. Области диагностики продвинуты в стек и извлечены из стека при следующих обстоятельствах:

  • Выполнение сохраненной программы.

    Помещение происходит прежде, чем программа выполняется, а выталкивание происходит позже. Если сохраненная программа заканчивается в то время, как обработчики выполняются, может быть больше, чем одна область диагностики: это происходит из-за исключения, для которого нет никаких соответствующих обработчиков, или из-за RETURN в обработчике.

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

  • Выполнение обработчика условия в пределах сохраненной программы.

    Когда помещение в стек происходит в результате активации обработчика условия, стековая область диагностики это область, которая была актуальна в пределах сохраненной программы до того. Новая теперь текущая область диагностики эир текущая область диагностики обработчика. GET [CURRENT] DIAGNOSTICS и GET STACKED DIAGNOSTICS может использоваться в пределах обработчика, чтобы получить доступ к содержанию текущей (обработчик) и стековой (сохраненная программа) области диагностики. Первоначально они возвращают тот же самый результат, но выполнение запросов в пределах обработчика изменяет текущую область диагностики, очищаяя и устанавливая ее содержание согласно нормальным правилам (см. раздел 14.6.7.7.3 ). Стековая область диагностики не может быть изменена выполнением запросов в пределах обработчика, кроме RESIGNAL.

    Если обработчик выполняется успешно, текущая (обработчик), область диагностики возвращена, а стековая (сохраненная программа) область диагностики снова становится текущей областью диагностики. Условия, добавленные к области диагностики обработчика во время выполнения обработчика, добавлены к текущей области диагностики.

  • Исполнение RESIGNAL.

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

14.6.7.7.5. Системные переменные, связанные с областью диагностики

Определенные системные переменные управляют или связаны с некоторыми аспектами области диагностики:

  • max_error_count управляет числом областей условия в области диагностики. Если больше условий происходит, MySQL тихо отказывается от информации для лишних условий. Условия, добавленные RESIGNAL , всегда добавляются с удалением более старых условий по мере необходимости, чтобы создать место.

  • warning_count указывает на число условий, которые произошли. Это включает ошибки, предупреждения и примечания. Обычно NUMBER и warning_count равны. Однако, поскольку число произведенных условий превышает max_error_count, значение warning_count продолжает повышаться тогда, как NUMBER остается равным max_error_count, потому что никакие дополнительные условия не сохранены в области диагностики.
  • error_count указывает на число ошибок, которые произошли. Это значение включает not found и условия исключения, но исключает предупреждения и примечания. Как warning_count, это значение может превысить max_error_count.
  • Если sql_notes=0, примечания не сохранены и не увеличивают warning_count.

Пример: Если max_error_count = 10, область диагностики может содержать максимум 10 областей условия. Предположите, что запрос поднимает 20 условий, 12 из которых являются ошибками. В этом случае область диагностики содержит первые 10 условий, NUMBER = 10, warning_count = 20, error_count = 12.

Изменения max_error_count не имеют никакого эффекта до следующей попытки изменить область диагностики. Если область диагностики содержит 10 областей условия и max_error_count = 5, это не имеет никакого непосредственного эффекта на размер или контент области диагностики.

14.7. Запросы управления базами данных

14.7.1. Запросы управления учетными записями

Информация учетной записи MySQL хранится в таблицах базы данных mysql. Эта база данных и система управления доступом обсуждены в главе 6.

Некоторые выпуски MySQL вводят изменения структуры таблиц, чтобы добавить новые привилегии или особенности. Чтобы гарантировать, что Вы можете использовать любые новые способности, обновите свои таблицы, чтобы иметь текущую структуру всякий раз, когда Вы обновляете к новой версии MySQL. См. раздел 5.4.5.

Когда read_only включена, запросы управления требуют привилегии SUPER в дополнение к любым другим необходимым привилегиям. Это потому, что они изменяют таблицы в базе данных mysql.

14.7.1.1. ALTER USER

ALTER USER [IF EXISTS]
user_specification [, user_specification] ...
[REQUIRE {NONE | tls_option [[AND] tls_option] ...}]
[WITH resource_option [resource_option] ...]
[password_option | lock_option] ...

ALTER USER [IF EXISTS]
USER() IDENTIFIED BY 'auth_string'

ALTER USER [IF EXISTS]
user DEFAULT ROLE
{NONE | ALL | role [, role ] ...}

user_specification:
user [ auth_option ]

auth_option: {
IDENTIFIED BY 'auth_string'
  | IDENTIFIED WITH auth_plugin
  | IDENTIFIED WITH auth_plugin BY 'auth_string'
  | IDENTIFIED WITH auth_plugin AS 'hash_string'
}

tls_option: {
   SSL
 | X509
 | CIPHER 'cipher'
 | ISSUER 'issuer'
 | SUBJECT 'subject'
}

resource_option: {
MAX_QUERIES_PER_HOUR count
  | MAX_UPDATES_PER_HOUR count
  | MAX_CONNECTIONS_PER_HOUR count
  | MAX_USER_CONNECTIONS count
}

password_option: {
PASSWORD EXPIRE
  | PASSWORD EXPIRE DEFAULT
  | PASSWORD EXPIRE NEVER
  | PASSWORD EXPIRE INTERVAL N DAY
}

lock_option: {
ACCOUNT LOCK
  | ACCOUNT UNLOCK
}
ALTER USER изменяет учетные записи MySQL. Это позволяет аутентификации, SSL/TLS, пределу ресурсов и свойствам пароля быть измененными для существующих учетных записей и включает блокировку учетной записи.

За исключением DEFAULT ROLE, ALTER USER требует глобальной привилегии CREATE USER или UPDATE для базы данных mysql. Для DEFAULT ROLE ALTER USER требует этих привилегий:

  • Установить роль по умолчанию для другого пользователя: глобальная CREATE USER или UPDATE для mysql.default_roles.

  • Установить роль значения по умолчанию для вас непосредственно: Никакие специальные привилегии, пока роль, которую Вы хотите, как значение по умолчанию, не предоставили Вам.

Когда включена read_only , ALTER USER требует привилегию SUPER.

Ошибка происходит, если Вы пытаетесь изменить учетную запись, которая не существует. IF EXISTS заставляет запрос производить предупреждение для каждой названной учетной записи, которая не существует, а не ошибку.

ALTER USER меняет строку таблицы mysql.user для каждой затронутой учетной записи согласно опциям, определенным в запросе. Неуказанные свойства сохраняют свое текущее значение.

Пример 1: Измените пароль учетной записи. В результате пользователь должен соединиться с названным паролем и выбрать новый в следующем соединении:

ALTER USER 'jeffrey'@'localhost'
      IDENTIFIED BY 'new_password' PASSWORD EXPIRE;
Пример 2: Измените учетную запись для применения ее плагина аутентификации sha256_password и данного пароля. Потребуйте, чтобы новый пароль был выбран каждые 180 дней:
ALTER USER 'jeffrey'@'localhost'
      IDENTIFIED WITH sha256_password BY 'new_password'
      PASSWORD EXPIRE INTERVAL 180 DAY;
Пример 3: Заблокируйте или разблокируйте учетную запись:
ALTER USER 'jeffrey'@'localhost' ACCOUNT LOCK;
ALTER USER 'jeffrey'@'localhost' ACCOUNT UNLOCK;
Пример 4: Потребуйте, чтобы учетная запись использовала SSL и установите предел 20 соединений в час:
ALTER USER 'jeffrey'@'localhost'
      REQUIRE SSL WITH MAX_CONNECTIONS_PER_HOUR 20;

При некоторых обстоятельствах ALTER USER может быть зарегистрирован в журналах сервера или на стороне клиента в файле истории, например, в ~/.mysql_history, что означает, что пароли открытого текста могут быть считаны любым имеющим доступ к этой информации. Для информации об условиях, при которых это происходит для журналов сервера и как управлять этим см. раздел 7.1.2.3. Для подобной информации о клиентском журналировании см. раздел 5.5.1.3.

Каждое имя учетной записи использует формат, описанный в разделе 7.2.3. Если Вы определяете только часть имени пользователя имени учетной записи, часть имени хоста '%'. Также возможно определить CURRENT_USER или CURRENT_USER(), чтобы ссылаться на учетную запись, связанную с текущим сеансом.

Для одного синтаксиса учетная запись может быть определена с помощью USER():

ALTER USER USER() IDENTIFIED BY 'auth_string';
Этот синтаксис позволяет изменить Ваш собственный пароль, не называя Вашу учетную запись буквально.

Каждый параметр user_specification состоит из имени учетной записи и дополнительного auth_option, которое определяет, как учетная запись подтверждает подлинность. Эти значения позволяют плагинам аутентификации учетной записи быть определенными. Каждый auth_option применяется только к пользователю, названному перед этим.

После пользовательских технических требований запрос может включать опции для SSL/TLS, предела ресурса, истечения пароля и свойств блокировки. Все эти опции глобальны для запроса и относятся ко всем названным пользователям.

Пример: Это запрос изменяет пароль для jeffrey, но не для jeanne. Для обеих учетных записей соединения обязаны использовать SSL, и каждая учетная запись может использоваться максимум для двух одновременных соединений:

ALTER USER 'jeffrey'@'localhost' IDENTIFIED BY 'new_password',
      'jeanne'@'localhost' REQUIRE SSL WITH MAX_USER_CONNECTIONS 2;
В отсутствие особого типа опции учетная запись остается неизменной в этом отношении. Например, без опции блокировки, статус блокировки учетной записи не изменен.

Есть несколько аспектов ALTER USER, описанных в этом разделе:

Опции аутентификации

Имя учетной записи может сопровождаться опцией аутентификации, которая определяет плагин аутентификации учетной записи:

  • auth_plugin называет плагин аутентификации. Имя может быть заключенной в кавычки буквальной строкой или именем. Имена сохранены в столбце plugin таблицы mysql.user.

  • 'auth_string' или 'hash_string' указывает пароль как открытый текст или хешированный в формате, ожидаемом плагином аутентификации, соответственно. Данные сохранены в столбец authentication_string таблицы mysql.user.

ALTER USER разрешает такие форматы auth_option:

  • IDENTIFIED BY 'auth_string'

    Устанавливает плагин аутентификации учетной записи в плагин по умолчанию, хеширует открытый текст 'auth_string' и и хранит результат в строке mysql.user учетной записи.

  • IDENTIFIED WITH auth_plugin

    Устанавливает плагин аутентификации учетной записи в auth_plugin, очищает пароль к пустой строке (пароль связан со старым плагином аутентификации, а не новым) и хранит результат в строке mysql.user учетной записи.

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

  • IDENTIFIED WITH auth_plugin BY 'auth_string'

    Устанавливает плагин аутентификации учетной записи в auth_plugin, хеширует открытый текст 'auth_string' и хранит результат в строке mysql.user учетной записи.

  • IDENTIFIED WITH auth_plugin AS 'hash_string'

    Устанавливает плагин аутентификации учетной записи в auth_plugin, берет хешированный пароль 'hash_string' как есть и хранит результат в строке mysql.user учетной записи. Строка пароля, как предполагается, уже хеширована в формате, требуемом плагином.

Плагин по умолчанию mysql_native_password, если переменная default_authentication_plugin не установлена иначе. Для описаний каждого плагина см. раздел 7.5.1.

Пример 1: Определите пароль как открытый текст, плагин по умолчанию используется:

ALTER USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass';
Пример 2: Определите плагин аутентификации, наряду со значением пароля открытого текста:
ALTER USER 'jeffrey'@'localhost' IDENTIFIED WITH mysql_native_password
      BY 'mypass';
Пример 3: Определите плагин аутентификации, наряду с хешированным значением пароля:
ALTER USER 'jeffrey'@'localhost' IDENTIFIED WITH mysql_native_password
      AS '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4';
Опции SSL/TLS

MySQL может проверить признаки сертификата X509 в дополнение к обычной аутентификации, которая основана на имени пользователя и пароле. Для вводной информации об использовании SSL с MySQL см. раздел 7.4.

Чтобы определить опции SSL для учетной записи MySQL, используйте REQUIRE, который определяет одну или больше tls_option.

ALTER USER разрешает значения tls_option:

  • NONE

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

    Клиент должен определить только опцию --ssl-mode=REQUIRED, чтобы получить зашифрованное соединение. Попытка соединения терпит неудачу, если SSL недоступен.

  • SSL

    Говорит серверу разрешать только зашифрованные соединения для учетной записи.

    ALTER USER 'jeffrey'@'localhost' REQUIRE SSL;
    
    Клиент должен определить только --ssl-mode=REQUIRED , чтобы получить зашифрованное соединение. Попытка соединения терпит неудачу, если SSL недоступен.
  • X509

    Требует, чтобы у клиента был допустимый сертификат, но точный сертификат, выпускающий и объект не имеют значения. Единственное требование: должно быть возможно проверить свою подпись с одним из сертификатов CA. Использование сертификатов X509 всегда подразумевает шифрование, таким образом, опция SSL является ненужной в этом случае.

    ALTER USER 'jeffrey'@'localhost' REQUIRE X509;
    
    Клиент должен определить опции --ssl-key и --ssl-cert, чтобы соединиться. Это рекомендуется, но не требуется: --ssl-ca также будет определена, чтобы публичный сертификат сервера мог быть проверен. Это истина для ISSUER и SUBJECT, так как опции REQUIRE подразумевают требования X509.
  • ISSUER 'issuer'

    Устанавливает ограничение для попыток соединения, которыми клиент должен представить допустимый сертификат X509, выпущенн CA 'issuer'. Если клиент представляет сертификат, который допустим, но имеет иного выпускающего, сервер отклоняет соединение. Использование серптификатов X509 всегда подразумевает шифрование, таким образом, опция SSL не нужна.

    Так как ISSUER подразумевает требования X509, клиент должен определить --ssl-key и --ssl-cert. Это рекомендуется, но не требуется: --ssl-ca также будет определена, чтобы публичный сертификат сервера мог быть проверен.

    ALTER USER 'jeffrey'@'localhost'
          REQUIRE ISSUER '/C=SE/ST=Stockholm/L=Stockholm/
          O=MySQL/CN=CA/emailAddress=ca@example.com';
    
  • SUBJECT 'subject'

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

    Поскольку SUBJECT подразумевает требования X509, клиент должен определить --ssl-key и --ssl-cert--ssl-ca также будет определена, чтобы публичный сертификат сервера мог быть проверен.

    ALTER USER 'jeffrey'@'localhost'
          REQUIRE SUBJECT '/C=SE/ST=Stockholm/L=Stockholm/
          O=MySQL demo client certificate/
          CN=client/emailAddress=client@example.com';
    
    MySQL делает простое строковое сравнение 'subject' со значением в сертификате, таким образом, регистр символов и порядок составляющих должны быть даны точно как существующие в сертификате.

    Относительно emailAddress см. примечание в описании REQUIRE ISSUER.

  • CIPHER 'cipher'

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

    ALTER USER 'jeffrey'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA';
    

SUBJECT, ISSUER и CIPHER могут быть объединены в REQUIRE:

ALTER USER 'jeffrey'@'localhost'
      REQUIRE SUBJECT '/C=SE/ST=Stockholm/L=Stockholm/
      O=MySQL demo client certificate/
      CN=client/emailAddress=client@example.com' AND
      ISSUER '/C=SE/ST=Stockholm/L=Stockholm/
      O=MySQL/CN=CA/emailAddress=ca@example.com' AND
      CIPHER 'EDH-RSA-DES-CBC3-SHA';
Порядок опций не имеет значения, но никакая опция не может быть определена дважды. AND является дополнительным между опциями REQUIRE.

Опции предела ресурса

Возможно установить границы использования ресурсов сервера учетной записью, как обсуждено в разделе 7.3.5. Чтобы сделать так, используйте WITH, который определяет одно или больше значений resource_option:

ALTER USER допускает такие значения resource_option:

  • MAX_QUERIES_PER_HOUR count, MAX_UPDATES_PER_HOUR count, MAX_CONNECTIONS_PER_HOUR count

    Эти опции ограничивают число запросов, обновлений и соединений с сервером, разрешенных этой учетной записи во время любого данного одночасового периода. Запросы, для которых результаты поданы от кэша запроса, не считаются. Если count = 0 (по умолчанию), это означает, что нет никакого ограничения для учетной записи.

  • MAX_USER_CONNECTIONS count

    Ограничивает максимальное количество одновременных соединений с сервером для учетной записи. Отличное от нуля count определяет предел для учетной записи явно. Если count = 0 (по умолчанию), сервер определяет число одновременных соединений для учетной записи от глобального значения max_user_connections. Если max_user_connections тоже 0, нет никакого предела для учетной записи.

Пример:

ALTER USER 'jeffrey'@'localhost'
      WITH MAX_QUERIES_PER_HOUR 500 MAX_UPDATES_PER_HOUR 100;
Если данный предел ресурса определен многократно, последний случай имеет приоритет.

Опции истечения пароля

ALTER USER поддерживает несколько password_option для управления истечением пароля, чтобы истечь пароль учетной записи или установить его логику. Стратегические опции не истекают пароль, вместо этого они определяют, как сервер применяет автоматическое истечение к учетной записи (см. раздел 7.3.7).

Время жизни пароля оценено с даты и времени последнего изменения.

ALTER USER позволяет эти значения password_option:

  • PASSWORD EXPIRE

    Истекает пароль учетной записи.

    ALTER USER 'jeffrey'@'localhost' PASSWORD EXPIRE;
    
  • PASSWORD EXPIRE DEFAULT

    Устанавливает учетную запись так, чтобы глобальная политика истечения применилась, как определено default_password_lifetime.

    ALTER USER 'jeffrey'@'localhost' PASSWORD EXPIRE DEFAULT;
    
  • PASSWORD EXPIRE NEVER

    Отключает истечение пароля для учетной записи так, чтобы ее пароль никогда не истек.

    ALTER USER 'jeffrey'@'localhost' PASSWORD EXPIRE NEVER;
    
  • PASSWORD EXPIRE INTERVAL N DAY

    Устанавливает жизнь пароля учетной записи в N дней. Этот запрос требует, чтобы пароль был изменен каждые 180 дней:

    ALTER USER 'jeffrey'@'localhost' PASSWORD EXPIRE INTERVAL 180 DAY;
    

Если многократные опции истечения пароля определены, последняя имеет приоритет.

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

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

Блокирующие учетную запись опции

MySQL поддерживает блокировку учетной записи через ACCOUNT LOCK и ACCOUNT UNLOCK, которые определяют статус блокировки для учетной записи. Для дополнительного обсуждения см. раздел 7.3.11.

Если многократные блокирующие учетную запись опции определены, последняя имеет приоритет.

Ролевые опции

ALTER USER ... DEFAULT ROLE определяет, какие роли становятся активными, когда запрос SET ROLE DEFAULT выполнен во время сеанса для данного пользователя. После успешной пользовательской аутентификации сервер неявно выполняет SET ROLE DEFAULT.

Следующий запрос назначает 'joe'@'10.0.0.1' роли по умолчанию administrator и developer:

ALTER USER 'joe'@'10.0.0.1' DEFAULT ROLE administrator, developer;

14.7.1.2. CREATE ROLE

CREATE ROLE [IF NOT EXISTS] role [, role ] ...
CREATE ROLE создает одну или более ролей, которые называют наборами привилегий. Чтобы использовать это запрос, у Вас должна быть глобальная привилегия CREATE ROLE или CREATE USER.

Ошибка происходит, если Вы пытаетесь создать роль, которая уже существует. IF NOT EXISTS заменяет ошибку предупреждением.

Если CREATE ROLE называет многократные роли, это преуспевает для всех названных ролей или откатывается и не имеет никакого эффекта, если ошибка происходит.

Роль при создании заблокирована, не имеет никакого пароля, и ей назначен плагин аутентификации по умолчанию.

Для ролевых примеров использования см. раздел 7.3.4.

14.7.1.3. CREATE USER

CREATE USER [IF NOT EXISTS]
user_specification [, user_specification] ...
[REQUIRE {NONE | tls_option [[AND] tls_option] ...}]
[WITH resource_option [resource_option] ...]
[password_option | lock_option] ...

user_specification:
user [ auth_option ]

auth_option: {
IDENTIFIED BY 'auth_string'
  | IDENTIFIED BY PASSWORD 'hash_string'
  | IDENTIFIED WITH auth_plugin
  | IDENTIFIED WITH auth_plugin BY 'auth_string'
  | IDENTIFIED WITH auth_plugin AS 'hash_string'
}

tls_option: {
   SSL
 | X509
 | CIPHER 'cipher'
 | ISSUER 'issuer'
 | SUBJECT 'subject'
}

resource_option: {
MAX_QUERIES_PER_HOUR count
  | MAX_UPDATES_PER_HOUR count
  | MAX_CONNECTIONS_PER_HOUR count
  | MAX_USER_CONNECTIONS count
}

password_option: {
PASSWORD EXPIRE
  | PASSWORD EXPIRE DEFAULT
  | PASSWORD EXPIRE NEVER
  | PASSWORD EXPIRE INTERVAL N DAY
}

lock_option: {
ACCOUNT LOCK
  | ACCOUNT UNLOCK
}
CREATE USER создает новые учетные записи MySQL. Это позволяет аутентификации, SSL/TLS, пределу ресурса и свойствам истечения пароля быть установленными для новых учетных записей, а также управляет, заблокированы ли учетные записи первоначально или нет.

У учетной записи когда создается нет никаких привилегий и роль по умолчанию NONE.

Чтобы использовать CREATE USER , Вы должны иметь глобальную привилегию CREATE USER или привилегию INSERT для базы данных mysql. При включенной переменной read_only CREATE USER дополнительно требует SUPER.

Ошибка происходит, если Вы пытаетесь создать учетную запись, которая уже существует. IF NOT EXISTS превращает ошибку в предупреждение.

Для каждой учетной записи CREATE USER создает новую строку в таблице mysql.user. Строка отражает свойства, определенные в запросе. Неуказанные свойства установлены в их значения по умолчанию.

Пример 1: Создайте учетную запись, которая использует плагин аутентификации по умолчанию и данный пароль. Отметьте пароль как истекший, чтобы пользователь выбрал новый в первом соединении с сервером:

CREATE USER 'jeffrey'@'localhost'
       IDENTIFIED BY 'new_password' PASSWORD EXPIRE;
Пример 2: Создайте учетную запись, которая использует плагин аутентификации sha256_password и данный пароль. Потребуйте, чтобы новый пароль был выбран каждые 180 дней:
CREATE USER 'jeffrey'@'localhost'
       IDENTIFIED WITH sha256_password BY 'new_password'
       PASSWORD EXPIRE INTERVAL 180 DAY;

При некоторых обстоятельствах CREATE USER может быть зарегистрирован в журналах сервера или на стороне клиента в файле истории ~/.mysql_history, что означает, что пароли открытого текста могут быть считаны любым имеющим доступ к этой информации. Для информации об условиях, при которых это происходит для журналов сервера и как управлять ею, см. раздел 7.1.2.3.

См. разделы 7.3.6 и 7.3.9.

Каждое имя учетной записи использует формат, описанный в разделе 7.2.3:

CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass';
Если Вы определяете только часть имени пользователя имени учетной записи, часть имени хоста '%'.

Каждый user_specification состоит из имени учетной записи и дополнительного значения auth_option, которое определяет, как учетная запись подтверждает подлинность. Эти значения позволяют плагинам аутентификации учетной записи быть определенными. Каждое значение auth_option применяется только к пользователю, названному перед этим.

После пользовательских технических требований запрос может включать опции для SSL/TLS, предела ресурса, истечения пароля и свойств блокировки. Все эти опции глобальны для запроса и относятся ко всем названным пользователям.

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

CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY 'new_password1',
       'jeanne'@'localhost' IDENTIFIED BY 'new_password2'
       REQUIRE X509 WITH MAX_QUERIES_PER_HOUR 60 ACCOUNT LOCK;
Для опущенных опций используются эти значения по умолчанию:

  • Аутентификация: плагин аутентификации, определенный default_authentication_plugin и пустой пароль.

  • SSL/TLS: NONE.
  • Пределы ресурса: не ограничено.
  • Истечение пароля: PASSWORD EXPIRE DEFAULT.
  • Блокировка учетной записи: ACCOUNT UNLOCK.

Есть несколько аспектов CREATE USER:

  • Опции аутентификации

  • Опции SSL/TLS
  • Опции предела ресурса
  • Опции истечения пароля
  • Блокирующие учетную запись опции

Все они в целом аналогичны описанным для команды ALTER USER.

14.7.1.4. DROP ROLE

DROP ROLE [IF EXISTS] role [, role ] ...
DROP ROLE удаляет одну или более ролей (наборов привилегий). Чтобы использовать этот запрос, у Вас должна быть глобальная привилегия DROP ROLE или привилегия CREATE USER .

Ошибка происходит, если Вы пытаетесь удалить роль, которая не существует. IF EXISTS заставляет запрос производить предупреждение, а не ошибку для каждой названной роли, которая не существует.

Если DROP ROLE названо много ролей, это преуспевает для всех названных ролей или откатывается и не имеет никакого эффекта, если ошибка происходит.

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

14.7.1.5. DROP USER

DROP USER [IF EXISTS] user [, user] ...
DROP USER удаляет одну или более учетных записей MySQL и их привилегии. Это удаляет строки привилегии для учетной записи из всех таблиц.

Для применения DROP USER Вы должны иметь глобальную привилегию CREATE USER или привилегию DELETE для базы данных mysql. При включенной опции read_only DROP USER дополнительно требует привилегию SUPER.

Ошибка происходит, если Вы пытаетесь удалить учетную запись, которая не существует. IF EXISTS превращает ошибку в предупреждение.

Каждое имя учетной записи использует формат, описанный в разделе 7.2.3:

DROP USER 'jeffrey'@'localhost';
Если Вы определяете только часть имени пользователя имени учетной записи, часть имени хоста '%'.

DROP USER автоматически не закрывает открытых пользовательских сеансов. Когда пользователь с открытым сеансом удален, запрос не вступает в силу до закрытия сеанса пользователя. Как только сеанс закрыт, пользователь удален, и следующая попытка пользователя войти в систему потерпит неудачу.

DROP USER автоматически не удаляет базы данных или объекты в их пределах, которых создал старый пользователь. Это включает сохраненные программы или представления, для которых DEFINER это удаленный пользователь. Попытки получить доступ к таким объектам могут произвести ошибку, если они выполняются в контексте безопасности определителя. Для информации о контексте безопасности см. раздел 21.6.

14.7.1.6. GRANT

GRANT
priv_type [(column_list)]
  [, priv_type [(column_list)]] ...
ON [object_type] priv_level
TO user_specification [, user_specification] ...
[REQUIRE {NONE | tls_option [[AND] tls_option] ...}]
[WITH {GRANT OPTION | resource_option} ...]

GRANT PROXY ON user_specification
TO user_specification [, user_specification] ...
[WITH GRANT OPTION]

GRANT role [, role] ...
TO user [, user] ...
[WITH ADMIN OPTION]

object_type: {
TABLE
  | FUNCTION
  | PROCEDURE
}

priv_level: {
*
  | *.*
  | db_name.*
  | db_name.tbl_name
  | tbl_name
  | db_name.routine_name
}

user_specification:
user [ auth_option ]
auth_option: {
IDENTIFIED BY 'auth_string'
  | IDENTIFIED BY PASSWORD 'hash_string'
  | IDENTIFIED WITH auth_plugin
  | IDENTIFIED WITH auth_plugin BY 'auth_string'
  | IDENTIFIED WITH auth_plugin AS 'hash_string'
}

tls_option: {
SSL
  | X509
  | CIPHER 'cipher'
  | ISSUER 'issuer'
  | SUBJECT 'subject'
}

resource_option: {
  | MAX_QUERIES_PER_HOUR count
  | MAX_UPDATES_PER_HOUR count
  | MAX_CONNECTIONS_PER_HOUR count
  | MAX_USER_CONNECTIONS count
}
GRANT позволяет системным администраторам предоставить привилегии и роли, которые они могут предоставить учетным записям пользователя и ролям. Эти ограничения синтаксиса применяются:

  • GRANT не может смешать предоставление привилегий и ролей в том же самом запросе. Данный GRANT должен предоставить привилегии или роли.

  • ON различает, предоставляет ли запрос привилегии или роли:

    • С ON запрос предоставляет привилегии.

    • Без ON запрос предоставляет роли.

Разрешено назначить привилегии и роли учетной записи, но Вы должны использовать отдельные запросы GRANT для ролей и привилегий.

Чтобы использовать GRANT Вы должны иметь привилегию GRANT OPTION и у Вас должны быть привилегии, которые Вы предоставляете. Когда включена переменная read_only, GRANT дополнительно требует привилегию SUPER.

REVOKE связан с GRANT и позволяет администраторам удалить привилегии учетной записи. См. раздел 14.7.1.8.

Обычно администратор базы данных сначала использует CREATE USER, чтобы создать учетную запись и определить такие ее характеристики, как пароль, использует ли это безопасные соединения и ограничения на доступ к ресурсам сервера, затем использует GRANT, чтобы определить привилегии. ALTER USER может использоваться, чтобы изменить характеристики существующих учетных записей. Например:

CREATE USER 'jeffrey'@'localhost' IDENTIFIED BY 'mypass';
GRANT ALL ON db1.* TO 'jeffrey'@'localhost';
GRANT SELECT ON db2.invoice TO 'jeffrey'@'localhost';
ALTER USER 'jeffrey'@'localhost' WITH MAX_QUERIES_PER_HOUR 90;

Примеры, показанные здесь, не включают IDENTIFIED. Предполагается, что Вы устанавливаете пароли с CREATE USER во время создания учетной записи, чтобы избежать создавать опасные учетные записи.

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

Однако, использование GRANT, чтобы создать учетные записи или определить характеристики устарело. Вместо этого выполните эти задачи с использованием CREATE USER или ALTER USER.

Из mysql GRANT отвечает Query OK, 0 rows affected, когда выполнен успешно. Чтобы определить, какие привилегии даны, надо использовать SHOW GRANTS. См. раздел 14.7.5.21.

Есть несколько аспектов GRANT:

GRANT понимает имена хоста до 60 символов в длину. База данных, таблица, столбец и имена подпрограмм могут быть до 64 символов. Имена пользователей могут быть до 32 символов.

Допустимая длина для имен пользователя не может быть изменена, изменяя mysql.user. Попытка сделать так приведет к непредсказуемому поведении, которое может даже лишить возможности пользователей входить в систему. Вы никогда не должны изменять структуру таблиц в базе данных mysql в любой манере вообще, кроме процедуры, описанной в разделе 5.4.5.

Привилегии, поддержанные MySQL

Следующая таблица суммирует допустимые типы привилегии priv_type, которые могут быть определены для GRANT и REVOKE, и уровни, на которых можно предоставить каждую привилегию. Для дополнительной информации об этих привилегиях см. раздел 7.2.1.

Таблица 14.3. Допустимые привилегии для GRANT и REVOKE

Привилегия Значение и уровни
ALL [PRIVILEGES]Предоставить все привилегии на указанном уровне доступа, кроме GRANT OPTION
ALTER Включает использование ALTER TABLE. Уровни: глобальный, база данных, таблица.
ALTER ROUTINEПозволяет сохраненным подпрограммам быть измененными или удаленными. Уровни: глобальный, база данных, процедура.
CREATE Включает создание таблиц и баз данных. Уровни: глобальный, база данных, таблица.
CREATE ROUTINEВключает создание сохраненных подпрограмм. Уровни: глобальный, база данных.
CREATE TABLESPACEПозволяет создавать, изменять или удалять табличные пространства и группы файлов системного журнала. Уровень: глобальный.
CREATE TEMPORARY TABLESРазрешает использовать CREATE TEMPORARY TABLE. Уровни: глобальный, база данных.
CREATE USERПозволяет использование CREATE USER, DROP USER, RENAME USER и REVOKE ALL PRIVILEGES. Уровень: глобальный.
CREATE VIEWПозволяет создавать или изменять представления. Уровни: глобальный, база данных, таблица.
DELETE Разрешает использовать DELETE . Уровни: глобальный, база данных, таблица.
DROP Позволяет удалять базы данных, таблицы и представления. Уровни: глобальный, база данных, таблица.
EVENT Включает использование событий для Event Scheduler. Уровни: глобальный, база данных.
EXECUTE Позволяет пользователю выполнить сохраненные подпрограммы. Уровни: глобальный, база данных, таблица.
FILE Позволяет пользователю заставить сервер читать или писать файлы. Уровень: глобальный.
GRANT OPTIONПозволяет предоставлять или удалять привилегии из других учетных записей. Уровни: глобальный, база данных, таблица, процедура, proxy.
INDEX Включает создание или удаление индекса. Уровни: глобальный, база данных, таблица.
INSERT Разрешает INSERT. Уровни: глобальный, база данных, таблица, столбец.
LOCK TABLESВключить использование LOCK TABLES на таблицах, для которых Вы имеете привилегию SELECT. Уровни: глобальный, база данных.
PROCESS Позволяет пользователю видеть все процессы с SHOW PROCESSLIST. Уровень: глобальный.
PROXY Включает пользователю proxying. Уровень: От пользователя пользователю.
REFERENCES Включает создание внешнего ключа. Уровни: глобальный, база данных, таблица, столбец.
RELOAD Включает использование FLUSH . Уровень: глобальный.
REPLICATION CLIENTПозволяет пользователю запросить основные или ведомые серверы. Уровень: глобальный.
REPLICATION SLAVEПозволяет ведомым устройствам читать двоичные события журнала с ведущего устройства. Уровень: глобальный.
SELECT Включает использование SELECT . Уровни: глобальный, база данных, таблица, столбец.
SHOW DATABASESПозволяет SHOW DATABASES показать все базы данных. Уровень: Глобальный.
SHOW VIEW Позволяет SHOW CREATE VIEW. Уровни: глобальный, база данных, таблица.
SHUTDOWN Позволяет mysqladmin shutdown. Уровень: Глобальный.
SUPER Позволяет использование других административных задач: CHANGE MASTER TO, KILL, PURGE BINARY LOGS, SET GLOBAL и mysqladmin debug . Уровень: Глобальный.
TRIGGER Включить работу с триггерами. Уровни: глобальный, база данных, таблица.
UPDATE Разрешает UPDATE. Уровни: глобальный, база данных, таблица, столбец.
USAGE Синоним для no privileges.

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

В GRANT ALL [PRIVILEGES] или PROXY привилегию нужно назвать отдельно, она не может быть определена наряду с другими привилегиями. ALL [PRIVILEGES] синоним для всех привилегий, доступных для уровня, на котором привилегии предоставлены, за исключением GRANT OPTION и PROXY.

USAGE может быть определен, чтобы создать пользователя, у которого нет никаких привилегий, или определить REQUIRE или WITH для учетной записи, не изменяя ее существующие привилегии. Однако, использование GRANT, чтобы определить такие характеристики устарело в MySQL 5.7.6. Используйте CREATE USER или ALTER USER.

Информация учетной записи MySQL хранится в таблицах базы данных mysql. Подробности в разделе 7.2.

Если таблицы содержат строки привилегии, которые содержат имена базы данных или имена таблиц смешанного регистра и lower_case_table_names не 0, REVOKE не может использоваться, чтобы отменить эти привилегии. Будет необходимо управлять таблицами непосредственно. ( GRANT не будет создавать такие строки, когда установлена lower_case_table_names, но такие строки, возможно, были созданы до установки этой переменной.

Привилегии можно предоставить на нескольких уровнях, в зависимости от синтаксиса, используемого для ON. Для REVOKE ON определяет, которые привилегии удалить.

Для уровней глобального, базы данных, таблицы и подпрограммы GRANT ALL назначает только привилегии, которые существуют на уровне, который Вы предоставляете. Например, GRANT ALL ON db_name .* на уровне базы данных, таким образом, это не предоставляет специфических глобальных привилегий, например, FILE. Предоставление ALL не назначает GRANT OPTION или PROXY.

object_type, если есть, должен быть определен как TABLE, FUNCTION или PROCEDURE, когда следующий объект это таблица, сохраненная функция или хранимая процедура.

Привилегии для базы данных, таблицы, столбца или подпрограммы сформированы совокупно как логическое OR из привилегий на каждом из уровней. Например, если у пользователя есть глобальный SELECT, привилегия не может отрицаться отсутствием привилегии на уровне базы данных, таблицы или столбца. Детали проверяющей привилегию процедуры представлены в разделе 7.2.6.

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

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

MySQL автоматически не отменяет привилегий, когда Вы удаляете базу данных или таблицу. Однако, если Вы удаляете подпрограмму, любые привилегии, предоставленные для этой подпрограммы, отменяются.

Глобальные привилегии

Глобальные привилегии являются административными или относятся ко всем базам данных по данному серверу. Чтобы назначить глобальные привилегии, надо использовать ON *.*:

GRANT ALL ON *.* TO 'someuser'@'somehost';
GRANT SELECT, INSERT ON *.* TO 'someuser'@'somehost';
CREATE TABLESPACE , CREATE USER, FILE, PROCESS, RELOAD, REPLICATION CLIENT , REPLICATION SLAVE, SHOW DATABASES, SHUTDOWN и SUPER являются административными и могут быть предоставлены только глобально.

Другие привилегии можно предоставить глобально или на более определенных уровнях.

MySQL хранит глобальные привилегии в таблице mysql.user.

Привилегии базы данных

Привилегии базы данных относятся ко всем объектам в данной базе данных. Чтобы назначить привилегии на уровне базы данных, надо использовать ON db_name.*:

GRANT ALL ON mydb.* TO 'someuser'@'somehost';
GRANT SELECT, INSERT ON mydb.* TO 'someuser'@'somehost';
Если Вы используете ON * (вместо ON *.*) и Вы выбрали базу данных по умолчанию, привилегии назначены на уровне базы данных для базы данных по умолчанию. Ошибка происходит, если нет никакой базы данных по умолчанию.

CREATE, DROP, EVENT, GRANT OPTION, LOCK TABLES и REFERENCES могут быть определены на уровне базы данных. Привилегии таблицы или подпрограммы также могут быть определены на уровне базы данных, когда они относятся ко всем таблицам или подпрограммам в базе данных.

MySQL хранит привилегии базы данных в таблице mysql.db.

Табличные привилегии

Табличные привилегии относятся ко всем столбцам в данной таблице. Чтобы назначить привилегии на уровне таблицы, надо использовать ON db_name.tbl_name:

GRANT ALL ON mydb.mytbl TO 'someuser'@'somehost';
GRANT SELECT, INSERT ON mydb.mytbl TO 'someuser'@'somehost';
Если Вы определяете tbl_name вместо db_name.tbl_name, запрос относится к tbl_name в базе данных по умолчанию. Ошибка происходит, если нет никакой базы данных по умолчанию.

Допустимые значения priv_type на табличном уровне: ALTER, CREATE VIEW, CREATE, DELETE, DROP, GRANT OPTION, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER и UPDATE.

MySQL хранит табличные привилегии в таблице mysql.tables_priv.

Привилегии столбца

Привилегии столбца относятся к единственному столбцу в данной таблице. Каждая привилегия, которая будет предоставлена на уровне столбца, должна сопровождаться столбцом или столбцами, приложенными в круглых скобках.

GRANT SELECT (col1), INSERT (col1,col2) ON mydb.mytbl TO 'someuser'@'somehost';
Допустимые значения priv_type для столбца (то есть, когда Вы используете column_list): INSERT, REFERENCES, SELECT и UPDATE.

MySQL хранит привилегии столбца в таблице mysql.columns_priv.

Привилегии сохраненных подпрограмм

ALTER ROUTINE, CREATE ROUTINE, EXECUTE и GRANT OPTION относятся к сохраненным подпрограммам (процедуры и функции). Их можно предоставить на глобальных уровнях и уровнях базы данных. За исключением CREATE ROUTINE, эти привилегии можно предоставить для отдельных подпрограмм.

GRANT CREATE ROUTINE ON mydb.* TO 'someuser'@'somehost';
GRANT EXECUTE ON PROCEDURE mydb.myproc TO 'someuser'@'somehost';
Допустимые priv_type на уровне подпрограмм: ALTER ROUTINE, EXECUTE и GRANT OPTION. CREATE ROUTINE не привилегия на обычном уровне, потому что у Вас должна быть эта привилегия, чтобы создать подпрограмму

MySQL хранит привилегии для подпрограмм в таблице mysql.procs_priv.

Привилегии Proxy

PROXY позволяет одному пользователю быть полномочием для другого. Пользователь является олицетворением или берет личность proxy-пользователя.

GRANT PROXY ON 'localuser'@'localhost' TO 'externaluser'@'somehost';
Когда PROXY предоставлена, это должна быть единственная привилегия, названная в GRANT, REQUIRE не может быть дан, и разрешен единственный параметр WITH: WITH GRANT OPTION.

Это требует, чтобы пользователь по доверенности подтвердил подлинность через плагин, который возвращает имя proxied пользователя к серверу, когда пользователь по доверенности соединяется, и что пользователь по доверенности имеет привилегию PROXY. Подробности в разделе 7.3.10.

MySQL хранит привилегии proxy в таблице mysql.proxies_priv.

Имена учетной записи и пароли

user_specification называет пользователя и произвольно предоставляет информацию об аутентификации, такую как пароль.

user указывает на учетную запись MySQL, к которой GRANT применяется. Чтобы приспособить предоставление прав пользователям от произвольных узлов, MySQL поддерживает определение user в формате user_name@host_name. Если user_name или host_name является законным как идентификатор, Вы не должны заключить его в кавычки. Однако, кавычки необходимы, чтобы определить user_name, содержащее специальные символы (например, -) или если host_name содержит специальные или подстановочные символы (например, %). Заключите в кавычки имя пользователя и имя хоста отдельно.

Вы можете определить подстановочные знаки в имени хоста. Например, user_name@'%.example.com' относится к user_name для любого узла в домене example.com, а user_name@'192.168.1.%' относится к user_name для любого узла в подсети 192.168.1 класса C.

Простая форма user_name это синоним для user_name@'%'.

MySQL не поддерживает подстановочные знаки в именах пользователей. Чтобы обратиться к анонимному пользователю, определите учетную запись с пустым именем пользователя с помощью GRANT:

GRANT ALL ON test.* TO ''@'localhost' ...;
В этом случае, любому пользователю, который соединяется от местного узла с правильным паролем для анонимного пользователя, разрешат доступ с привилегиями, связанными с анонимной учетной записью пользователя.

См. раздел 7.2.3.

Чтобы определить заключенные в кавычки значения, заключите в кавычки базу данных, таблицу или столбец как идентификаторы. Имена пользователя и хоста берутся в кавычки как идентификаторы или как строки. Пароли берутся в кавычки как строки. Для заключения в кавычки строк и идентификаторов см. разделы 10.1.1 и 10.2.

_ и % разрешены, определяя имена базы данных в GRANT, которые предоставляют привилегии на уровне базы данных. Это означает, например, что, если Вы хотите использовать _ как часть имени базы данных, Вы должны определить это как \_ в GRANT, чтобы предотвратить возможность доступа к дополнительным базам данных, соответствующих подстановочному образцу, например, GRANT ... ON `foo\_bar`.* TO ....

Если Вы разрешаете анонимным пользователям соединяться с сервером MySQL, Вы должны также предоставить привилегии всем местным пользователям как user_name@localhost. Иначе анонимная учетная запись пользователя для localhost в таблице mysql.user (создаваемая во время установки MySQL) используется, когда названный пользователь пытается войти в систему MySQL с местной машины. Для деталей см. раздел 7.2.5.

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

SELECT Host, User FROM mysql.user WHERE User='';
Чтобы избежать этой проблемы, удалите местную анонимную учетную запись пользователя, используя этот запрос:
DROP USER ''@'localhost';

Чтобы указать, как пользователь должен подтвердить подлинность, соединяясь с сервером, значение user_specification может включать IDENTIFIED, чтобы определить плагин аутентификации, пароль или обоих. Синтаксис пользовательской спецификации тот же самый, что в CREATE USER. См. раздел 14.7.1.3.

Если задан IDENTIFIED BY и у Вас есть глобальная привилегия (GRANT OPTION), пароль становится новым паролем для учетной записи, даже если учетная запись существует и уже имеет пароль. Без IDENTIFIED BY пароль учетной записи остается неизменным.

Неявное создание учетной записи

Если учетную запись называют в GRANT , но она не существует, предпринятые меры зависят от значения режима SQL NO_AUTO_CREATE_USER :

  • Если NO_AUTO_CREATE_USER выключен, GRANT создает учетную запись. Это очень опасно, если Вы не определяете непустой пароль через IDENTIFIED BY.

  • Если включен NO_AUTO_CREATE_USER, GRANT не создает учетную запись, если Вы не определяете непустой пароль через IDENTIFIED BY или плагин аутентификации через IDENTIFIED WITH.

Если учетная запись уже существует, IDENTIFIED WITH запрещен, потому что это предназначено только для использования, создавая новые учетные записи.

Другие характеристики учетной записи

MySQL может проверить признаки сертификата X509 в дополнение к обычной аутентификации, которая основана на имени пользователя. Для вводной информации об использовании SSL с MySQL см. раздел 7.4.

REQUIRE определяет опции SSL для учетной записи MySQL. Синтаксис тот же самый, что и в CREATE USER, см. раздел 14.7.1.3.

WITH используется в этих целях:

  • Позволять пользователю предоставить привилегии другим пользователям.

  • Определить ограничение ресурса для пользователя.

WITH GRANT OPTION дает пользователю способность дать другим пользователям любые привилегии, которые пользователь имеет на указанном уровне привилегии.

Чтобы предоставить GRANT OPTION учетной записи, иначе не изменяя ее привилегии, сделайте это:

GRANT USAGE ON *.* TO 'someuser'@'somehost' WITH GRANT OPTION;
Два пользователя с различными привилегиями могут быть в состоянии объединить привилегии!

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

Знайте что, когда Вы предоставляете пользователю GRANT OPTION на особом уровне привилегии, любые привилегии, которыми пользователь обладает (или может получить в будущем) на этом уровне, могут быть предоставлены им другим пользователям. Предположите, что Вы предоставляете пользователю привилегию INSERT на базе данных. Если Вы потом предоставляете привилегию SELECT на базе данных м указываете WITH GRANT OPTION, тот пользователь может дать другим пользователям не только SELECT, но и INSERT. Если Вы позже предоставляете UPDATE на базе данных, пользователь может предоставить INSERT, SELECT и UPDATE.

Для неадминистративного пользователя Вы не должны предоставить ALTER глобально или для базы данных mysql. Если Вы делаете это, пользователь может попытаться ниспровергать систему привилегий, переименовывая таблицы!

См. раздел 7.2.1.

Возможно установить границы использования ресурсов сервера учетной записью, как обсуждено в разделе 7.3.5. Используйте WITH с параметром resource_option. Не определенные пределы сохраняют свое текущее значение. Синтаксис тот же самый, что в CREATE USER, см. раздел 14.7.1.3.

Версии GRANT в MySQL и стандартном SQL

Самые большие различия между MySQL и стандартными версиями SQL GRANT:

  • MySQL связывает привилегии с комбинацией имени хоста и имени пользователя а не только с именем пользователя.

  • У стандартного SQL нет глобальных или привилегий на уровне базы данных, и при этом он не поддерживает все типы привилегий MySQL.
  • MySQL не поддерживает стандартную привилегию SQL UNDER.
  • Стандартные привилегии SQL структурированы в иерархической манере. Если Вы удаляете пользователя, отменяются все привилегии, которые предоставили пользователю. Это также истина в MySQL, если Вы используете DROP USER, см. раздел 14.7.1.5.
  • В стандартном SQL, когда Вы удаляете таблицу, отменяются все привилегии для таблицы. В стандартном SQL, когда Вы отменяете привилегию, также отменяются все привилегии, которые предоставили, основываясь на этой привилегии. В MySQL привилегии могут быть удалены с DROP USER или REVOKE.
  • В MySQL возможно иметь INSERT только для некоторых столбцов в таблице. В этом случае Вы можете все еще выполнить INSERT на таблице, при условии, что Вы вставляете значения только для тех столбцов, для которых Вы имеете привилегию INSERT . Опущенные столбцы установлены в их неявные значения по умолчанию, если строгий режим SQL не включен. В строгом режиме запрос отклонен, если у какого-либо из опущенных столбцов нет никакого значения по умолчанию. Стандартный SQL требует, чтобы Вы имели привилегию INSERT на всех столбцах. Для информации о строгом режиме SQL и неявных значениях по умолчанию см. разделы 6.1.8 и 12.7.

14.7.1.7. RENAME USER

RENAME USER old_user TO new_user
[, old_user TO new_user] ...
RENAME USER переименовывает существующие учетные записи MySQL. Ошибка происходит для старых учетных записей, которые не существуют, или новых учетных записей, которые уже существуют.

Чтобы использовать RENAME USER , у Вас должна быть глобальная привилегия CREATE USER или привилегия UPDATE для базы данных mysql. Если включена read_only, RENAME USER требует привилегии SUPER.

Каждое имя учетной записи использует формат, описанный в разделе 7.2.3:

RENAME USER 'jeffrey'@'localhost' TO 'jeff'@'127.0.0.1';
Если Вы определяете только часть имени пользователя имени учетной записи, используется часть имени хоста '%'.

RENAME USER копирует привилегии старого пользователя новому. Однако, RENAME USER автоматически не удаляет базы данных или объекты, которые создал старый пользователь. Это включает сохраненные программы или представления, для которых DEFINER это старый пользователь. Попытки получить доступ к таким объектам могут произвести ошибку, если они выполняют в контексте безопасности определителя (см. раздел 21.6).

Изменения привилегий вступают в силу как обозначено в разделе 7.2.7.

14.7.1.8. REVOKE

REVOKE
priv_type [(column_list)]
  [, priv_type [(column_list)]] ...
ON [object_type] priv_level
FROM user [, user] ...

REVOKE ALL PRIVILEGES, GRANT OPTION
FROM user [, user] ...

REVOKE PROXY ON user
FROM user [, user] ...

REVOKE role [, role ] ...
FROM user [, user ] ...
REVOKE позволяет системным администраторам отменить привилегии и роли, которые он может отменить от учетных записей пользователя и ролей.

При включенной переменной read_only REVOKE требует привилегии SUPER.

Каждое имя учетной записи использует формат, описанный в разделе 7.2.3:

REVOKE INSERT ON *.* FROM 'jeffrey'@'localhost';
Если Вы определяете только часть имени пользователя имени учетной записи, часть имени хоста '%'.

Для деталей об уровнях, на которых привилегии существуют, допустимых значениях priv_type, priv_level и object_type см. раздел 14.7.1.6.

Чтобы использовать первый вариант REVOKE, Вы должны иметь привилегию GRANT OPTION, и у Вас должны быть привилегии, которые Вы отменяете.

Чтобы отменить все привилегии, используйте второй синтаксис, который удаляет все привилегии глобальные, базы данных, таблицы и столбца для названного пользователя или пользователей: named user or users:

REVOKE ALL PRIVILEGES, GRANT OPTION FROM user
[, user] ...
Чтобы использовать этот вариант REVOKE , у Вас должна быть глобальная привилегия CREATE USER или привилегия UPDATE на базе данных mysql.

REVOKE ALL PRIVILEGES, GRANT OPTION FROM user не отменяет ролей.

REVOKE удаляет привилегии, но не удаляет записи таблицы mysql.user. Чтобы удалить учетную запись пользователя полностью, надо использовать DROP USER (см. раздел 14.7.1.5) или DELETE.

Если таблицы содержат строки привилегии, которые содержат имена базы данных или имена таблиц в смешанном регистре и lower_case_table_names не 0, REVOKE не может использоваться, чтобы отменить эти привилегии. Будет необходимо управлять таблицами непосредственно. GRANT не будет создавать такие строки, когда lower_case_table_names установлена, но такие строки, возможно, были созданы до установки переменной.

Когда успешно выполнено из mysql, REVOKE отвечает Query OK, 0 rows affected. Чтобы определить результат команды, используйте SHOW GRANTS . См. раздел 14.7.5.21.

14.7.1.9. REVOKE ROLE

REVOKE ROLE
{
auth_id [, auth_id ] ...
  | ALL ROLES
}
FROM auth_id [, auth_id ] ...
auth_id: user_name[@host_name]
Это раздел образца.

14.7.1.10. SET DEFAULT ROLE

SET DEFAULT ROLE
{NONE | ALL | role [, role ] ...}
TO role [, role ] ...
Этот запрос альтернативный синтаксис для ALTER USER ... DEFAULT ROLE (см. раздел 14.7.1.1). Это определяет, какие роли становятся активными, когда SET ROLE DEFAULT выполнен во время сеанса для каждой role немедленно после TO.

DEFAULT ROLE может иметь эти значения:

  • NONE: Роль по умолчанию NONE.

  • ALL: Значение по умолчанию: все роли, предоставленные учетной записи.
  • role [, role ] ...: Значение по умолчанию: все названные роли.

14.7.1.11. SET PASSWORD

SET PASSWORD [FOR user] = password_option
password_option: {
PASSWORD('auth_string')
  | 'auth_string'
}
SET PASSWORD назначает пароль на учетную запись пользователя MySQL, определенный как открытый текст (не зашифрован) или как зашифрованное значение:

  • 'auth_string' представляет пароль открытого текста.

  • 'hash_string' представляет зашифрованный пароль.

SET PASSWORD может использоваться с или без явно названной учетной записи пользователя:

  • С FOR user запрос устанавливает пароль для названной учетной записи, которая должна существовать:

    SET PASSWORD FOR 'jeffrey'@'localhost' = password_option;
    
    В этом случае Вы должны иметь привилегию UPDATE на базе данных mysql.
  • Без FOR user запрос устанавливает пароль для текущего пользователя:
    SET PASSWORD = password_option;
    
    Любой клиент, который соединяется с сервером, используя неанонимную учетную запись, может изменить пароль для той учетной записи. Чтобы видеть, какая учетная запись подтверждала Вашу подлинность, вызовите функцию CURRENT_USER():
    SELECT CURRENT_USER();
    

При включенной опции read_only SET PASSWORD требует привилегию SUPER.

Если FOR user дан, имя учетной записи использует формат, описанный в разделе 7.2.3. user должно быть дано как 'user_name'@'host_name' , где 'user_name' и 'host_name' точно как перечислены в столбцах User и Host строки таблицы mysql.user. Если Вы определяете только имя пользователя, имя хоста '%'. Например, чтобы установить пароль для учетной записи с User и Host соответственно 'bob' и '%.example.org':

SET PASSWORD FOR 'bob'@'%.example.org' = PASSWORD('auth_string');
Пароль может быть определен этими способами:

  • Используя функцию PASSWORD() (устарел с MySQL 5.7.6).

    Функциональный параметр 'auth_string' открытый текст (незашифрованный) пароль. PASSWORD() хеширует пароль и возвращает зашифрованную строку пароля для хранения в строке mysql.user.

    Функция PASSWORD() хеширует пароль, используя хеширующий метод, определенный значением old_passwords. Если SET PASSWORD отклоняет хешированное значение пароля, возвращенное PASSWORD() как не заданное в правильном формате, может быть необходимо изменить old_passwords, чтобы изменить хеширующий метод. Например, если учетная запись использует плагин mysql_native_password, значение old_passwords должно быть равно 0:

    SET old_passwords = 0;
    SET PASSWORD FOR 'jeffrey'@'localhost' = PASSWORD('mypass');
    
    Если old_passwords отличается от требуемого плагином аутентификации, хешированное значение пароля, возвращенное PASSWORD() не является приемлемым для этого плагина, и попытка установить пароль, производит ошибку. Разрешенные значения old_passwords описаны позже в этом разделе.
  • Используя строку без PASSWORD().

    SET PASSWORD интерпретирует строку как строку открытого текста и хеширует это соответственно для плагина аутентификации учетной записи прежде, чем сохранить это в строке таблицы mysql.user.

См. раздел 7.3.6.

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

Значение Метод хеширования пароля Связанный плагин аутентификации
0MySQL 4.1 native mysql_native_password
2SHA-256 sha256_password

Если Вы используете MySQL Replication, в настоящее время, пароль, используемый ведомым устройством в качестве части CHANGE MASTER TO ограничен 32 символами в длину, если пароль больше, любые лишние символы усечены. Это не происходит ни из-за какого предела, наложенного сервером MySQL вообще, а скорее является проблемой, определенной для MySQL Replication (см. Bug #43439).

14.7.1.12. SET ROLE

SET ROLE
{
DEFAULT
  | NONE
  | ALL
  | ALL EXCEPT role [, role ] ...
  | role [, role ] ...
}
SET ROLE изменяет эффективные привилегии текущего пользователя. Запрос разрешает эти ролевые спецификаторы:

  • DEFAULT: Установить текущую роль в роль по умолчанию для пользователя.

  • NONE: Установить текущую роль в NONE.
  • ALL: Установить текущую роль во все роли, предоставленные учетной записи.
  • ALL EXCEPT role_list: Установить текущую роль во все роли, предоставленные учетной записи, кроме названных.
  • role [, role ] ...: Установить текущую роль в названные роли.

14.7.2. Запросы обслуживания таблиц

14.7.2.1. ANALYZE TABLE

ANALYZE [NO_WRITE_TO_BINLOG | LOCAL] TABLE
tbl_name [, tbl_name] ...
ANALYZE TABLE анализирует и хранит ключевое распределение для таблицы. Во время анализа таблица заблокирована с блокировкой чтения для InnoDB и MyISAM. Этот запрос работает с InnoDB, NDB и MyISAM. Для MyISAM этот запрос эквивалентен использованию myisamchk --analyze . Этот запрос не работает с представлениями.

Для получения дополнительной информации о том, как анализ работает в пределах InnoDB см. разделы 16.6.10.1, 16.6.10.3 и 16.8.7. В частности, когда Вы включаете опцию innodb_stats_persistent, Вы должны выполнить ANALYZE TABLE после загрузки существенных данных в InnoDB или создания нового индекса.

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

Это запрос требует привилегии SELECT и INSERT на таблице.

ANALYZE TABLE поддержан для разделенных таблиц, и Вы можете использовать ALTER TABLE ... ANALYZE PARTITION, чтобы проанализировать один или более раздела, для получения дополнительной информации см. разделы 14.1.7 и 20.3.4.

ANALYZE TABLE возвращает набор результатов со следующими столбцами.

СтолбецЗначение
TableИмя таблицы
OpВсегда analyze
Msg_typestatus, error, info, note или warning
Msg_text Соответствующее информационное сообщение

Вы можете проверить сохраненное ключевое распределение с SHOW INDEX, см. раздел 14.7.5.22.

Если таблица не изменилась, начиная с последнего ANALYZE TABLE, она не проанализирована снова.

По умолчанию сервер пишет ANALYZE TABLE в двоичный журнал, чтобы они копировались к ведомым устройствам репликации. Чтобы подавить журналирование, определите дополнительное ключевое слово NO_WRITE_TO_BINLOG или его псевдоним LOCAL.

14.7.2.2. CHECK TABLE

CHECK TABLE tbl_name [, tbl_name]
      ... [option] ... option = {
FOR UPGRADE
  | QUICK
  | FAST
  | MEDIUM
  | EXTENDED
  | CHANGED
}
CHECK TABLE проверяет таблицу или таблицы на ошибки. CHECK TABLE работает для таблиц InnoDB, MyISAM, ARCHIVE и CSV. Для MyISAM ключевые статистические данные обновлены также.

Перед выполнением CHECK TABLE на InnoDB см. здесь .

Чтобы проверить таблицу, у Вас должна быть некоторая привилегия для этого.

CHECK TABLE может также проверить представления на проблемы, такие как таблицы, на которые ссылаются в определении представления, которые больше не существуют.

CHECK TABLE поддержан для разделенных таблиц, и Вы можете использовать ALTER TABLE ... CHECK PARTITION, чтобы проверять один или более разделов, для получения дополнительной информации см. разделы 14.1.7 и 20.3.4.

CHECK TABLE игнорирует произведенные виртуальные столбцы, которые не индексированы.

Вывод

CHECK TABLE возвращает набор результатов со следующими столбцами.

СтолбецЗначение
TableИмя таблицы
OpВсегда check
Msg_typestatus, error, info, note или warning
Msg_text Соответствующее информационное сообщение

Запрос может произвести много строк информации для каждой проверенной таблицы. У последней строки есть Msg_type status и Msg_text обычно должен быть OK. Если это не OK или Table is already up to date для MyISAM, Вы должны обычно выполнять ремонт таблицы. См. раздел 8.6. Table is already up to date сообщает, что механизм хранения для таблицы указал, что не было никакой потребности проверить таблицу.

Проверка совместимости вариантов

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

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

FOR UPGRADE обнаруживает эти несовместимости:

  • Порядок индексации в столбцах TEXT для InnoDB и MyISAM изменился между MySQL 4.1 и 5.0.

  • Метод хранения нового типа данных DECIMAL изменился между MySQL 5.0.3 и 5.0.5.
  • Изменения иногда производятся в наборах символов или сопоставлениях, которые требуют, чтобы таблица была пересоздана. Для деталей об этих изменениях и когда FOR UPGRADE их найдет, см. раздел 2.10.3.
  • MySQL 8.0 не поддерживает тип данных YEAR(2), разрешенный в более старых версиях MySQL. Для таблиц, содержащих столбцы YEAR(2), CHECK TABLE рекомендует REPAIR TABLE, который конвертирует YEAR(2) в YEAR(4).
  • Время создания триггеров поддержано.

Проверка последовательности данных

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

ТипСмысл
QUICKНе просматривать строки, чтобы проверить на неправильные ссылки. Относится к таблицам InnoDB и MyISAM и представлениям.
FASTПроверить только таблицы, которые не были закрыты должным образом. Применяется только к MyISAM таблицам и представлениям, проигнорирован для InnoDB.
CHANGEDПроверка только таблиц, которые были изменены, начиная с последней проверки или не были закрыты должным образом. Применяется только к MyISAM таблицам и представлениям, проигнорирован для InnoDB.
MEDIUMСканировать строки, чтобы проверить, которые удаленные ссылки допустимы. Это также вычисляет ключевую контрольную сумму для строк и проверяет это с расчетной контрольной суммой для ключей. Применяется только к MyISAM, проигнорирован для InnoDB.
EXTENDEDСделать полный ключевой поиск для всех ключей для каждой строки. Это гарантирует, что таблица на 100% последовательна, но занимает много времени. Применяется только к MyISAM, проигнорирован для InnoDB.

Если ни одна из опций QUICK, MEDIUM или EXTENDED не определены, тип проверки по умолчанию для динамического формата MyISAM MEDIUM . У этого есть тот же самый результат, как у myisamchk --medium-check tbl_name. Тип проверки по умолчанию также MEDIUM для статического формата MyISAM, если CHANGED или FAST заданы. В этом случае значение по умолчанию QUICK. Просмотр строки пропущен для CHANGED и FAST, так как строки очень редко повреждаются.

Вы можете объединить опции проверки, как в следующем примере, который делает быструю проверку на таблице, чтобы определить, было ли это закрыто должным образом:

CHECK TABLE test_table FAST QUICK;

Если CHECK TABLE не находит проблем с таблицей, которая отмечена как corrupted или not closed properly , CHECK TABLE может удалить метку.

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

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

FAST и CHANGED главным образом предназначены, чтобы использоваться из скрипта (например, из cron ), если Вы хотите проверить таблицы время от времени. В большинстве случаев FAST должен быть предпочтен CHANGED. Единственный случай, когда это не так, это когда Вы подозреваете, что нашли ошибку в коде MyISAM.

EXTENDED должен использоваться только после того, как Вы осуществили нормальную проверку, но все еще получаете странные ошибки от таблицы, когда MySQL пытается обновить строку или найти строку ключом. Это очень маловероятно, если нормальная проверка преуспела.

Использование CHECK TABLE ... EXTENDED может влиять на план выполнения, произведенный оптимизатором.

Некоторые проблемы, сообщенные CHECK TABLE не могут быть исправлены автоматически:

  • Found row where the auto_increment column has the value 0 .

    Это означает, что есть строка в таблице, где столбец AUTO_INCREMENT содержит значение 0. Возможно создать строку, где AUTO_INCREMENT = 0, явно устанавливая столбец в 0 с помощью UPDATE.

    Это не ошибка само по себе, но может доставить неприятности, если Вы решаете вывести таблицу в дамп и восстановить ее или сделать ALTER TABLE. В этом случае AUTO_INCREMENT изменяет значение согласно правилам AUTO_INCREMENT, которые могли вызвать проблемы, такие как ошибка дублирования ключа.

    Чтобы избавиться от предупреждения, выполните UPDATE, чтобы установить столбец в некоторое значение кроме 0.

Примечания использования CHECK TABLE с InnoDB

Следующие примечания относятся к таблицам InnoDB:

  • Если CHECK TABLE сталкивается с поврежденной страницей, сервер останавливается, чтобы предотвратить распространение ошибки (Bug #10132). Если повреждение происходит во вторичном индексе, но табличные данные читаемы, запуск CHECK TABLE может все еще вызвать выход сервера.

  • Если CHECK TABLE сталкивается с поврежденным полем DB_TRX_ID или DB_ROLL_PTR в кластеризируемом индексе, CHECK TABLE может вызвать доступ InnoDB к недопустимой записи журнала отмены, приводящей к сбою сервера, связанному с MVCC.
  • Если CHECK TABLE находит ошибки в таблицах или индексах InnoDB, это сообщает об ошибке и обычно отмечает индекс и иногда таблицу как поврежденные, предотвращая дальнейшее использование индекса или таблицы. Такие ошибки включают неправильное число записей во вторичном индексе или неправильные ссылки.
  • Если CHECK TABLE находит неправильное число записей во вторичном индексе, он сообщает об ошибке, но не вызывает выход сервера или запрет доступа к файлу.
  • CHECK TABLE рассматривает структуру индексной страницы, затем рассматривает каждую запись ключа. Это не проверяет ключевой указатель на кластеризируемую запись или следует по пути для указателей на BLOB.
  • Когда таблица InnoDB сохранена в ее собственном файле .ibd, первые 3 страницы файла .ibd содержит информацию о заголовке, а не таблицу или данные индекса. CHECK TABLE не обнаруживает несогласованности, которые затрагивают только данные о заголовке. Чтобы проверить все содержание файла .ibd, использщуйте innochecksum .
  • Запуская CHECK TABLE на больших таблицах InnoDB, другие потоки могут быть заблокированы во время CHECK TABLE. Чтобы избежать тайм-аутов, порог ожидания (600 секунд) расширен на 2 часа (7200 секунд) для CHECK TABLE. Если InnoDB обнаруживает семафор, который ждет 240 секунд или больше, он начинает выводить монитор InnoDB в журнал ошибок. Если запрос блокировки простирается вне порога ожидания семафора, прерывает процесс. Чтобы избежать возможности семафора ждать тайм-аут полностью, Вы можете выполнить CHECK TABLE QUICK вместо CHECK TABLE.
  • CHECK TABLE функциональность для InnoDB индексов SPATIAL включает проверку достоверности R-дерева и проверку, чтобы гарантировать, что количество строк R-дерева соответствует кластеризируемому индексу.
  • CHECK TABLE поддерживает вторичные индексы на произведенных виртуальных столбцах. InnoDB имеет поддержку вторичного индекса на произведенных виртуальных столбцах.

14.7.2.3. CHECKSUM TABLE

CHECKSUM TABLE tbl_name [, tbl_name]
         ... [ QUICK | EXTENDED ]
CHECKSUM TABLE сообщает контрольную сумму для содержания таблицы. Во время работы контрольной суммы таблица заблокирована с блокировкой чтения для InnoDB и MyISAM. Вы можете использовать этот запрос, чтобы проверить, что содержание то же самое прежде и после резервного копирования, отката или другой работы, которая предназначена, чтобы привести данные в известный статус. Это запрос требует привилегии SELECT для таблицы.

Этот запрос не поддержано для представлений. Если Вы выполняете CHECKSUM TABLE на представлении, значение Checksum всегда NULL и будет предупреждение.

Исполнительные соображения

По умолчанию, вся таблица читается построчно, и контрольная сумма вычислена. Для больших таблиц это может занять много времени, таким образом, Вы будете только иногда выполнять эту работу. Это вычисление аналогично тому, что Вы получаете с EXTENDED в InnoDB и всех других механизмах хранения, кроме MyISAM, а также таблицах MyISAM, не созданных с CHECKSUM=1.

Для таблиц MyISAM, созданных с CHECKSUM=1, CHECKSUM TABLE или CHECKSUM TABLE ... QUICK вернет текущую контрольную сумму таблицы, которая может быть возвращена очень быстро. Если таблица не удовлетворяет всем этим условиям, QUICK возвращает NULL. См. раздел 14.1.15.

Для несуществующей таблицы CHECKSUM TABLE вернет NULL и предупреждение.

Значение контрольной суммы зависит от формата строки таблицы. Если формат строки изменяется, контрольная сумма также изменяется. Например, формат хранения для таких временных типов, как TIME, DATETIME и TIMESTAMP изменен в MySQL 5.6, так что при обновлении таблиц с 5.5 до 5.6 значение контрольной суммы может измениться.

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

14.7.2.4. OPTIMIZE TABLE

OPTIMIZE [NO_WRITE_TO_BINLOG | LOCAL] TABLE
tbl_name [, tbl_name] ...
Реорганизует физическое хранение табличных данных и связанных индексных данных, чтобы уменьшить место для хранения и улучшить эффективность ввода/вывода, получая доступ к таблице. Точные изменения, произведенные в каждой таблице, зависят от механизма хранения, используемого этой таблицей. Этот запрос не работает с представлениями.

Используйте OPTIMIZE TABLE в этих случаях, в зависимости от типа таблицы:

  • После выполнения существенной вставки, обновления или удаления на InnoDB, у которой есть ее собственный файл .ibd, потому что она создавалась с опцией innodb_file_per_table. Таблица и индекс реорганизованы, и дисковое пространство может быть освобождено для использования операционной системой.

  • После выполнения существенной вставки, обновления или удаления на столбцах, которые являются частью FULLTEXT в InnoDB. Установите опцию innodb_optimize_fulltext_only=1. Чтобы сохранить период обслуживания индекса к соответствующему времени, установите innodb_ft_num_word_optimize, чтобы определить, сколько слов обновить в поисковом индексе, и выполняйте последовательность OPTIMIZE TABLE до полного обновления поискового индекса.
  • После удаления значительной части MyISAM или ARCHIVE или внесения значительных изменений в таблицы MyISAM или ARCHIVE со строками переменной длины (таблицы, которые имеют столбцы VARCHAR, VARBINARY, BLOB или TEXT). Удаленные строки поддержаны в связанном списке и последующие INSERT повторно используют старые позиции строки. Вы можете использовать OPTIMIZE TABLE, чтобы восстановить неиспользуемое место и для дефрагментации файла с данными. После обширных изменений таблицы этот запрос может также улучшить исполнение запросов, которые используют таблицу, иногда значительно.

Этот запрос требует табличных привилегий SELECT и INSERT.

OPTIMIZE TABLE также поддержан для разделенных таблиц. Для информации об использовании этого запроса с разделенными таблицами см. раздел 20.3.4.

OPTIMIZE TABLE работает с таблицами InnoDB, MyISAM и ARCHIVE.

По умолчанию OPTIMIZE TABLE не работает для других механизмов хранения и возвращает результат, указывающий на это. Вы можете сделать, чтобы OPTIMIZE TABLE работал для других механизмов хранения, запуская mysqld с опцией --skip-new. В этом случае OPTIMIZE TABLE отображен на ALTER TABLE.

Детали InnoDB

Для InnoDB OPTIMIZE TABLE отображен на ALTER TABLE ... FORCE, который пересоздает таблицу, чтобы обновить индексную статистику и свободное неиспользуемое место в кластеризируемом индексе. Это выведено на экран в выводе OPTIMIZE TABLE, когда Вы выполняете это на InnoDB:

mysql> OPTIMIZE TABLE foo;
+----------+----------+----------+-------------------------------------------------------------------+
| Table    | Op       | Msg_type | Msg_text                                                          |
+----------+----------+----------+-------------------------------------------------------------------+
| test.foo | optimize | note     | Table does not support optimize, doing recreate + analyze instead |
| test.foo | optimize | status   | OK                                                                |
+----------+----------+----------+-------------------------------------------------------------------+
OPTIMIZE TABLE использует online DDL (ALGORITHM=INPLACE) для таблиц InnoDB. Это блокирует таблицу только на краткое время, что уменьшает время простоя для параллельных операций DML.

OPTIMIZE TABLE продолжает использовать ALGORITHM=COPY при следующих условиях:

OPTIMIZE TABLE, используя online DDL (ALGORITHM=INPLACE), не поддержан для таблиц InnoDB с индексами FULLTEXT. Тут нужен ALGORITHM=COPY.

InnoDB хранит данные, используя метод распределения страницы и не страдают от фрагментации, как MyISAM. Оптимизатор рассматривает рабочую нагрузку транзакций, которые обработает Ваш сервер:

  • Некоторый уровень фрагментации ожидается. InnoDB заполняет страницы только на 93%, чтобы оставить место для обновлений, не имея необходимости разделять страницы.

  • Операции удаления могут оставить промежутки, которые оставляют страницы менее заполненными, чем желательно, что может сделать полезным оптимизировать таблицу.
  • Обновления строк обычно переписывают данные в пределах той же самой страницы, в зависимости от типа данных и формата строки, когда достаточное пространство доступно. См. разделы 16.9.1.5 и 16.10.1.
  • Рабочие нагрузки высокого параллелизма могли бы оставить промежутки внутри индекса в течение долгого времени, как InnoDB сохраняет многократные версии тех же самых данных через его механизм MVCC, см. раздел 16.3.

Детали MyISAM

Для таблиц MyISAM OPTIMIZE TABLE работает так:

  1. Если таблица удалила или разделила строки, восстановит таблицу.

  2. Если индексные страницы не сортированы, сортирует их.
  3. Если статистические данные таблицы не современны (и ремонт не может быть достигнут, сортируя индекс), обновит их.

Другие соображения

OPTIMIZE TABLE возвращает набор результатов со следующими столбцами.

СтолбецЗначение
ТаблицаИмя таблицы
OpВсегда optimize
Msg_typestatus, error, info, note или warning
Msg_text Соответствующее информационное сообщение

Для таблиц InnoDB до 5.7.4 и других табличных типов MySQL блокирует таблицу в течение времени работы OPTIMIZE TABLE. OPTIMIZE TABLE выполнен онлайн для обычных и разделенных таблиц InnoDB.

По умолчанию сервер пишет OPTIMIZE TABLE в двоичный журнал так, чтобы они копировались к ведомым устройствам. Чтобы подавить журналирование, определите дополнительный параметр NO_WRITE_TO_BINLOG или LOCAL.

OPTIMIZE TABLE не сортирует R-дерево индекса, такое как пространственный индекс на столбцах POINT (Bug #23578).

OPTIMIZE TABLE ловит и бросает любые ошибки, которые происходят, копируя табличную статистику от старого файла в недавно созданный. Например. если пользовательский ID владельца файла .MYD или .MYI отличается от пользовательского ID процесса mysqld, OPTIMIZE TABLE производит ошибку "cannot change ownership of the file", если mysqld не запущен от имени root.

14.7.2.5. REPAIR TABLE

REPAIR [NO_WRITE_TO_BINLOG | LOCAL] TABLE
tbl_name [, tbl_name] ...
[QUICK] [EXTENDED] [USE_FRM]
REPAIR TABLE восстанавливает возможно поврежденную таблицу, для определенных механизмов хранения. По умолчанию это имеет тот же самый эффект, как myisamchk --recover tbl_name. REPAIR TABLE работает для таблиц MyISAM, ARCHIVE и CSV, см. разделы 17.2 17.5 и 17.4. Этот запрос не работает с представлениями.

Нужны привилегии SELECT и INSERT на уровне таблицы.

Вы можете использовать ALTER TABLE ... REPAIR PARTITION, чтобы восстановить один или более разделов, см. разделы 14.1.7 и 20.3.4.

Хотя обычно Вам никогда не придется выполнять REPAIR TABLE, этот запрос, очень вероятно, возвратит все Ваши данные из таблицы MyISAM. Если Ваши таблицы становятся поврежденными часто, попытайтесь найти причину этого, чтобы избавиться от необходимости использовать REPAIR TABLE. См. разделы B.5.3.3 и 17.2.4.

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

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

REPAIR TABLE возвращает набор результатов со следующими столбцами.

СтолбецЗначение
TableИмя таблицы
OpВсегда repair
Msg_typestatus, error, info, note или warning
Msg_text Соответствующее информационное сообщение

REPAIR TABLE может произвести много строк информации для каждой восстановленной таблицы. У последней строки есть Msg_type = status и Msg_test обычно должен быть OK. Если это не OK для таблицы MyISAM, Вы должны попытаться восстановить ее с myisamchk --safe-recover. REPAIR TABLE не осуществляет все опции myisamchk. С myisamchk --safe-recover Вы можете также использовать опции, которые не поддерживает REPAIR TABLE , например, --max-record-length.

Если Вы используете опцию QUICK, REPAIR TABLE попытается восстановить только индексный файл, а не файл с данными. Этот тип ремонта походит на myisamchk --recover --quick.

Если Вы используете опцию EXTENDED, MySQL создает индекс строку за строкой вместо того, чтобы создать индекс за один раз с сортировкой. Этот тип ремонта походит на myisamchk --safe-recover .

Опция USE_FRM доступна для использования, если индексный файл .MYI отсутствует или если его заголовок поврежден. Эта опция говорит MySQL не доверять информации из заголовка файла .MYI и обновлять это, используя информацию из словаря данных. Этот вид ремонта не может быть сделан с myisamchk.

Используйте USE_FRM только, если Вы не можете использовать обычные режимы REPAIR. Сообщение серверу проигнорировать файл .MYI делает важные табличные метаданные, сохраненные в .MYI, недоступными процессу ремонта, у этого могут быть вредные последствия:

  • Текущее значение AUTO_INCREMENT потеряно.

  • Ссылка к удаленным записям в таблице потеряна, что означает, что свободное пространство останется незанятым.
  • Заголовок .MYI указывает, сжата ли таблица. Если сервер игнорирует эту информацию, он не может сказать, что таблица сжата, и ремонт может вызвать изменение или потерю табличного содержания. Это означает, что USE_FRM не должна использоваться со сжатыми таблицами. Это не должно быть необходимо: сжатые таблицы предназначены только для чтения, таким образом, они не должны стать поврежденными.

Если USE_FRM не используется, REPAIR TABLE проверяет таблицу, чтобы видеть, требуется ли обновление. Если так, это выполняет обновление по тем же самым правилам, как CHECK TABLE ... FOR UPGRADE. См. раздел 14.7.2.2.

По умолчанию, сервер пишет REPAIR TABLE в двоичный журнал так, чтобы они копировались к ведомым устройствам. Чтобы подавить журналирование, определите дополнительный параметр NO_WRITE_TO_BINLOG или LOCAL.

Когда таблица на ведущем устройстве становится поврежденной, и Вы выполняете REPAIR TABLE, любые получающиеся изменения оригинальной таблицы не размножены ведомым устройствам.

Вы можете быть в состоянии увеличить скорость REPAIR TABLE, устанавливая определенные системные переменные. См. раздел 9.6.3.

14.7.3. Компоненты, плагины и определяемые пользователем функциональные запросы

14.7.3.1. CREATE FUNCTION

CREATE [AGGREGATE] FUNCTION function_name
       RETURNS {STRING|INTEGER|REAL|DECIMAL}
       SONAME shared_library_name
User-defined function (UDF) является способом расширить MySQL с новой функцией, которая работает как родная (встроенная) функция MySQL, например, ABS() или CONCAT().

function_name имя, которое должно использоваться в запросах SQL, чтобы вызвать функцию. RETURNS указывает на тип возвращаемого значения функции. DECIMAL допустимое значение после RETURNS, но в настоящее время DECIMAL возвращают строковые значения и должны быть написаны как STRING.

shared_library_name это базовое имя совместно используемого файла библиотеки, который содержит код, который осуществляет функцию. Файл должен быть расположен в каталоге плагинов. Этот каталог дан значением plugin_dir. См. раздел 26.4.2.5.

Чтобы создать функцию, Вы должны иметь привилегию INSERT для базы данных mysql. Это необходимо потому что CREATE FUNCTION добавляет строку к системной таблице mysql.func, которая делает запись имени функции и имени библиотеки. Если у Вас нет этой таблицы, Вы должны выполнить mysql_upgrade, чтобы создать ее. См. раздел 5.4.5.

Активная функция это та, которая была загружена CREATE FUNCTION и не удалена с DROP FUNCTION. Все активные функции перезагружены каждый раз, когда сервер запускается, если Вы не запускаете mysqld с опцией --skip-grant-tables. В этом случае инициализация UDF пропущена и UDF недоступны.

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

AGGREGATE работает точно как совокупная функция MySQL вроде SUM или COUNT() . Чтобы AGGREGATE работала, Ваша таблица mysql.func должна содержать столбец type. Если это не так, выполните mysql_upgrade (см. раздел 5.4.5.

Чтобы обновить совместно используемую библиотеку UDF, используйте DROP FUNCTION, обновите совместно используемую библиотеку, и затем скомандуйте CREATE FUNCTION. Если Вы обновляете совместно используемую библиотеку сначала и затем используете DROP FUNCTION, сервер может рухнуть.

14.7.3.2. DROP FUNCTION

DROP FUNCTION function_name
Этот запрос удаляет определяемую пользователем функцию (UDF) function_name.

Чтобы удалить функцию, Вы должны иметь привилегию DELETE для базы данных mysql. Это потому, что DROP FUNCTION удаляет строку из системной таблицы mysql.func, которая делает запись имени функции.

DROP FUNCTION также используется, чтобы удалить сохраненные функции (см. раздел 14.1.23).

14.7.3.3. INSTALL COMPONENT

INSTALL COMPONENT component_name [, component_name ] ...
Этот запрос устанавливает один или более серверных компонентов, которые становятся активными немедленно. Компонент оказывает услуги, которые доступны серверу и другим компонентам. INSTALL COMPONENT требует привилегию INSERT для таблицы mysql.component.

Служба загрузчика обрабатывает установку компонентов, а также перечисляет установленные компоненты в mysql.component, которая служит регистрацией. Для последующих перезапусков сервера любые компоненты, перечисленные в mysql.component, установлены службой загрузчика во время запуска. Это происходит, даже если сервер запущен с --skip-grant-tables (это отличается от эффекта той опции в подавлении загрузки mysql.event, mysql.func и mysql.proc).

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

ERROR 3527 (HY000): Cannot satisfy dependency for service 'component1'
required by component 'component2'.
Чтобы избежать этого, устанавливайте все компоненты в том же самом запросе или устанавливайте зависимый компонент после установки любых компонентов, от которых это зависит.

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

В настоящее время названия компонента это URN, которые начинаются file:// и для которого следующее значение имени файла не содержит имен каталогов и задано относительно каталога, названного в переменной plugin_dir . Названия компонента не включают зависимого от платформы суффикса имени файла, например, .so или .dll. Эти детали подвержены изменениям, потому что интерпретация названия компонента самостоятельно выполнена службой, и составляющая инфраструктура позволяет заменить выполнение службы по умолчанию альтернативным выполнением.

Например:

INSTALL COMPONENT 'file://component1', 'file://component2';
См. раздел 6.5.

14.7.3.4. INSTALL PLUGIN

INSTALL PLUGIN plugin_name SONAME 'shared_library_name'
Этот запрос устанавливает плагин сервера. Это требует привилегии INSERT для таблицы mysql.plugin.

plugin_name это название плагина как определено в дескрипторной структуре, содержавшейся в файле библиотеки (см. раздел 26.2.4.2). Имена не являются чувствительными к регистру. Для максимальной совместимости имена должны быть ограничены символами ASCII, цифрами и подчеркиванием, потому что они используются в исходных файлах C и SQL.

shared_library_name название совместно используемой библиотеки, которая содержит код плагина. Имя включает расширение имени файла (например, libmyplugin.so, libmyplugin.dll или libmyplugin.dylib).

Совместно используемая библиотека должна быть расположена в каталоге плагинов (указан в plugin_dir ). Библиотека должна быть непосредственно в каталоге, не в подкаталоге. По умолчанию plugin_dir это подкаталог plugin в соответствии с каталогом, названным переменной pkglibdir, но это может быть изменено, устанавливая значение plugin_dir при запуске сервера. Например, установите ее значение в файле my.cnf:

[mysqld]
plugin_dir=/path/to/plugin/directory
Если значение plugin_dir относительный путь, это взято относительно основного каталога MySQL (значение basedir).

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

INSTALL PLUGIN также регистрирует плагин, добавляя строку, которая указывает на имя плагина и имя файла библиотеки в таблицу mysql.plugin. При запуске сервера он загружает и инициализирует любой плагин, который перечислен в mysql.plugin. Это означает, что плагин установлен с INSTALL PLUGIN , только однажды, а не каждый раз, когда сервер запускается. Загрузки плагина при запуске не происходит, если сервер запущен с опцией --skip-grant-tables.

Библиотека может содержать много плагинов. Для каждого из них используйте отдельный запрос INSTALL PLUGIN. Каждый запрос называет различный плагин, но все они определяют то же самое имя библиотеки.

INSTALL PLUGIN заставляет сервер читать файл опций (my.cnf), как во время запуска сервера. Это позволяет плагину поднять любые соответствующие опции от тех файлов. Возможно добавить опции к файлу опции даже прежде, чем загрузить плагин (если использовать префикс loose). Также возможно удалить плагин, отредактировать my.cnf и установить плагин снова. Перезапуск плагина этим путем приводит к новым значениям опции без перезапуска сервера.

Для опций, которые управляют отдельным плагином, загружающимся при запуске сервера, см. раздел 6.6.2. Если Вы должны загрузить плагины для запуска сервера, когда задана опция --skip-grant-tables (которая говорит серверу не читать системные таблицы), используйте опцию --plugin-load, см. раздел 6.1.4.

Чтобы удалить плагин, используйте запрос UNINSTALL PLUGIN.

См. раздел 6.6.2.

Чтобы видеть, какие плагины установлены, используйте SHOW PLUGINS или смотрите таблицу INFORMATION_SCHEMA.PLUGINS.

Если Вы повторно собираете библиотеку и надо повторно установить ее, Вы можете использовать любой из следующих методов:

  • Используйте UNINSTALL PLUGIN, чтобы удалить все плагины в библиотеке, установите новый файл библиотеки в каталоге, и затем используйте INSTALL PLUGIN, чтобы устанавливать все плагины в библиотеке. У этой процедуры есть преимущество, что это может использоваться, не останавливая сервер. Однако, если библиотека содержит много плагинов, Вы должны выпустить много запросов INSTALL PLUGIN и UNINSTALL PLUGIN.

  • Остановите сервер, установите новый файл библиотеки и перезапустите сервер.

14.7.3.5. UNINSTALL COMPONENT

UNINSTALL COMPONENT component_name [, component_name ] ...
Этот запрос дезактивирует и удаляет один или более серверных компонентов. Это требует привилегии DELETE для таблицы mysql.component. UNINSTALL COMPONENT дополнение INSTALL COMPONENT .

Служба загрузчика также разрегистрирует удаленные компоненты в A loader service also unregisters uninstalled components from mysql.component. В результате они больше не установлены во время запуска для последующих перезапусков сервера.

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

См. раздел 14.7.3.3.

Пример:

UNINSTALL COMPONENT 'file://component2';
См. раздел 6.5.

14.7.3.6. UNINSTALL PLUGIN

UNINSTALL PLUGIN plugin_name
Этот запрос удаляет установленный плагин сервера. Это требует привилегию DELETE на системной таблице mysql.plugin. UNINSTALL PLUGIN дополняет INSTALL PLUGIN.

plugin_name должно быть названием некоторого плагина, который перечислен в таблице mysql.plugin. Сервер выполняет функцию парковки плагина и удаляет строку для плагина из таблицы mysql.plugin, чтобы последующие перезапуски сервера не загрузили и инициализировали плагин. UNINSTALL PLUGIN не удаляет совместно используемый файл библиотеки плагина.

Вы не можете удалить плагин, если любая таблица, которая использует это, открыта.

У удаления есть значения для использования связанных таблиц. Например, если полнотекстовый плагин анализатора связан с индексом FULLTEXT таблицы, удаление плагина делает таблицу непригодной. Любая попытка получить доступ к таблице приводит к ошибке. Таблица не может даже быть открыта, таким образом, Вы не можете удалить индекс, для которого используется плагин. Это означает, что удаление плагина является чем-то, что надо делать аккуратно. Если Вы удаляете плагин без намерения повторно установить это позже, и Вы заботитесь о табличном содержании, Вы должны вывести таблицу в дамп с помощью mysqldump и удалить WITH PARSER из CREATE TABLE в дампе, чтобы Вы могли перезагрузить таблицу позже. Если Вы не заботитесь о таблице, DROP TABLE может использоваться, даже если какие-либо плагины, связанные с таблицей, отсутствуют.

См. раздел 6.6.2.

14.7.4. SET

SET имеет несколько форм:

14.7.4.1. SET для назначения переменных

SET variable_assignment [, variable_assignment] ...
variable_assignment:
  user_var_name = expr
| param_name = expr
| local_var_name = expr
| [GLOBAL | SESSION | PERSIST]
system_var_name = expr
| [@@global. | @@session. | @@persist. | @@]
system_var_name = expr
SET для назначения переменных позволяет Вам назначить значения на различные типы переменных, которые затрагивают работу сервера или клиентов:

  • Системные переенные. См. раздел 6.1.5. Системные переенные также могут быть установлены при запуске сервера, как описано в разделе 6.1.6. Чтобы вывести на экран имя и значение системные переменной, используйте SHOW VARIABLES, см. раздел 14.7.5.39.

  • Определяемые пользователем переменные. См. раздел 10.4.
  • Параметры хранимых процедур и функций и местные переменные сохраненной подпрограммы. См. раздел 14.6.4.

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

Следующие примеры иллюстрируют SET для того, чтобы установить переменные. Они используют оператор назначения =, но оператор назначения := также разрешен с этой целью.

Пользовательская переменная записана как @var_name и назначено значение выражения следующим образом:

SET @var_name = expr;
Примеры:
SET @name = 43;
SET @total_tax = (SELECT SUM(tax) FROM taxable_transactions);
Как демонстрирующийся этими запросами, expr может быть простым (буквальное значение) или более сложным (значение, возвращенное скалярным подзапросом).

SET относится к параметрам и местным переменным в контексте объекта, в пределах которого они определены. Следующая процедура использует местную переменную counter как счетчик:

CREATE PROCEDURE p()
BEGIN
  DECLARE counter INT DEFAULT 0;
  WHILE counter < 10 DO
    -- ... do work ...
    SET counter = counter + 1;
  END WHILE;
END;
Много системных переменных являются динамичными и могут быть изменены во время выполнения при использовании SET . Список см. в разделе 6.1.6.2. Чтобы изменить системную переменную с SET, обратитесь к этому по имени, произвольно предваренному модификатором:

  • Чтобы указать, что переменная глобальная, предшествуйте ее имени GLOBAL или @@global.:

    SET GLOBAL max_connections = 1000;
    SET @@global.max_connections = 1000;
    
    Привилегия SUPER нужна, чтобы устанавливать глобальные переменные.
  • Другой способ установить глобальную переменную состоит в том, чтобы поставить перед именем ключевое слово PERSIST или @@persist.:
    SET PERSIST max_connections = 1000;
    SET @@persist.max_connections = 1000;
    
    SET позволяет Вам произвести изменения конфигурации во время выполнения, которые также сохраняются через перезапуски сервера. Как SET GLOBAL, SET PERSIST изменяет значение переменной во время выполнения, но также пишет установку переменной в файл опции mysqld-auto.cnf в каталоге данных (заменяющий любую существующую установку переменной, если есть). При запуске сервер обрабатывает этот файл после всех других файлов опции. Нужна привилегия SUPER, чтобы сохранять глобальные переменные.

    Управление mysqld-auto.cnf нужно оставить серверу и не выполнять вручную:

    • Удаление файла приведет к потере всех сохраненных настроек при следующем запуске сервера. Это допустимо, если Ваше намерение состоит в том, чтобы реконфигурировать сервер без этих настроек.

    • Изменения файла могут привести к ошибке разбора при запуске сервера. В этом случае сервер сообщает об ошибке и завершается. Если эта проблема происходит, запустите сервер с выключенной переменной persisted_globals_load или с опцией --no-defaults. Альтернативно, удалите файл mysqld-auto.cnf, но, как отмечено ранее, удаляя этот файл потеряете все сохраненные настройки.

    Переменная плагина может быть сохранена, если плагин установлен, когда выполнен SET PERSIST. Назначение сохраненной переменной плагина вступает в силу для последующих перезапусков сервера, если плагин все еще установлен. Если плагин больше не будет установлен, то переменная не будет существовать, когда сервер будет читать файл mysqld-auto.cnf. В этом случае сервер пишет предупреждение в журнал ошибок и продолжает работу:

    currently unknown variable 'var_name'
    was read from the persisted config file
    
  • Чтобы указать, что переменная это переменная сеанса, поставьте перед ее именем SESSION, @@session. или @@:
    SET SESSION sql_mode = 'TRADITIONAL';
    SET @@session.sql_mode = 'TRADITIONAL';
    SET @@sql_mode = 'TRADITIONAL';
    
    Установка переменной сеанса обычно не требует никакой специальной привилегии, хотя есть исключения, которые требуют привилегию SUPER (например, sql_log_bin). Клиент может изменить его собственные переменные сеанса, но не таковые для любого другого клиента.

    Системные переменные только для сеанса не могут быть сохранены. Они не могут быть установлены при запуске сервера, таким образом нет никакой причины перечислить их в mysqld-auto.cnf.

  • LOCAL и @@local. синонимы для SESSION и @@session..
  • Если никакой модификатор не присутствует, SET меняет переменную сеанса. Если у переменной нет никакого значения сеанса, ошибка происходит.
    mysql> SET max_connections = 1000;
    ERROR 1229 (HY000): Variable 'max_connections' is a
    GLOBAL variable and should be set with SET GLOBAL
    
  • Ошибка происходит при этих обстоятельствах:

    • Используйте SET GLOBAL (@@global.) или SET PERSIST (или @@persist.), устанавливая переменную, у которой есть только значение сеанса.

    • Опустите GLOBAL (или @@global.) или PERSIST (или @@persist.), устанавливая переменную, у которой есть только глобальное значение.
    • Используйте SET SESSION (или @@SESSION.), устанавливая переменную, у которой есть только глобальное значение.

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

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

SET @x = 1, SESSION sql_mode = '';
Если Вы устанавливаете многократные системные переменные, новый модификатор GLOBAL или SESSION в запросе используется для следующих назначений, у которых нет никакого определенного модификатора.

Примеры многократно-переменного назначения:

SET GLOBAL sort_buffer_size = 1000000, SESSION sort_buffer_size = 1000000;
SET @@global.sort_buffer_size = 1000000, @@local.sort_buffer_size = 1000000;
SET GLOBAL max_connections = 1000, sort_buffer_size = 1000000;
Если любое переменное назначение в SET терпит неудачу, весь запрос терпит неудачу, никакие переменные не изменены, mysqld-auto.cnf не изменен тоже.

Если Вы меняете системную переменную сеанса, значение остается в силе в пределах Вашего сеанса, пока Вы не меняете переменную к иному значению или завершаете сеанс. Изменение не имеет никакого эффекта на другие сеансы.

Если Вы меняете глобальную системную переменную, значение используется для новых сеансов, пока Вы не меняете переменную к иному значению или не завершите сервер. Изменение видимо любому клиенту, который получает доступ к глобальной переменной. Однако, изменение затрагивает соответствующую переменную сеанса только для клиентов, которые соединяются после изменения. Изменение глобальной переменной не затрагивает переменную сеанса для любых текущих сеансов клиента (даже сеанс, в пределах которого выполнена команда SET GLOBAL).

Чтобы сделать установку глобальной системной переменной постоянной, чтобы это применилось через перезапуски сервера, измените это с помощью SET PERSIST, чтобы сделать запись в файл mysqld-auto.cnf. Также возможно использовать SET GLOBAL и вручную изменить my.cnf, но тут есть вероятность накосячить. SET PERSIST более удобно.

Чтобы установить значение GLOBAL в значение по умолчанию MySQL или соответствующее GLOBAL, установите переменную к значению DEFAULT. Например, следующие два запроса идентичны в установке значения max_join_size к текущему глобальному значению:

SET @@session.max_join_size=DEFAULT;
SET @@session.max_join_size=@@global.max_join_size;
Не все системные переменные могут быть установлены в DEFAULT. В таких случаях назначение DEFAULT приводит к ошибке.

С SET PERSIST (или @@persist.), эффект установки глобальной переменной к ее значению по умолчанию является определенным версией:

  • С MySQL 8.0.1 установка глобальной переменной в DEFAULT назначает значение по умолчанию и удаляет это из файла mysqld-auto.cnf. Установка переменной к ее буквальному значению по умолчанию назначает значение по умолчанию и добавляет установку для переменной в файл mysqld-auto.cnf.

  • В MySQL 8.0.0 установка глобальной переменной в DEFAULT или к буквальной переменной назначает ее значение по умолчанию. Это также добавляет установку для переменной к файлу mysqld-auto.cnf, если ее там нет, и удаляет из mysqld-auto.cnf, если есть.

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

Чтобы обратиться к значению системной переменной в выражениях, используйте один из модификаторов @@. Например, Вы можете получить значения в SELECT:

SELECT @@global.sql_mode, @@session.sql_mode, @@sql_mode;
Для ссылки на системную переменную в выражении как @@var_name (вместо @@global. или @@session.) MySQL возвращает значение сеанса, если это существует и глобальное значение иначе. Это отличается от SET @@var_name = expr , который всегда обращается к значению сеанса.

@@persist. не разрешен в выражениях.

14.7.4.2. SET CHARACTER SET

SET {CHARACTER SET | CHARSET}
{charset_name | DEFAULT}
Этот запрос отображает все строки, посланные между сервером и текущим клиентом с данным отображением. SET CHARACTER SET устанавливает три системных переменные сеанса: character_set_client и character_set_results установлены в данный набор символов, и character_set_connection к значению character_set_database. См. раздел 11.1.4.

Отображение наборов символов по умолчанию может быть восстановлено при использовании значения DEFAULT. Значение по умолчанию зависит от конфигурации сервера.

ucs2, utf16 и utf32 не может использоваться в качестве набора символов клиента, что означает, что они не работают в SET CHARACTER SET.

14.7.4.3. SET NAMES

SET NAMES {'charset_name'
[COLLATE 'collation_name'] | DEFAULT}
Этот запрос устанавливает три системных переменные сеанса character_set_client , character_set_connection и character_set_results к данному набору символов. Установка character_set_connection в charset_name также установит collation_connection к сопоставлению по умолчанию для charset_name. См. раздел 11.1.4.

Дополнительный параметр COLLATE может использоваться, чтобы определить сопоставление явно. Если дано, сопоставление должно быть одним из разрешенных сопоставлений для charset_name.

Отображение значения по умолчанию может быть восстановлено при использовании значения DEFAULT. Значение по умолчанию зависит от конфигурации сервера.

ucs2, utf16 и utf32 не может использоваться в качестве набора символов клиента, что означает, что они не работают в SET NAMES.

14.7.5. SHOW

SHOW имеет много форм, которые предоставляют информацию о базах данных, таблицах, столбцах или сервере. Этот раздел описывает следующее:

SHOW {BINARY | MASTER} LOGS
SHOW BINLOG EVENTS [IN 'log_name']
     [FROM pos] [LIMIT [offset,]
     row_count]
SHOW CHARACTER SET [like_or_where]
SHOW COLLATION [like_or_where]
SHOW [FULL] COLUMNS FROM tbl_name
     [FROM db_name] [like_or_where]
SHOW CREATE DATABASE db_name
SHOW CREATE EVENT event_name
SHOW CREATE FUNCTION func_name
SHOW CREATE PROCEDURE proc_name
SHOW CREATE TABLE tbl_name
SHOW CREATE TRIGGER trigger_name
SHOW CREATE VIEW view_name
SHOW DATABASES [like_or_where]
SHOW ENGINE engine_name {STATUS | MUTEX}
SHOW [STORAGE] ENGINES
SHOW ERRORS [LIMIT [offset,] row_count]
SHOW EVENTS
SHOW FUNCTION CODE func_name
SHOW FUNCTION STATUS [like_or_where]
SHOW GRANTS FOR user
SHOW INDEX FROM tbl_name [FROM db_name]
SHOW MASTER STATUS
SHOW OPEN TABLES [FROM db_name]
     [like_or_where]
SHOW PLUGINS
SHOW PROCEDURE CODE proc_name
SHOW PROCEDURE STATUS [like_or_where]
SHOW PRIVILEGES
SHOW [FULL] PROCESSLIST
SHOW PROFILE [types] [FOR QUERY n]
     [OFFSET n] [LIMIT n]
SHOW PROFILES
SHOW RELAYLOG EVENTS [IN 'log_name']
     [FROM pos] [LIMIT [offset,]
     row_count]
SHOW SLAVE HOSTS
SHOW SLAVE STATUS [NONBLOCKING]
SHOW [GLOBAL | SESSION] STATUS [like_or_where]
SHOW TABLE STATUS [FROM db_name]
     [like_or_where]
SHOW [FULL] TABLES [FROM db_name]
     [like_or_where]
SHOW TRIGGERS [FROM db_name]
     [like_or_where]
SHOW [GLOBAL | SESSION] VARIABLES [like_or_where]
SHOW WARNINGS [LIMIT [offset,] row_count]
     like_or_where:
LIKE 'pattern'
  | WHERE expr
Если синтаксис для данного SHOW включает часть LIKE 'pattern', 'pattern' это строка, которая может содержать SQL-символы % и _. Образец полезен для ограничения вывода запроса соответствием значений.

Несколько SHOW также принимают WHERE, который обеспечивает больше гибкости в определении, которые строки вывести на экран. См. раздел 22.31.

Много MySQL APIs (например, PHP) позволяют обработать результат SHOW как набор результатов из SELECT, см. главу 25. Кроме того, Вы можете работать в SQL с результатами запросов на таблицах в базе данных INFORMATION_SCHEMA, которые Вы не можете легко полцить из SHOW. См. главу 22.

14.7.5.1. SHOW BINARY LOGS

SHOW BINARY LOGS
SHOW MASTER LOGS
Перечисляет двоичные файлы системного журнала на сервере. Это запрос используется как часть процедуры, описанной в разделе 14.4.1.1, которая показывает, как определить, какие журналы могут быть очищены.
mysql> SHOW BINARY LOGS;
+---------------+-----------+
| Log_name      | File_size |
+---------------+-----------+
| binlog.000015 | 724935    |
| binlog.000016 | 733481    |
+---------------+-----------+
SHOW MASTER LOGS эквивалент SHOW BINARY LOGS .

Нужны привилегии SUPER или REPLICATION CLIENT .

14.7.5.2. SHOW BINLOG EVENTS

SHOW BINLOG EVENTS
     [IN 'log_name'] [FROM pos]
     [LIMIT [offset,] row_count]
Показывает события в двоичном журнале. Если Вы не определяете 'log_name', первый двоичный журнал выведен на экран.

LIMIT имеет тот же самый синтаксис, что в SELECT. См. раздел 14.2.9.

SHOW BINLOG EVENTS без LIMIT может занять очень много времени и потреблять ресурс процесса, потому что сервер возвращает клиенту полное содержание двоичного журнала (который включает все запросы, выполненные сервером, которые изменяют данные). Как альтернатива SHOW BINLOG EVENTS, используйте mysqlbinlog, чтобы сохранить двоичной журнал к текстовому файлу для более поздней экспертизы и анализа. См. раздел 5.6.8.

Некоторые события, касающиеся установки пользователя и системных переменных, не включены в вывод SHOW BINLOG EVENTS. Чтобы получить полный обзор событий в пределах двоичного журнала, используйте mysqlbinlog.

SHOW BINLOG EVENTS не работает с файлами системного журнала реле. Вы можете использовать SHOW RELAYLOG EVENTS для этого.

14.7.5.3. SHOW CHARACTER SET

SHOW CHARACTER SET
     [LIKE 'pattern' | WHERE expr]
SHOW CHARACTER SET показывает все доступные наборы символов. LIKE, если дан, указывает, который набор символов соответствует. WHERE может быть дан, чтобы выбрать строки, используя более общие условия, как обсуждено в разделе 22.31:
mysql> SHOW CHARACTER SET LIKE 'latin%';
+---------+-----------------------------+-------------------+--------+
| Charset | Description                 | Default collation | Maxlen |
+---------+-----------------------------+-------------------+--------+
| latin1  | cp1252 West European        | latin1_swedish_ci |  1     |
| latin2  | ISO 8859-2 Central European | latin2_general_ci |  1     |
| latin5  | ISO 8859-9 Turkish          | latin5_turkish_ci |  1     |
| latin7  | ISO 8859-13 Baltic          | latin7_general_ci |  1     |
+---------+-----------------------------+-------------------+--------+
Maxlen показывает максимальное количество байтов, требуемых, чтобы сохранить один символ.

filename набора символов только для внутреннего пользования, SHOW CHARACTER SET не выводит его на экран.

Вы можете также получить информацию о наборах символов из INFORMATION_SCHEMA, которая содержит таблицу CHARACTER_SETS. См. раздел 22.1.

14.7.5.4. SHOW COLLATION

SHOW COLLATION
[LIKE 'pattern' | WHERE expr]
Этот запрос перечисляет сопоставления, поддержанные сервером. По умолчанию вывод SHOW COLLATION включает все доступные сопоставления. LIKE, если есть, указывает, которое сопоставление соответствует. WHERE может быть дан, чтобы выбрать строки, используя более общие условия, как обсуждено в разделе 22.31:
mysql> SHOW COLLATION WHERE Charset = 'latin1';
+-------------------+---------+----+---------+----------+---------+
| Collation         | Charset | Id | Default | Compiled | Sortlen |
+-------------------+---------+----+---------+----------+---------+
| latin1_german1_ci | latin1  |  5 |         | Yes      |       1 |
| latin1_swedish_ci | latin1  |  8 | Yes     | Yes      |       1 |
| latin1_danish_ci  | latin1  | 15 |         | Yes      |       1 |
| latin1_german2_ci | latin1  | 31 |         | Yes      |       2 |
| latin1_bin        | latin1  | 47 |         | Yes      |       1 |
| latin1_general_ci | latin1  | 48 |         | Yes      |       1 |
| latin1_general_cs | latin1  | 49 |         | Yes      |       1 |
| latin1_spanish_ci | latin1  | 94 |         | Yes      |       1 |
+-------------------+---------+----+---------+----------+---------+
Столбцы Collation и Charset указывают на названия сопоставления и набора символов, с которым оно связано. Id ID сопоставления. Default указывает, является ли сопоставление значением по умолчанию для своего набора символов. Compiled указывает, собран ли набор символов в сервер. Sortlen связан с суммой памяти, требуемой, чтобы сортировать строки, выраженные в наборе символов.

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

mysql> SHOW COLLATION WHERE `Default` = 'Yes';
+-------------------+---------+----+---------+----------+---------+
| Collation         | Charset | Id | Default | Compiled | Sortlen |
+-------------------+---------+----+---------+----------+---------+
| big5_chinese_ci   | big5    |  1 | Yes     | Yes      |      1  |
| dec8_swedish_ci   | dec8    |  3 | Yes     | Yes      |      1  |
| cp850_general_ci  | cp850   |  4 | Yes     | Yes      |      1  |
| hp8_english_ci    | hp8     |  6 | Yes     | Yes      |      1  |
| koi8r_general_ci  | koi8r   |  7 | Yes     | Yes      |      1  |
| latin1_swedish_ci | latin1  |  8 | Yes     | Yes      |      1  |
...
Вы можете также получить информацию о сопоставлениях из INFORMATION_SCHEMA, которая содержит таблицу COLLATIONS, см. раздел 22.2.

14.7.5.5. SHOW COLUMNS

SHOW [FULL] COLUMNS {FROM | IN} tbl_name
     [{FROM | IN} db_name]
     [LIKE 'pattern' | WHERE expr]
SHOW COLUMNS показывает сведения о столбцах в данной таблице. Это также работает на представлениях. LIKE, если есть, указывает, которые имена столбцов соответствуют. WHERE может быть дан, чтобы выбрать строки, используя более общие условия, как обсуждено в разделе 22.31.

SHOW COLUMNS покажет сведения только для тех столбцов, для которых у Вас есть некоторая привилегия.

mysql> SHOW COLUMNS FROM City;
+------------+----------+------+-----+---------+----------------+
| Field      | Type     | Null | Key | Default | Extra          |
+------------+----------+------+-----+---------+----------------+
| Id         | int(11)  | NO   | PRI | NULL    | auto_increment |
| Name       | char(35) | NO   |     |         |                |
| Country    | char(3)  | NO   | UNI |         |                |
| District   | char(20) | YES  | MUL |         |                |
| Population | int(11)  | NO   |     | 0       |                |
+------------+----------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
Если типы данных отличаются от того, что Вы ожидаете, что они будут основаны на CREATE TABLE, отметьте, что MySQL иногда изменяет типы данных, когда Вы создаете или изменяете таблицу. Условия, при которых это происходит, описаны в раздел 14.1.15.4.

FULL заставляет вывод включать с