2009-12-14 121 views
0

我想使用單個查詢來更新MySQL表中的多個記錄。基本上,這是一個任務表,它爲不同日期的不同人員分配任務。當這些分配被改變並通過在線表單提交時,會有很多POST數據被提交(幾乎所有待處理的分配)。我已經寫了整理着所有這些信息,並得到我想出來的是什麼算法,但我卡上書寫的查詢,更新MySQL表:如何使用單個MySQL查詢更新表中的多個記錄?

// Find the modified records and save their information 
    $update = 0; 
    for ($n = 0; $n < $total_records; $n++) 
    { 
    if ($_POST['update'.$n] == true) 
    { 
     $updates_arr[$update] = array(intval($_POST['user_id'.$n]), intval($_POST['task'.$n]), $_POST['date'.$n]); 
     $update++; 
    } 
    } 

    if ($mysql_db = OpenDatabase()) 
    { 
    $query = "UPDATE tasks_tbl"; 
    if ($updates_arr[0]) 
    { 
     $query .= " SET task = ".$updates_arr[0][1]." WHERE user_id = ".$updates_arr[0][0]." AND date = ".$updates_arr[0][2]; 
    } 

    for ($n = 1; $n < $updates; $n++) 
    { 
     $query .= ", SET task = ".$updates_arr[$n][1]." WHERE user_id = ".$updates_arr[$n][0]." AND date = ".$updates_arr[$n][2]; 
    } 

    $result = mysql_query($query, $mysql_db); 

    if ($result) 
    { 
     $page .= "<p>Success!</p>\n\n"; 
    } 
    else 
    { 
     $page .= "<p>Error: ".mysql_error()."</p>\n\n"; 
    } 
    } 

這是生成的查詢:

UPDATE tasks_tbl 
    SET task = 1 
WHERE user_id = 16 
    AND date = 2010-05-05, 
    SET task = 1 
WHERE user_id = 17 
    AND date = 2222-02-22 

任何意見,將不勝感激。謝謝。

+1

對於真正大量的插入,可能有利於對臨時表執行批量INSERT,然後使用臨時表中的值更新目標表。 – 2009-12-14 18:32:03

+0

你爲什麼要這樣做?如果只有其中一個失敗,您將面臨不更新多個項目的風險。將個別交易陷入困境並不是更好,因此可以將它們顯示給用戶嗎? – 2009-12-14 18:34:41

+0

算法比我在這裏展示的還多。在運行查詢之前,所有數據都經過驗證,所以不應該存在無效數據可能導致查詢失敗的實例。 – 2009-12-14 18:45:36

回答

1

感謝您的建議,大家好。我結束了與多個查詢,因爲它顯然不會像我所希望的那樣簡單。

foreach ($updates_arr as $record => $data): 
     $query = "UPDATE tasks_tbl"; 
     $query .= " SET task = ".$data[1]; 
     $query .= " WHERE task_id = ".$data[0]; 
     $result = mysql_query($query, $mysql_db); 
     if (!$result) 
     { 
      break; 
     } 
     endforeach; 
+0

同樣,如果您要使用預準備語句,則不必每次通過循環重新生成查詢字符串,都不會每次通過網絡發送整個查詢時,sql服務器不必每次都解析sql,並且您將受到SQL注入的保護,而您的代碼不是。 – DGM 2009-12-15 15:31:04

-4

我不認爲這是可能的一個聲明。您將需要創建單獨的UPDATE語句:

UPDATE tasks_tbl SET task = 1 WHERE user_id = 16 AND date = 2010-05-05; 
UPDATE tasks_tbl SET task = 1 WHERE user_id = 17 AND date = 2222-02-22 

你可以將它們傳遞到請求mysql_query()作爲分隔一根弦「;」如果您將mysql設置爲接受multiple queries

似乎支持多個查詢。 你只需要通過標誌65536爲 的mysql_connect的5參數 (client_flags)

+1

首先完成句子的文檔中: 的mysql_query()發送一個唯一的查詢(**多個查詢,不支持**)當前激活的數據庫與指定link_identifier關聯的服務器上。 – 2009-12-14 18:18:51

+0

我沒有意識到唯一的更新會將任務更改爲1.我認爲只需爲每個UPDATE發佈新語句會更容易。 – 2009-12-14 18:30:23

+0

這是不可能的,因爲他澄清說,一些任務將被設置爲1,2或3 – 2009-12-14 19:05:51

5

您可以生成這樣的查詢:

UPDATE tasks_tbl SET task=1 WHERE 
    (user_id=16 AND date='2010-05-05') OR 
    (user_id=17 AND date='2010-02-22') 

有黑客避免使用(... and ...) or (... and ...)結構(串連領域, PARAMS:"concat(user_id, date) = '". $user_id. $date. "'",但他們的工作有點慢

的PHP代碼:

for ($i = 0; !empty($_POST['update'. $i]; $i++) 
    if (intval($_POST['task'.$i]) == 1) 
     $cond[] = '(user_id='. intval($_POST['user_id'. $i]). 
     ' and date=\''. mysql_real_escape_string($_POST['date'.$i]). '\')'; 

$query = 'UPDATE tasks_tbl SET task=1 WHERE '. implode(' OR ', $cond). ')'; 

編輯:我不太明白爲什麼你需要在單個查詢中做到這一點。 task可以有多少個值? 1,2,3還是更多?有了3個值,你可以使用嵌套IF(...)功能:

UPDATE tasks_tbl SET task=if('. <imploded tasks with value 1>. ', 1, if('. 
<tasks with value 2>. ', 2, if('. <tasks with 3>. ', 3, 
task))) /* leave as is otherwise */ 

或者你可以將一個簡單的循環,在我給代碼:

for ($j = 1; $j <= 3; $j++) 
    for ($i = 0; !empty($_POST['update'. $i]; $i++) 
     if (intval($_POST['task'.$i]) == 1) 
      $cond[] = '(user_id='. intval($_POST['user_id'. $i]). 
      ' and date=\''. mysql_real_escape_string($_POST['date'.$i]). '\')'; 

    mysql_query('UPDATE tasks_tbl SET task=1 WHERE '. implode(' OR ', $cond). ')'); 
+0

假設任務總是設置爲1 .. – stuartd 2009-12-14 18:15:25

+0

哎呀!謝謝,修正:) – 2009-12-14 18:19:48

0

您正在尋找這樣的:

UPDATE tasks_tbl 
    SET task = 1 
WHERE (user_id = 16 AND date = 2010-05-05) 
     OR (user_id = 17 AND date = 2222-02-22) 

或者你正試圖用不同的行將單個語句的'task'設置爲不同的值? 後者是不可能的

+0

find_in_set&elt函數是可能的。只有2級函數調用堆棧。 – 2009-12-14 18:28:28

1

我寧願使用準備好的查詢和循環的數據(如果需要在事務內)。這使得它更易於理解,這對於可維護性來說更好。

您的代碼也會產生sql injection的不安全感,這些準備好的查詢會消除。

見:與PDO preparehttp://www.php.net/manual/en/mysqli.prepare.php甚至更​​好:

+0

謝謝,但是這看起來好像需要在我的網站上重寫所有PHP - > MySQL代碼。現在,我正在考慮從mysql_connect()切換到mysql_pconnect(),這隻需要進行一些更改。不過,我一定會爲我的下一個網站記住mysqli APIs! – 2009-12-16 15:05:08

+0

代碼比我所展示的代碼多得多。我使用mysql_real_escape_string()並驗證結果是否在預期的範圍內,因此如果不是不可能的話,將任何內容都插入到查詢中是非常困難的。 – 2009-12-16 15:07:38

2

我不同意你的架構在這裏,但下面應該工作。使用您自己的風險:

UPDATE 
    Tasks_Table 
SET 
    task = 
      CASE 
       WHEN user_id = 16 AND date = 2010-05-05 THEN 1 
       WHEN user_id = 17 AND date = 2222-02-22 THEN 1 
       ... 
      END 
WHERE 
    (user_id = 16 AND date = 2010-05-05) OR 
    (user_id = 17 AND date = 2222-02-22) OR 
    ... 

在你的榜樣,你在任何情況下都有任務= 1,但與CASE語句,你可以改變它們是您所需要的每一種情況下。我會留下字符串建築給你。

+0

謝謝湯姆。我明白這是如何工作的,儘管這樣做會讓人感到難以忍受,而且還會讓人感到痛苦。 – 2009-12-14 19:27:22

+0

這看起來很有趣。常用的CASE語句,還是MySQL的一個比較模糊的特性? – 2009-12-16 14:58:05

+0

其實,我大部分都是MS SQL開發人員。CASE語句是SQL ANSI標準的一部分,所以它應該在大多數RDBMS中可用 – 2009-12-16 15:33:34

相關問題