2012-12-27 26 views
0

這實際上是從here繼續。Coldfusion:如何用一個ID更新多條記錄

說一個老師想更新學生的技能。過程如下:

  1. 選擇學生的姓名。
  2. 查看學生的個人資料。
  3. 點擊更新鏈接。 UPDATE頁面顯示了複選框的技能列表。
  4. 老師可以選中或取消選中學生的技能。然後點擊提交。

E.g:

+------+------------------------+ 
Draw | <checkbox checked > 
+------+------------------------+ 
Read | <checkbox> 
+------+------------------------+ 
Dance | <checkbox checked > 
+------+------------------------+ 

所以這裏的問題;

  1. 如何使用一個ID更新多個提交? (比較提交值與數據庫中的提交值)

  2. 當studentskill中不存在skillid時,如何添加(INSERT INTO)?

表技能

+---------+------------+ 
| skillid | skillname | 
+---------+------------+ 
| 1  | draw  | 
+---------+------------+ 
| 2  | read  | 
+---------+------------+ 
| 3  | dance  | 
+---------+------------+ 

表studentskill

+----------+----------| 
|studentid | skillid | 
+----------+----------+ 
| 001  | 1  | 
| 001  | 2  | 
| 002  | 1  | 
| 002  | 2  | 
| 002  | 3  | 
+----------+----------+ 
+0

難道你還不得不刪除一個技能,如果它沒有選中? – orandov

+0

@orandov:studentskill表中有一個skill_flag列。如果教師想要取消選中該複選框,它將更新爲0.(默認情況下,當教師提交學生的技能時,skill_flag值將爲1) – vamps

回答

2

我同意李的答案。我只是添加(以及此添加太長的評論)如下:

1)避免刪除所有記錄,然後重新添加它們。有一天,你可能會決定你需要額外的數據,如果你刪除了所有的技能,那麼只要這段代碼運行,你就會失去它。很容易正確地添加WHERE子句,所以你可以這樣做。

2)我會建議使用「WHERE NOT EXISTS」而不是OUTER JOIN來確保記錄不存在於學生技能表中。 OUTER JOIN可能會表現得更好一些,但是WHERE NOT EXISTS應該在這種情況下表現得更好,並且會更清晰。

畢竟,你說過「學生技能不存在於表studentkill」和「WHERE NOT EXISTS」中的讀法非常類似。

<cftransaction> 
    <cfquery ...> 
     DELETE 
     FROM StudentSkill 
     WHERE studentID = <cfqueryparam value="#form.studentId#" cfsqltype="cf_sql_integer"> 
     <cfif listLen(form.skillId)> 
     AND skillId NOT IN (<cfqueryparam value="#form.skillId#" cfsqltype="cf_sql_integer" list="true">) 
     </cfif> 
    </cfquery> 

    <cfquery ...> 
     INSERT INTO StudentSkill (studentId, skillId) 
     SELECT <cfqueryparam value="#form.studentId#" cfsqltype="cf_sql_integer"> 
       , skillId 
     FROM Skill 
     WHERE skillId IN (<cfqueryparam value="#form.skillId#" cfsqltype="cf_sql_integer" list="true">) 
     AND NOT EXISTS 
       (
        SELECT 1 
        FROM  StudentSkill 
        WHERE studentID = <cfqueryparam value="#form.studentId#" cfsqltype="cf_sql_integer"> 
         AND skillID = Skill.skillID 
       ) 
    </cfquery> 
    </cftransaction> 

如前所述,將整個事物封裝在cftransaction中將確保發生更改的有限集合或根本沒有。

+0

是的,'不存在'是另一種選擇,我同意它更直觀。甚至可能比「外部」加入要便宜一點。但是你必須檢查實際的查詢計劃。 – Leigh

+0

@vamps - 另外,我從後面的評論中看到'studentSkill'表可能包含超出學生和技能ID的其他數據。如果是這樣的話,史蒂夫是對的。你一定要去第二個選擇。 – Leigh

+0

是@leigh,我確實意識到這一點,我將更新答案,直到我讀到更正確的史蒂夫布萊恩回答。謝謝,你們倆。 – vamps

0

SQL Server 2008支持表值參數,但我不知道這是否是在ColdFusion支持。

查看此答案:Passing a Table Valued parameter to a stored procedure

在那個答案中有一個如何將XML列表傳遞給存儲過程的鏈接。在存儲過程中,您可以將XML列表加載到臨時表中,並通過加入臨時表來插入和刪除記錄。

+0

此場景的ColdFusion部分將創建發送的xml字符串到存儲過程。 CF具有足夠的功能。 –

4

更新:

原來,StudentSkill包含附加列(超出StudentID和SkillID)。 Steve Bryant's answer是該場景的更好選擇。


一個常用的方法是DELETE第一個選定的學生的所有現有技能。然後INSERT新技能。優點:比第二種方法更直接一點缺點:即使沒有任何變化,每次都會刪除一次。

<!--- change cfsqltypes if needed ---> 
    <cfquery ...> 
     DELETE FROM StudentSkill 
     WHERE studentID = <cfqueryparam value="#form.studentId#" cfsqltype="cf_sql_integer"> 
    </cfquery> 

    <cfquery ...> 
     INSERT INTO studenSkill (studenId, skillId) 
     SELECT <cfqueryparam value="#form.studentId#" cfsqltype="cf_sql_integer"> 
       , skillId 
     FROM skill 
     WHERE skillId IN 
       (
       <cfqueryparam value="#form.skillId#" cfsqltype="cf_sql_integer" list="true"> 
       ) 
    </cfquery> 



另一種方法是DELETE只爲選中/刪除技能。然後使用新添加的技能OUTER JOININSERT。其他任何東西都被認爲是不變的

<cfquery ...> 
     DELETE FROM StudentSkill 
     WHERE studentID = <cfqueryparam value="#form.studentId#" cfsqltype="cf_sql_integer"> 
     <cfif listLen(form.skillId)> 
     AND skillId NOT IN 
      (
       <cfqueryparam value="#form.skillId#" cfsqltype="cf_sql_integer" list="true"> 
      ) 
     </cfif> 
    </cfquery> 

    <cfquery ...> 
     INSERT INTO StudentSkill (studenId, skillId) 
     SELECT <cfqueryparam value="#form.studentId#" cfsqltype="cf_sql_integer"> 
       , s.skillId 
     FROM Skill s LEFT JOIN StudentSkill stu 
       ON s.skillID = stu.skillID 
       AND stu.studentID = <cfqueryparam value="#form.studentId#" cfsqltype="cf_sql_integer"> 
     WHERE s.skillId IN 
       (
       <cfqueryparam value="#form.skillId#" cfsqltype="cf_sql_integer" list="true"> 
       ) 
     AND stu.skillID IS NULL 
    </cfquery> 

注:請務必在cftransaction,使他們被視爲一個單位來包裝這兩個查詢。

+0

:謝謝你的擡頭。這是我第一次聽說cftransaction。 – vamps

+0

任何時候當你有修改數據庫的「相關查詢」時,你都想使用一個事務。它確保*所有查詢都成功或者全部失敗。所以你永遠不要把事情置於不一致的狀態。這是一篇舊文章,但第一部分使用[經典銀行轉帳示例](http://aspnet.4guysfromrolla.com/articles/072705-1.aspx)提供了一個很好的描述爲什麼需要交易。 – Leigh

0

@leigh提供了一個很好的答案,但另一種方法可能是將「選定」選項顯示爲鏈接而不是複選框。該鏈接會提示您確認刪除該選項並刷新頁面。

然後你的複選框處理將只用於添加新記錄(這聽起來像你已經在做)。這將有助於防止人們意外地檢查錯誤的框並刪除技能。