有没有办法忽略INSERT上不存在的列?

时间:2011-10-09 14:50:32

标签: mysql sql

我正在使用MySQL GUI将某些网站迁移到新版本的CMS,方法是选择某些表并将从备份转储生成的INSERT语句运行到空表中(新模式) )。旧表中有一些列在新表中不存在,因此脚本会停止,并出现如下错误:

  

脚本行:'字段列表'中的未知列'user_id'

挑选要导出的所需列,或者编辑转储文件会过于繁琐且耗时。要解决这个问题,我会在生成错误时创建未使用的列,通过运行查询导入数据,然后在完成该表时删除未使用的列。我看过INSERT IGNORE,但这似乎是为了忽略重复的键(不是我正在寻找的)。

有没有办法在忽略目标表中不存在的列的同时预先形成INSERT?我正在寻找一些“无痛”的东西,就像一些现有的SQL功能一样。

为了澄清,我正在使用一堆备份文件并将数据导入本地数据库进行测试,然后再将其移至实时服务器。我希望的解决方案示例:

-- Don't try to insert data from columns that don't exist in "new_table"
INSERT INTO `new_table` {IGNORE UNKNOWN COLUMNS} (`id`, `col1`, `col2`) VALUES 
  (1, '', ''),
  (2, '', '');

如果这样的事情根本不存在,我很乐意接受这个答案并继续使用我当前的解决方法。

7 个答案:

答案 0 :(得分:5)

您目前的技术似乎足够实用。只是一个小小的变化。

您可以只导出架构,执行差异并查找所有表中所有缺少的列,而不是等待错误然后逐个创建列。

这样就少了工作。

你的gui将只能导出架构,或者mysqldump上的以下开关将有助于找出所有缺失的列。

mysqldump --no-data -uuser -ppassword --database dbname1 > dbdump1.sql
mysqldump --no-data -uuser -ppassword --database dbname2 > dbdump2.sql

扩展dbdump1.sql和dbdump2.sql将为您提供两个数据库的所有差异。

答案 1 :(得分:3)

你可以写一个像这样的商店功能:

sf_getcolumns(table_name varchar(100))

返回字符串,如下所示: 'field_1,field_2,field_3,...'

然后创建商店程序

sp_migrite (IN src_db varchar(50), IN target_db varchar(50))

运行表格,并为每个表获取字段列表,然后创建一个类似

的字符串
cmd = 'insert into ' || <target_db><table_name> '(' || <fileds_list> || ') SELECT' || <fileds_list> || ' FROM ' <src_db><table_name>
然后

执行每个表的字符串

答案 2 :(得分:1)

  

有没有办法在忽略目标表中不存在的列的同时执行INSERT?我正在寻找一些“无痛”的东西,就像一些现有的SQL功能一样。

不,没有“无痛”的方法。

相反,您必须显式处理最终表中不存在的那些列。例如,您必须从输入流中删除它们,在事实之后删除它们,播放脏技巧(engine=BLACKHOLE +触发器以仅插入您想要的真实目标模式),无论如何。

现在,这不一定需要 manual - 有工具(如Devart noted)以及查询db目录以确定列名的方法。但是,它并不像简单地注释INSERT语句那么容易。

也许CMS供应商可以提供合理的迁移脚本?

答案 3 :(得分:0)

dbForge Studio for MySQL将为您提供在两个数据库之间compare and synchronize数据的机会。

默认情况下,仅对具有相同名称的对象执行数据比较;您可以手动使用自动映射或映射数据库对象。 dbForge Studio允许您自定义表和列的映射,因此您可以比较具有不相等名称,所有者和结构的对象的数据。您还可以映射具有不同类型的列,但这可能会导致某些类型的同步期间数据截断,舍入和错误。

答案 4 :(得分:0)

发现你的问题很有趣。

我知道有一种方法可以从MySQL中的表中选择列名;它是show columns from tablename。我忘记的是所有MySQL表数据都保存在一个名为“information_schema”的特殊数据库中。

这是合乎逻辑的解决方案,但它不起作用:

mysql> insert into NEW_TABLE (select column_name from information_schema.columns where table_name='NEW_TABLE') values ...
但是,我会继续寻找。如果可以从select column_name查询中获取逗号分隔的值,那么您可能正在开展业务。

编辑:

您可以使用select ... from ... into命令生成单行CSV,如下所示:

mysql> select column_name from information_schema.columns where table_name='NEW_TABLE' into outfile 'my_file' fields terminated by '' lines terminated by ', '

我不知道如何将其输出到MySQL CLI标准输出端。

答案 5 :(得分:0)

我仔细阅读了所有这些帖子,因为我遇到了同样的挑战。请查看我的解决方案:

我是用c#做的,但你可以用任何语言做。

检查insert语句的列名。如果您的实际表中缺少任何内容,请将它们添加为TEXT列,因为TEXT可以吃任何东西。

完成插入该表后,删除添加的列。

完成。

答案 6 :(得分:0)

如果您的表和数据库位于同一台服务器上,并且您 知道 这些通用列兼容,则可以使用GROUP_CONCAT,{ {1}}和准备好的语句。

此示例创建两个相似的表 并从通用列中插入数据 table_a到table_b。由于两个表都有 (注意:我正在使用的数据库[table_schema]称为“测试”)

INFORMATION_SCHEMA.COLUMNS

准备好的语句最终看起来像这样:

create table if not exists `table_a` (
  `id` int(11) not null auto_increment,
  `a` varchar(2) default null,
  `b` varchar(2) default null,
  `c` varchar(2) default null,
  `d` varchar(2) default null,
  PRIMARY KEY (`id`)
);

create table if not exists `table_b` (
  `id` int(11) not null auto_increment,
  `a` varchar(2) default null,
  `b` varchar(2) default null,
  `c` varchar(2) default null,
  PRIMARY KEY (`id`)
);

insert into table_a
  (a, b, c, d)
values
  ('a1', 'b1', 'c1', 'd1'),
  ('a2', 'b2', 'c2', 'd2'),
  ('a3', 'b3', 'c3', 'd3');

-- This creates a comma delimited list of common
-- columns in table_a and table_b. It also excludes
-- any columns you don't want from table_a

set @common_columns = (
  select
    group_concat(column_name)
  from
    information_schema.columns
  where
    table_schema = 'test'
    and
    table_name = 'table_a'
    and
    column_name not in ('id')
    and
    column_name in (
      select
        column_name
      from
        information_schema.columns
      where
        table_schema = 'test'
        and
        table_name = 'table_b'
    )
);

set @stmt = concat(
  'insert into table_b (', @common_columns, ') ',
  'select ', @common_columns, ' from table_a;'
);

prepare stmt from @stmt;
execute stmt;
deallocate prepare stmt;

select * from table_b;

不要忘记更改insert into table_b (a, b, c) select a, b, c from table_a; table_name的值以匹配 您的表和数据库(table_schema) 。如果有用,可以创建一个存储过程来完成此任务。