【问题标题】:MySQL: How to copy rows, but change a few fields?MySQL:如何复制行,但更改几个字段?
【发布时间】:2011-02-16 12:14:33
【问题描述】:

我有大量行要复制,但我需要更改一个字段。

我可以选择要复制的行:

select * from Table where Event_ID = "120"

现在我想复制所有这些行并创建新行,同时将Event_ID 设置为155。我怎样才能做到这一点?

【问题讨论】:

    标签: sql mysql


    【解决方案1】:
    INSERT INTO Table
              ( Event_ID
              , col2
               ...
              )
         SELECT "155"
              , col2
               ...
          FROM Table WHERE Event_ID = "120"
    

    这里,col2, ... 表示表中的其余列( Event_ID 之外的列)。

    【讨论】:

    • 有没有什么方法可以不用指定列名?
    • 我不知道。当然,如果您的表有 1000 列或其他内容,并且您不想全部输入,那么您可以编写一条 SQL 语句来构建您的 SQL 语句 :)。您将这样做的方式是使用 information_schema 来获取表的列名。但这实在是太过分了,我只需要输入列名。
    • 这是否可以使用星号来获取剩余的列?
    • 登录投票只是为了发现我已经投票了。我想这已经救了我好几次了:)谢谢!
    • @Bitterblue - 对不起,我不明白你的评论。我从未说过 col2, ... 是您不想复制的列,我只是说它们代表表中的其余列。很明显它们会被复制,否则根本不会出现在 SQL 语句中。
    【解决方案2】:

    这是一个解决方案,您的表格中有许多字段,并且不想因输入所有字段而手指抽筋,只需输入所需的字段即可:)

    如何将一些行复制到同一个表中,其中一些字段具有不同的值:

    1. 创建一个包含所有要复制的行的临时表
    2. 用您想要的值更新临时表中的所有行
    3. 如果你有一个自增字段,你应该在临时表中将它设置为NULL
    4. 将临时表的所有行复制到原始表中
    5. 删除临时表

    您的代码:

    CREATE table temporary_table AS SELECT * FROM original_table WHERE Event_ID="155";
    
    UPDATE temporary_table SET Event_ID="120";
    
    UPDATE temporary_table SET ID=NULL;
    
    INSERT INTO original_table SELECT * FROM temporary_table;
    
    DROP TABLE temporary_table;
    

    一般场景代码:

    CREATE table temporary_table AS SELECT * FROM original_table WHERE <conditions>;
    
    UPDATE temporary_table SET <fieldx>=<valuex>, <fieldy>=<valuey>, ...;
    
    UPDATE temporary_table SET <auto_inc_field>=NULL;
    
    INSERT INTO original_table SELECT * FROM temporary_table;
    
    DROP TABLE temporary_table
    

    简化/压缩代码:

    CREATE TEMPORARY TABLE temporary_table AS SELECT * FROM original_table WHERE <conditions>;
    
    UPDATE temporary_table SET <auto_inc_field>=NULL, <fieldx>=<valuex>, <fieldy>=<valuey>, ...;
    
    INSERT INTO original_table SELECT * FROM temporary_table;
    

    由于临时表的创建使用 TEMPORARY 关键字,它会在会话结束时自动删除(如 @ar34z 建议的那样)。

    【讨论】:

    • MySQL 支持TEMPORARY 关键字来创建临时表。当会话(一系列 SQL 查询)完成时,CREATE TEMPORARY TABLE 的使用将自动删除表。删除该表是不必要的,并且它不会与使用相同名称的其他临时表冲突。 (例如,当实时黑客(我不推荐))
    • 此代码仅在您使用#temporary_table 而不是temporary_table 时才有效,可能是MSSQL 问题?
    • 这对我来说基本上是完美的,但我确实必须克服临时表中主键上的 Not Null 约束,该约束似乎是从原始表中复制的。我通过在更新之前更改临时表来解决此问题,如下所示:ALTER TABLE temporary_table MODIFY &lt;auto_inc_not_null_field&gt; INT; 然后将主键更新为 Null 不会失败。
    • 我无法让它在 PostgreSQL 9.4 中工作:Exception: null value in column &lt;auto_inc_not_null_field&gt; violates not-null constraint。我试过ALTER TABLE temporary_table ALTER COLUMN &lt;auto_inc_not_null_field&gt; DROP NOT NULL;
    • 我用不同的 MySQL 和 MariaDB 版本进行了测试。非常适合我,我更喜欢这个版本而不是接受的答案,这实际上经常发生在这里:)
    【解决方案3】:

    假设您的表格还有另外两列:foo 和 bar

    INSERT INTO Table (foo, bar, Event_ID)
    SELECT foo, bar, "155"
      FROM Table
     WHERE Event_ID = "120"
    

    【讨论】:

    • 有没有什么方法可以不用指定列名?
    • @PeterBailey MySQL 新手,能否请您了解一下代码的工作原理:/
    【解决方案4】:

    如果您的表中有大量列并且不想输入每一列,您可以使用临时表来完成,例如;

    SELECT *
    INTO #Temp
    FROM Table WHERE Event_ID = "120"
    GO
    
    UPDATE #TEMP
    SET Column = "Changed"
    GO
    
    INSERT INTO Table
    SELECT *
    FROM #Temp
    

    【讨论】:

    • 注意:这假设您的表中没有主键
    【解决方案5】:

    嘿,如何复制所有字段,将其中一个更改为相同的值 + 其他值。

    INSERT INTO Table (foo, bar, Event_ID)
    SELECT foo, bar, Event_ID+"155"
      FROM Table
     WHERE Event_ID = "120"
    

    ????????????

    【讨论】:

      【解决方案6】:

      只要 Event_ID 为 Integer,请执行以下操作:

      INSERT INTO Table (foo, bar, Event_ID)
      SELECT foo, bar, (Event_ID + 155)
        FROM Table
      WHERE Event_ID = "120"
      

      【讨论】:

        【解决方案7】:

        补充@DaveTheBFG 的答案: 如果您有一个标识列(以下示例中的“Table_PK”),则 INSERT 行将失败,但您可以执行以下操作(特定于 SQL Server,但该概念可能适用于其他数据库):

        SELECT *
        INTO #Temp
        FROM Table WHERE Event_ID = "120"
        
        UPDATE #TEMP
        SET Column = "Changed"
        
        ALTER TABLE #TEMP DROP COLUMN Table_PK
        
        EXEC sp_executesql N'INSERT INTO Table SELECT * FROM #Temp'
        

        【讨论】:

          猜你喜欢
          • 2021-03-12
          • 2017-11-22
          • 2012-05-25
          • 1970-01-01
          • 1970-01-01
          • 2014-04-11
          • 2013-09-22
          • 1970-01-01
          • 2019-12-16
          相关资源
          最近更新 更多