关于mysql:INSERT INTO…SELECT而不详细列出所有列

INSERT INTO … SELECT without detailing all columns

如何在MySQL中使用SQL在table_sourcetable_target中插入选定的行,其中:

  • 两个表具有相同的架构
  • 除自动递增id之外,所有列均应传输
  • 如果没有显式地写所有列名,那将是乏味的

琐碎的INSERT INTO table_target SELECT * FROM table_source在重复的主键条目上失败。


您可以在插入...选择中列出所有想要的字段,或者在外部使用其他内容为您创建列表。

SQL没有SELECT * except somefield FROM之类的东西,因此您必须硬着头皮写出字段名称。


必须指定列名-

1
2
INSERT INTO table_target SELECT NULL, column_name1, column_name2, column_name3, ...
  FROM table_source;

只需将NULL作为自动递增id字段的值传递。


当然,主键必须是唯一的。这取决于要实现的目标,但是您可以排除具有主键已经存在的行。

1
2
INSERT INTO table_target SELECT * FROM table_source
WHERE table_source.id NOT IN (SELECT id FROM table_target)

更新:由于还需要多余的行,因此您应该首先解决冲突,table_source是否具有关系?如果没有,您可以更改这些键:

1
2
UPDATE table_source SET id = id + 1000
WHERE id IN (SELECT id FROM table_target)

其中1000是一个常数,足够大,因此它们可以放在表的末尾。


乏味但又安全又正确。

在不提供列列表的情况下编写INSERT语句会导致难以调试的代码,更重要的是,如果更改表的定义,则会导致非常脆弱的代码中断。

如果您绝对不能自己写出列名,那么在您的代码中构建一个将为您创建逗号分隔列表的工具相对容易。


这是我使用'replace insert'命令进行批量更新的最终解决方案。

1
2
3
4
5
6
7
8
SET @@session.group_concat_max_len = @@global.max_allowed_packet;
SET @schema_db = 'db';
SET @tabl = 'table';
SET @cols = (SELECT CONCAT('`',GROUP_CONCAT(COLUMN_NAME SEPARATOR '`, `'), '`') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema_db AND TABLE_NAME = @tabl GROUP BY TABLE_NAME);
SET @Querystr = CONCAT('REPLACE INTO ',@schema_db,'.',@tabl,' SELECT ', @cols,' FROM import.tbl_', @tabl);

PREPARE stmt FROM @Querystr;
EXECUTE stmt;

我认为您可以使用如下语法:

1
2
INSERT INTO table (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE c=c+1;

REF:http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
希望对您有帮助


n


似乎无法在MySQL Prepared语句中将列作为占位符给出。我已经编译了以下解决方案进行测试:

1
2
3
4
5
6
7
SET @schema_db = 'DB';
SET @table = 'table';
SET @cols = (SELECT CONCAT(GROUP_CONCAT(COLUMN_NAME SEPARATOR ', '),"\
"
) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema_db AND TABLE_NAME = @table GROUP BY TABLE_NAME);
SET @Querystr = CONCAT('SELECT',' ', @cols,' ','FROM',' ',@schema_db,'.',@table,' ', 'Limit 5');
PREPARE stmt FROM @Querystr;
EXECUTE stmt;

您可以使用准备好的语句来完成此操作。

1
2
3
4
PREPARE table_target_insert FROM 'INSERT INTO table_target SELECT ? FROM table_source';
SET @cols:='';
SELECT @cols:=GROUP_CONCAT(IF(column_name = 'id','NULL',column_name) separator",") FROM information_schema.columns WHERE table_name='table_source';
EXECUTE table_target_insert USING @cols;

INSERT IGNORE只是"绕过"重复的行。

http://dev.mysql.com/doc/refman/5.5/zh-CN/insert.html


最简单的方法是使用phpmyadmin编写列列表,然后根据需要进行更改,在下面的示例中,我要复制id = 1078的行,并且在此表中,我具有id唯一的自动增量和别名unique。因此我创建了如下查询,其ID为