2008-10-08 81 views
2

取代問題:Update multiple rows into SQL table多個數據庫更新:

下面是更新考試結果集的代碼片段。 DB結構是給定的,但我可以提交包含存儲過程(這是修改痛苦,所以我保存到最後。)

的問題:有沒有使用SQL v服務器2005年有更好的方式。 ,淨2.0?

string update = @"UPDATE dbo.STUDENTAnswers 
           SET [email protected] 
           WHERE StudentID [email protected] and QuestionNum [email protected]"; 
      SqlCommand updateCommand = new SqlCommand(update, conn); 
      conn.Open(); 

      string uid = Session["uid"].ToString(); 
      for (int i= tempStart; i <= tempEnd; i++) 
      { 
       updateCommand.Parameters.Clear(); 
       updateCommand.Parameters.AddWithValue("@ID",uid); 
       updateCommand.Parameters.AddWithValue("@qnum",i); 
       updateCommand.Parameters.AddWithValue("@answer", Request.Form[i.ToString()]); 
       try 
       { 
        updateCommand.ExecuteNonQuery(); 
       } 
       catch { } 
      } 

回答

4

有幾件事情中脫穎而出:

  • 你不顯示在SqlConnection的實例化,因此目前還不清楚,你妥善處理它。

  • 您不應該在循環中吞食異常 - 更好地在頂級異常處理程序中處理它們。

  • 您正在通過循環實例化每次迭代的新參數 - 您可以重新使用這些參數。

把此一併它可能看起來像下面的(如果你不想使用事務,即不關心,如果一些但不是所有的更新成功):

using (SqlConnection conn = new SqlConnection(connectionString)) 
{ 
    conn.Open(); 
    using (SqlCommand updateCommand = new SqlCommand(update, conn)) 
    { 
     string uid = Session["uid"].ToString(); 
     updateCommand.Parameters.AddWithValue("@ID", uid); 
     updateCommand.Parameters.AddWithValue("@qnum", i); 
     updateCommand.Parameters.Add("@answer", System.Data.SqlDbType.VarChar); 
     for (int i = tempStart; i <= tempEnd; i++) 
     { 
      updateCommand.Parameters["@answer"] = Request.Form[i.ToString()]; 
      updateCommand.ExecuteNonQuery(); 
     } 
    } 
} 

或使用事務,以確保全有或全無:

using (SqlConnection conn = new SqlConnection(connectionString)) 
{ 
    conn.Open(); 
    using (SqlTransaction transaction = conn.BeginTransaction()) 
    { 
     using (SqlCommand updateCommand = new SqlCommand(update, conn, transaction)) 
     { 
      string uid = Session["uid"].ToString(); 
      updateCommand.Parameters.AddWithValue("@ID", uid); 
      updateCommand.Parameters.AddWithValue("@qnum", i); 
      updateCommand.Parameters.Add("@answer", System.Data.SqlDbType.VarChar); 
      for (int i = tempStart; i <= tempEnd; i++) 
      { 
       updateCommand.Parameters["@answer"] = Request.Form[i.ToString()]; 
       updateCommand.ExecuteNonQuery(); 
      } 
      transaction.Commit(); 
     } 
    } // Transaction will be disposed and rolled back here if an exception is thrown 
} 

最後,另一個問題是,你是混合數據訪問代碼UI代碼(例如的Request.Form)。分離這些將會更模塊化和可測試 - 例如通過將應用程序分解爲UI,業務邏輯和數據訪問層。

-1

發出一個更新是違背了值表:

UPDATE s SET ANSWER=a FROM dbo.STUDENTAnswers s JOIN (
    SELECT 1 as q, 'answer1' as a 
    UNION ALL SELECT 2, 'answer2' -- etc... 
) x ON s.QuestionNum=x.q AND [email protected] 

所以你只要把這個在一起,就像這樣:

using(SqlCommand updateCommand = new SqlCommand()) { 
    updateCommand.CommandType = CommandType.Text; 
    updateCommand.Connection = conn; 
    if (cn.State != ConnectionState.Open) conn.Open(); 

    StringBuilder sb = new StringBuilder("UPDATE s SET ANSWER=a FROM dbo.STUDENTAnswers s JOIN ("); 
    string fmt = "SELECT {0} as q, @A{0} as a"; 
    for(int i=tempStart; i<tempEnd; i++) { 
    sb.AppendFormat(fmt, i); 
    fmt=" UNION ALL SELECT {0},@A{0}"; 
    updateCommand.Parameters.AddWithValue("@A"+i.ToString(), Request.Form[i.ToString()]); 
    } 
    sb.Append(") x ON s.QuestionNum=x.q AND [email protected]"); 
    updateCommand.CommandText = sb.ToString(); 
    updateCommand.Parameters.AddWithValue("@ID", uid); 
    updateCommand.ExecuteNonQuery(); 
} 

這具有的其他所有優點沒有任何操作(如果你在交易中包裝了幾個更新)並且運行速度會更快:

  • 表和相關的索引看着/更新一次
  • 只需支付應用程序與數據庫服務器之間的延遲一次,而不是每次更新
0

我看到的一個問題是,當你正在打開您的連接。

我會至少在每次更新之前調用open並在更新後關閉連接。

如果您的循環需要時間來執行,您的連接將會打開很長時間。

這是一個很好的規則,永遠不要打開你的命令,直到你需要它。

+0

每次回發循環運行約30次。 我的想法是,我可以節省30次開閉。我錯了嗎? – 2008-10-08 19:49:16

+0

我同意,我寧願有一個打開的連接,無論循環需要執行多長時間,都要打開和關閉連接N次。 – palmsey 2008-10-08 20:45:56

0

您可以使用OpenXML進行批量插入。創建一個包含所有問題和答案的XML文檔,並使用它來插入值。

編輯:如果您堅持使用您當前的解決方案,我至少會將您的SqlConnection和SqlCommand包裝在一個使用塊中,以確保它們被丟棄。

2

對於30個更新,我認爲你是在正確的軌道上,雖然關於需要在updateCommand附近使用的評論是正確的。

我們發現執行批量更新(> 100行)的最佳執行方式是通過SqlBulkCopy類轉移到臨時表,然後通過存儲過程調用來填充活動表。