【问题标题】:Update multiple rows into SQL table将多行更新到 SQL 表中
【发布时间】:2008-10-08 18:17:36
【问题描述】:

假设有一个完全填充的数据数组 String[n][3] myData。

我想这样做:

for (String[] row : myData)
{
   SQL = "update mytable set col3 = row[2]
   where col1 = row[0] and col2=row[1];" 
}

显然我遗漏了很多,但我想尽可能简洁地表达这个想法。

有没有一种简单的方法可以在单个 DB 命令中执行此操作? 不那么简单的方法怎么样?

编辑: 数据不是来自另一个表(这是一个网络表单提交 - 多项选择考试)
鉴于应用程序是面向网络的,它必须是防注入的。参数化查询是我的首选方式。
我正在使用 MS-SQL Server 2005

编辑:关闭,并以Multiple DB Updates:重新询问

编辑:重新打开,因为这似乎是一个热门问题

【问题讨论】:

    标签: c# asp.net sql


    【解决方案1】:

    这取决于您使用的数据库。如果您使用的是 SQL Server 2008,则可以使用存储过程 TABLE parameters。这允许您将所有值传递到单个表中的存储过程中,然后您可以这样做:

    update mytable set mytable.col1 = @tbl.col1
      from mytable 
      inner join @tbl on mytable.col2 = @tbl.col2
    

    如果您使用的是 SQL Server 2005,则可以使用 XML。将值格式化为 XML,然后使用 XQuery 语句(即“nodes”和“value”)解析出 XML。这也可以在单个 SQL 语句中完成,并且不需要存储过程。

    【讨论】:

    • 我喜欢第一个选项,我得先等待升级。这是一个非常可爱的功能。
    • 任何示例如何使用 XQuery 的内连接方法在单个语句中更新?
    【解决方案2】:

    如果您使用的是 Sql Server,则可以使用 SqlBulkCopy。您首先必须将数据放入 DataTable 中,这非常容易,因为您已经将它放在了字符串数组中。

    http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx

    【讨论】:

      【解决方案3】:

      你可以制作一个大字符串,比如:

      for (String[] row : myData)
      {
         SQL += "update mytable set col3 = row[2]
         where col1 = row[0] and col2=row[1];" 
      }
      
      sqlDriver.doInsertQuery(SQL); // change this to your way of inserting into the db
      

      并且一次全部提交。我不太擅长 SQL,所以我会这样做。

      sql 引擎只会用 ';' 分割它并自己进行单独的插入。不过,可以将其全部添加到字符串中。这就像你将一个带有多个更新/插入的大字符串复制到 sql 提示符中一样

      【讨论】:

      • 现在如何参数化它?
      【解决方案4】:

      这可能不是您想要的答案,但是从数据库的角度来看,打开一个事务、执行您的语句然后提交该事务将按照您的描述进行。

      在事务完成之前,对于数据库的其他用户,数据库的状态不会改变,这可能是首选效果。

      【讨论】:

        【解决方案5】:

        如果您在数据访问层中使用Enterprise Library,您可以在 .Net 中创建事务,遍历您的过程调用,然后从 .Net 提交/回滚。

        DbTransaction transaction = connection.BeginTransaction();
        try
        {
            for (String[] row : myData)
            {
                ListDictionary params = new Specialized.ListDictionary();
                params.add("@col3", row[2]);
                params.add("@col1", row[0]);
                params.add("@col2", row[1]);
                executeNonQuery("myUpdateProcedure", params);
            }
        
            transaction.commit();
        
        }
        catch(Exception ex)
        {
            transaction.rollback();
            throw ex;
        }
        finally
        {
        
            connection.close();
        }
        

        【讨论】:

        • 我喜欢这样。虽然,多次调用 executeNonQuery 怎么样?这不也是一笔开销吗?
        • 取决于您的查询。如果您保持轻量级并且不使用动态 SQL,那么您应该没问题。以这种方式运行事务使用单个连接,这节省了一些服务器资源,并且查询将在缓存中保持新鲜。
        • 抱歉 - 我的意思是说影响取决于您的查询。对数据库运行任何东西都是一笔开销。
        【解决方案6】:

        如果由于某种原因您无法使用上面建议的方法之一执行更新,那么下面的效率极低的方法可能对您有用。

        SQL = "Update myTable Set Col3 = Case " 
        for (String[] row : myData)
        {
           SQL += "When Col1 = " + Row[0] + " and Col2 = " + Row[1] + " then " + row[2] + " "   
        }
        SQL + = "Else Col3 end"  
        

        【讨论】:

          【解决方案7】:

          看起来您想要更新 A,在具有编码 B 和 C 的行上。(A、B、C)在 myData 中存储为元组(行)。不是吗?

          也许(如果您使用的是 Microsoft SQL Server...我不知道它是否存在于 Oracle 中,可能)您可以使用带有 UPDATE 的 JOIN。您可以在与另一个连接的表上声明更新。如果 myData 来自另一个表,那么您可以这样做(这不是正确的语法):

          UPDATE whatchanges wc INNER JOIN changes c ON <yourcondition>
          SET wc.col1 = c.newvalue
          WHERE ....
          

          (如果您想应用“更改”表中的所有更改,您当然不必使用 WHERE,INNER JOIN 已经选择了正确的行)。

          当然,这种更新是有限制的。它是 MS SQL 专有的。因此,如果是您的情况,我建议您在 MS web 上查找它(关键字:UPDATE 和 JOIN)

          【讨论】:

          • 第一个段落是正确的,只是 C 被更新了,条件 A 和 B,但这是微不足道的。
          【解决方案8】:

          不是真的。您可以使用相同的循环创建字符串,然后将您的值作为参数传递,但这仍然是多个数据库命令。

          for each whatever
              sql += "UPDATE ... ;"
          end for
          execute (sql)
          

          【讨论】:

          • 是的,这就是我要避免的。我想在单个事务中使用参数化查询进行批量更新。
          【解决方案9】:

          我怀疑您将需要使用多个 SQL 语句。您可能会找到一个包装器来处理细节,但在下面我想它会为每个 UPDATE 迭代地运行一条 SQL 语句。

          【讨论】:

            【解决方案10】:

            发出与值表相反的更新:

            UPDATE myTable SET col3=c FROM myTable JOIN (
              SELECT 1 as a, 2 as b, 'value1' as c UNION ALL
              SELECT 3 as a, 4 as b, 'value2' as c -- etc...
            ) x ON myTable.col1=x.a AND myTable.col2=x.b
            

            所以你只需像这样把它放在一起:

            // make one of these for each row
            String.Format("SELECT {0} as a, {1} as b, '{2}' as c", 
              row[0], row[1], row[2].Replace("'","''")) 
            
            // put it together
            string expr = "UPDATE myTable SET col3=c FROM myTable JOIN (" +
              String.Join(stringformatarray, " UNION ALL ") +
              ") x ON myTable.col1=x.a AND myTable.col2=x.b"
            

            或者你可以使用 StringBuilder 把它放在一起。

            然后,当然,你执行这个字符串。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2013-02-11
              • 1970-01-01
              • 2020-03-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多