Как обрабатываются ключи auto_increment в INSERT (SELECT * FROM…)

13

У меня есть table1и table2в MySQL. У обоих есть первичный auto_incrementключ id.

Если схемы таблиц совпадают, и я делаю, INSERT INTO table1 (SELECT * FROM table2)что происходит с новыми строками, вставленными в table1? Сохраняют ли они свои старые idзначения и порождают ли конфликты, когда строка из table1них совпадает id? Новые значения генерируются auto_increment? Это зависит от системы хранения или блокировки?

Томас Джонсон
источник

Ответы:

13

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

Если вы попытаетесь вставить значение NULL или 0 или DEFAULT, или если вы опустите столбец автоинкремента из столбцов в вашем операторе INSERT, это активирует генератор автоинкремента.

Так что это нормально INSERT INTO table1 SELECT * FROM table2(кстати, вам не нужны скобки). Это означает, что значения id в table2будут скопированы дословно, и неtable1 будут генерировать новые значения.

Если вы хотите table1 генерировать новые значения, вы не можете сделать SELECT *. Либо вы используете ноль или 0 для столбца id:

INSERT INTO table1 SELECT 0, col1, col2, col3, ... FROM table2;

Или же вы опускаете столбец как из списка столбцов оператора INSERT, так и из списка выбора оператора SELECT:

-- No id in either case:
INSERT INTO table1 (col1, col2, col3) SELECT col1, col2, col3, ... FROM table2;

Прежде чем вы спросите, в SQL нет синтаксиса для «select *, кроме одного столбца». Вы должны изложить полный список имен столбцов, которые вы хотите вставить.

Билл Карвин
источник
Нет ли опции, которая позволяет / запрещает вставку 0 в качестве значения? (Относительно вашего второго абзаца)
Саша Рэмбо
1
Да, SQL_MODE = NO_AUTO_VALUE_ON_ZERO , иначе мы никогда не сможем вставить буквально нулевое значение в столбец AI. Если вы используете этот режим SQL, NULL по-прежнему работает, чтобы активировать генератор AI, или опускание столбца тоже работает.
Билл Карвин
@BillKarwin, Что касается вашего последнего абзаца, после получения подрезультата select * from table, нет ли способа воздействовать на этот подрезультат, чтобы удалить его первый столбец?
Pacerier
@Pacerier, если я правильно понимаю, ты спрашиваешь, select *может ли это иметь в виду select * except for the first column. Ответ - нет. select *всегда запрашивает все столбцы из этой таблицы. Если вы хотите подмножество, вы должны указать столбцы, которые вы хотите.
Билл Карвин
@BillKarwin, Хм, я думал о том, чтобы повернуть таблицу, чтобы сделать вертикальные пункты, где, а затем повернуть ее назад, например, select*from transpose(select*from(transpose(select*from table where Id=1))where col_name<>Id)или, возможно, более кратко, как select*from table where Id=1 and $col<>Id, что вы думаете?
Pacerier
3

Идентификатор из выбора будет таким же значением, вставленным в таблицу. Это приведет к ошибке, если вы попытаетесь дублировать существующие строки.

Билл Карвин: Прежде чем вы спросите, в SQL нет синтаксиса для «select *, кроме одного столбца».

Это может быть достигнуто с некоторой креативностью:

SET @sql = CONCAT('INSERT INTO <table> SELECT null, 
    ', (SELECT GROUP_CONCAT(COLUMN_NAME) 
    FROM information_schema.columns 
    WHERE table_schema = '<database>' 
    AND table_name = '<table>' 
    AND column_name NOT IN ('id')), ' 
from <table> WHERE id = <id>');  

PREPARE stmt1 FROM @sql;
EXECUTE stmt1;

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

curmil
источник
2
Умно, но для меня это считается полным списком имен столбцов, которые вы хотите вставить.
Билл Карвин
1
Ну, это MySQL автоматически по сравнению с выполнением вручную. Если у вас есть таблицы с большим количеством столбцов, это позволит вам не пропустить одну или несколько ошибок в написании.
Curmil