2010-05-05 50 views
0

好吧,我想用這個CASE STATEMENT,但我迷失了這個。基本上,我需要更新大量的行,但只是在「職位」列。我需要UPDATE所有的位置值都大於位置值,該位置值以id_layout和id_layout_position爲基礎被移除到position - 1SQL:使用CASE語句一次更新1000行

OK,這裏是什麼樣的表看起來像一個PIC: alt text http://acs.graphicsmayhem.com/images/dp_positions_table.png

現在讓我們假設我刪除盤旋行,這將刪除位置= 2,給我:0,1,3,5,它應該重新定位大於2的位置值,以便它看起來像這樣:0,1,2,4,5,6和3.

好的,這是我的(注意:$ module_info ['clones'] =要刪除的克隆數組,在上表中沒有,因爲所有的id_clone值都是0 ,$ module_info ['id']是我們正在移除的id_module值):

// Get rid of id_clone = 0, because we can't use them. 
$module_info['clones'] = array_values(array_filter($module_info['clones'])); 

// Selecting the positions. 
if (isset($module_info['clones'][0])) 
    $query = 'id_module = {int:id_module} || id_clone IN ({array_int:id_clones})'; 
else 
    $query = 'id_module = {int:id_module}'; 

$request = $smcFunc['db_query']('', ' 
    SELECT 
     id_position, id_layout_position, id_layout, position 
    FROM {db_prefix}dp_module_positions 
    WHERE ' . $query, 
    array(
     'zero' => 0, 
     'id_module' => $module_info['id'], 
     'id_clones' => $module_info['clones'],   
    ) 
); 

while ($row = $smcFunc['db_fetch_assoc']($request)) 
{ 
    $module_info['position'][$row['id_layout']]['pos' . $row['id_position'] . $row['position'] . '_' . $row['id_layout_position']] = $row['position']; 
    $module_info['id_positions'][] = $row['id_position']; 
} 

$smcFunc['db_free_result']($request); 

// Remove all module and clone positions from the layout! 
$smcFunc['db_query']('', ' 
    DELETE FROM {db_prefix}dp_module_positions 
    WHERE id_position IN ({array_int:id_positions})', 
    array(
     'id_positions' => $module_info['id_positions'], 
    ) 
); 

foreach($module_info['position'] as $id_layout => $id_layout_pos) 
{ 
    foreach($id_layout_pos as $key => $position_val) 
    { 
     $lPos = explode('_', $key); 
     $lPosId = (int) $lPos[1]; 

     $smcFunc['db_query']('', ' 
      UPDATE {db_prefix}dp_module_positions 
      SET 
       position = position - 1 
      WHERE position > {int:position} AND id_layout = {int:id_layout} AND id_layout_position = {int:id_layout_position}', 
      array(
       'id_layout' => (int) $id_layout, 
       'position' => (int) $position_val, 
       'id_layout_position' => $lPosId, 
      ) 
     ); 
    } 
} 

NEW QUESTION: 這裏還有得是某種方式在這個UPDATE現在使用CASE語句。例如,我現在需要將所有職位更新到位置-1,每個id_layout和每個id_layout_position基礎。但只有位置大於id_layout和id_layout_position值的當前位置的位置。

有沒有辦法做到這一點,而不使用FOREACH LOOP

+1

你的問題是很難理解...... – 2010-05-05 10:54:46

+0

好了,問題是,我該如何使用在第一個代碼示例一個'CASE statement',這樣我可以更新所有[0] - 找到的總行數是否在'position'列中的行中,具有'id_layout'值和'id_layout_position'值,並且該表中的所有不同'id_layout'值都會繼續執行此操作? – SoLoGHoST 2010-05-05 10:58:53

+1

你仍然在尋求你的解決方案:說明你實際上想要達到的目標,而不是你認爲你應該怎麼做? – 2010-05-05 11:01:35

回答

2

在刪除一行之前,可以獲取它的位置並減少位置較高的所有行的位置。

僞代碼:

function deleteRow($id){ 
    DB::startTransaction() 
    try{ 
    $infos = DB::getData('SELECT position FROM db_positions WHERE id_position = :ID', array(':ID' => $id)); 
    if(empty($infos)){ 
     throw("useless ID"); 
    } 
    DB::query('DELETE FROM db_positions WHERE id_position = :ID', array(':ID' => $id)); 
    DB::query('UPDATE db_positions SET position = position - 1 WHERE position > :position', array(':position' => $infos['position']); 
    DB::commit(); 
    } 
    catch(Exception $e){ 
    DB::rollBack(); 
    } 
} 
+0

現在這是一個想法...嗯,謝謝:) – SoLoGHoST 2010-05-05 12:58:34

+0

好的,這個代碼有問題,你刪除了id位置,而更新是從位置列中獲取所有信息而不是信息從不存在的id_position值...嗯 – SoLoGHoST 2010-05-05 13:38:28

+0

而比如果你嘗試更新它,你會遇到另一個問題.... OMG,如何做到這一點... – SoLoGHoST 2010-05-05 13:40:17

1

要不間斷列的更新,你可以使用以下命令:

SET @reset := 0; 
UPDATE dp_positions 
SET 
    positions = 
    CASE   
    WHEN id_layout_position > @reset THEN 
     IF(@pos:=0,NULL, @reset:=id_layout_position)   
    ELSE @pos := @pos + 1  
    END - 1 
ORDER BY id_layout_position, position; 

注:@reset應設置爲id_layout_position的最小值,假設你是重新啓動在id_layout_position變化櫃檯上,如果是比較複雜的WHEN條件將需要改變,你可能需要更多的變量來保存前一行的值。
此外,IF是一個黑客,只要您將@pos設置爲0而不是其他初始值,我就不知道如何強制mysql來評估兩個表達式(任何人,是那裏有什麼優雅的東西?)

上面已經過測試,但有不同的列/表名(重新輸入錯誤可能)。

編輯:我的測試是不太好,上面有錯誤,而且也似乎OP需要繞過框架的安全性,所以這裏的修正和存儲過程版本

使用phpmyadmin或MySQL命令行執行

delimiter // 
CREATE PROCEDURE `renumerate`() 
BEGIN 
SET @pos := -1; 
SET @reset := (SELECT MIN(id_layout_position) FROM dp_position); 
UPDATE 
    dp_positions 
SET 
    position = 
    CASE   
     WHEN b > @reset THEN 
     IF(@reset:=id_layout_position, @pos:=0, @pos:=0)   
     ELSE @pos := @pos + 1  
    END 
ORDER BY id_layout_position, position; 
END // 
delimiter ; 

(如果你使用phpMyAdmin不使用分隔符聲明,但直接在界面中指定分隔符爲//)。 當調用存儲過程執行正常的SQL

$smcFunc['db_query']('', 'CALL renumerate()'); 

希望我的測試是更好的這段時間。

+0

你好,我不確定SMF會允許我在查詢中執行':=',並且我不能在不使用$ smcFunc類的情況下訪問數據庫,請看看SMF如何在我的問題的第二個代碼塊中進行操作,也許您可以將相同的風格納入您的回答?我真的很感激它。謝謝:) – SoLoGHoST 2010-05-05 12:20:49

+0

另外,在您的查詢中,我沒有看到您設置位置列值的位置? 'dp_positions'應該是'position'列嗎?但是表名又怎麼樣呢?我看到你裏面有'two',而不是表名... – SoLoGHoST 2010-05-05 12:28:03

+0

嗯,檢查SMF的深度並不是真的很癢。嘗試將上面的SQL作爲2條語句運行,它可能對過敏性更強;然後到:= – Unreason 2010-05-05 12:28:56