¿Cómo se manejan las claves de aumento automático en INSERT (SELECT * FROM ...)
12
Tengo table1y table2en MySQL. Ambos tienen una auto_incrementclave primaria id.
Si los esquemas de la tabla coinciden y hago INSERT INTO table1 (SELECT * FROM table2)lo que sucede con respecto a las nuevas filas insertadas en table1? ¿Mantienen sus viejos idvalores y generan conflictos cuando una fila de table1tiene el mismo id? ¿Los nuevos valores son generados por auto_increment? ¿Depende del motor de almacenamiento o el bloqueo?
Puede insertar en una columna de incremento automático y especificar un valor. Esto esta bien; simplemente anula el generador de incremento automático.
Si intenta insertar un valor de NULL o 0 o DEFAULT, o si omite la columna de incremento automático de las columnas en su instrucción INSERT, esto activa el generador de incremento automático.
Entonces, está bien INSERT INTO table1 SELECT * FROM table2(por cierto, no necesitas los paréntesis). Esto significa que los valores de ID en table2serán copiados textualmente, y table1serán no generar nuevos valores.
Si deseatable1 generar nuevos valores, no puede hacerlo SELECT *. O usa nulo o 0 para la columna de identificación:
O bien, omite la columna de la lista de columnas de la instrucción INSERT y de la lista de selección de la instrucción SELECT:
-- No id in either case:INSERTINTO table1 (col1, col2, col3)SELECT col1, col2, col3,...FROM table2;
Antes de preguntar, no hay sintaxis en SQL para "select * excepto para una columna". Debe deletrear la lista completa de nombres de columnas que desea insertar.
¿No hay una opción que permita / no permita la inserción de 0 como valor? (Con respecto a su segundo párrafo)
Sascha Rambeaud
1
Sí, SQL_MODE = NO_AUTO_VALUE_ON_ZERO , de lo contrario nunca podríamos insertar un valor cero literal en una columna AI. Si usa este modo SQL, NULL aún funciona para activar el generador de IA, o la omisión de la columna también funciona.
Bill Karwin
@BillKarwin, Respecto a su último párrafo, después de obtener el resultado secundario select * from table, ¿no hay forma de operar en este resultado secundario para eliminar su primera columna?
Pacerier
@Pacerier, si entiendo correctamente, me preguntas si select *puede significar select * except for the first column. La respuesta es no. select *siempre solicita todas las columnas de esa tabla. Si desea un subconjunto, debe deletrear las columnas que desee.
Bill Karwin
@BillKarwin, Hmm, estaba pensando en girar la tabla para hacer cláusulas verticales, luego girarla hacia atrás, por ejemplo, select*from transpose(select*from(transpose(select*from table where Id=1))where col_name<>Id)o tal vez de manera más sucinta select*from table where Id=1 and $col<>Id, ¿qué te parece?
Pacerier
3
La identificación de la selección será el mismo valor insertado en la tabla. Esto provocará un error si está intentando duplicar filas existentes.
Bill Karwin: Antes de preguntar, no hay sintaxis en SQL para "select * excepto para una columna".
Esto se puede lograr con algo de creatividad:
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 NOTIN('id')),'
from <table> WHERE id = <id>');
PREPARE stmt1 FROM@sql;EXECUTE stmt1;
Esto dará como resultado que la nueva fila obtenga una identificación con incremento automático en lugar de la identificación de la fila seleccionada.
Inteligente, pero para mí, eso cuenta como deletrear la lista completa de los nombres de columna que desea insertar.
Bill Karwin
1
Bueno, es mysql automáticamente deletreando en lugar de hacerlo manualmente. Si tiene tablas con muchas columnas, evitará que se pierda una o que escriba algunas mal.
select * from table
, ¿no hay forma de operar en este resultado secundario para eliminar su primera columna?select *
puede significarselect * except for the first column
. La respuesta es no.select *
siempre solicita todas las columnas de esa tabla. Si desea un subconjunto, debe deletrear las columnas que desee.select*from transpose(select*from(transpose(select*from table where Id=1))where col_name<>Id)
o tal vez de manera más sucintaselect*from table where Id=1 and $col<>Id
, ¿qué te parece?La identificación de la selección será el mismo valor insertado en la tabla. Esto provocará un error si está intentando duplicar filas existentes.
Esto se puede lograr con algo de creatividad:
Esto dará como resultado que la nueva fila obtenga una identificación con incremento automático en lugar de la identificación de la fila seleccionada.
fuente