2016-11-16 21 views
0

我有一個食品項目表。他們有一個「職位」字段,表示他們應該在列表中顯示的順序(listID是他們所在的列表,我們不想重新排列另一個列表中的項目)。基於單個記錄更改的SQL對多個記錄進行更改使用SQL

+--id--+--listID--+---name---+--position--+ 
| 1 |  1 | cheese |  0  | 
| 2 |  1 | chips |  1  | 
| 3 |  1 | bacon |  2  | 
| 4 |  1 | apples |  3  | 
| 5 |  1 | pears |  4  | 
| 6 |  1 | pie  |  5  | 
| 7 |  2 | carrots |  0  | 
| 8,9+ | 3,4+ | ...  |  ... | 
+------+----------+----------+------------+ 

我希望能夠說「芯片之前將梨」,這包括設置梨的位置位置1,然後遞增1。其間的所有立場,使我得到的表看起來像這樣...

+--id--+--listID--+---name---+--position--+ 
| 1 |  1 | cheese |  0  | 
| 2 |  1 | chips |  2  | 
| 3 |  1 | bacon |  3  | 
| 4 |  1 | apples |  4  | 
| 5 |  1 | pears |  1  | 
| 6 |  1 | pie  |  5  | 
| 7 |  2 | carrots |  0  | 
| 8,9+ | 3,4+ | ...  |  ... | 
+------+----------+----------+------------+ 

讓所有我需要做的是SELECT name FROM mytable WHERE listID = 1 ORDER BY position,我會得到我的所有食品按照正確的順序。

是否可以用單個查詢來做到這一點?請記住,記錄可能在列表中向上或向下移動,並且該表包含多個列表的記錄,所以我們需要隔離listID。

我對SQL的知識相當有限,所以現在我知道要做到這一點的唯一方法是SELECT id, position FROM mytable WHERE listID = 1 AND position BETWEEN 1 AND 5,然後我可以使用Javascript(node.js)將位置5更改爲1,並將所有其他+1加1。然後更新我剛更改的所有記錄。

這只是我每次試圖閱讀SQL的東西,每個人都會說避免多個查詢,並避免做syncronous編碼和類似的東西。

謝謝

+0

你想要什麼結果.. –

+0

@reds讓我的表看起來像從我的問題,第二個例子,當我想之前移動「梨」 「芯片」 –

+0

你想讓梨成爲你的第二排記錄?你是這個意思嗎? –

回答

1

這需要一個複雜的查詢來更新很多記錄。但是對數據的小改動可以改變事情,以便通過只修改一條記錄的簡單查詢來實現。

UPDATE my_table set position = position*10; 

在過去,很多系統上的BASIC編程語言都有行號,它鼓勵使用spagetti代碼。很多人寫了GOTO line_number而不是功能。如果您按順序編號行並且必須添加或刪除幾行,則會出現真正的麻煩。人們如何繞過它?通過增加10行!這就是我們在這裏所做的。

所以你想讓梨成爲第二個項目?

UPDATE my_table set position = 15 WHERE listId=1 AND name = 'Pears' 

擔心最終的項目之間的差距將消失後,多次重新排序?沒有恐懼只是做

UPDATE my_table set position = position*10; 

時不時。

+0

這個答案很聰明,幾乎可以回答我的問題。但是如果我現在嘗試在梨之前移動一些東西呢?有沒有簡單的方法來設置位置= 12.5或其他?我覺得這開始變得同樣複雜。 –

+0

你不需要進入小數點。您可以將其設置爲12.仍然只需要一個查詢(藉助聯接)進行更新。 – e4c5

+0

你能告訴我這樣做的查詢嗎?是否需要檢查位置15是否先存在?然後是12,然後是11,我怎麼知道何時再次設置位置* 10? –

0

我主要是想通了我的問題。所以我決定在這裏提供一個答案,任何人都會發現它有幫助。 我可以在SQL中使用CASE語句。另外通過使用Javascript預先構建我的SQL查詢,我可以更改多個記錄。

這建立我的SQL查詢:

var sql; 
var incrementDirection = (startPos > endPos)? 1 : -1; 
sql = "UPDATE mytable SET position = CASE WHEN position = "+startPos+" THEN "+endPos; 
for(var i=endPos; i!=startPos; i+=incrementDirection){ 
    sql += " WHEN position = "+i+" THEN "+(i+incrementDirection); 
} 
sql += " ELSE position END WHERE listID = "+listID; 

如果我想芯片之前梨移動到。我可以設置:

startPos = 4; 
endPos = 1; 
listID = 1; 

我的代碼將產生一個類似一條SQL語句:

UPDATE mytable 
SET position = CASE 
    WHEN position = 4 THEN 1 
    WHEN position = 1 THEN 2 
    WHEN position = 2 THEN 3 
    WHEN position = 3 THEN 4 
    ELSE position 
END 
WHERE listID = 1 

我運行的代碼和我的決賽桌的樣子:

+--id--+--listID--+---name---+--position--+ 
| 1 |  1 | cheese |  0  | 
| 2 |  1 | chips |  2  | 
| 3 |  1 | bacon |  3  | 
| 4 |  1 | apples |  4  | 
| 5 |  1 | pears |  1  | 
| 6 |  1 | pie  |  5  | 
| 7 |  2 | carrots |  0  | 
| 8,9+ | 3,4+ | ...  |  ... | 
+------+----------+----------+------------+ 

之後,我所要做的就是運行SELECT name FROM mytable WHERE listID = 1 ORDER BY position,輸出如下:

cheese 
pears 
chips 
bacon 
apples 
pie 
1

我不認爲這可以方便地在少於兩個查詢中完成,這是可以的,應儘可能少的查詢,但不會有任何代價。這兩個查詢會是這樣(根據你自己寫的)

UPDATE mytable SET position = 1 WHERE listID = 1 AND name = 'pears'; 
UPDATE mytable SET position = position + 1 WHERE listID = 1 AND position BETWEEN 2 AND 4; 
+0

我喜歡這個。我提出的解決方案比較簡單。你知道是否有任何優點/缺點建立一個像我的一個更復雜的SQL,有像你這樣的2個更簡單的查詢? –

+1

我更喜歡它的主要原因是清晰度,這意味着對未來更好的可維護性。我並不完全瞭解MySQL內部,但我懷疑它可能會比CASE的解決方案更好地執行,因爲像UPDATE這樣的標準操作更關注並因此得到優化。如果你沒有類似數百萬條記錄的話,這可能是沒有意義的。 – comodoro