2013-08-25 120 views
2

我試圖回答另一個SO question,並突然遇到以下問題。積分應分配給每個班級的最高3分(mrk)組(grp)(sec)。得分最高的隊伍得到5分,排名第二的得分爲3分,排在第三的得分只有1分。對於所有其他pts應設置爲null如何在UPDATE語句中使用用戶定義的變量?

| ID | SEC | GRP | MRK | PTS | 
|----|-----|-----|-----|--------| 
| 1 | cl2 | ge | 32 | (null) | 
| 2 | cl1 | gb | 22 | (null) | 
| 3 | cl1 | gd | 22 | (null) | 
| 4 | cl1 | ge | 18 | (null) | 
| 5 | cl2 | ga | 26 | (null) | 
| 6 | cl1 | ga | 55 | (null) | 
| 7 | cl2 | gb | 66 | (null) | 
| 8 | cl2 | gc | 15 | (null) | 
| 9 | cl1 | gc | 12 | (null) | 
| 10 | cl2 | gf | 5 | (null) | 
| 11 | cl2 | ge | 66 | (null) | 

我選擇了與用戶定義的變量來工作,因爲他們提供了關於分配方案最大的靈活性,並很快想出了以下解決方案:

說明的 NULLIF(@i:=5,(@s:=sec)=(@m:=mrk))
SELECT id,sec,grp,mrk, 
CASE WHEN @s=sec THEN   -- whenever there is a new class ... 
CASE WHEN @m=mrk THEN @i ELSE -- issue the same points for 
           -- identical scorers, otherwise ... 
    CASE WHEN IF(@m:=mrk,@i,@i)>2 THEN @i:[email protected] -- store mrk in @mrk and 
           -- while @i>2 return points: 3 or 1 ... 
           ELSE @i:=null -- no points for the rest 
    END 
END 
ELSE NULLIF(@i:=5,(@s:=sec)=(@m:=mrk)) -- store sec in @s and mrk in @m 
             -- and return points: 5 
END pts 
FROM tbl ORDER BY sec,mrk desc 

的表達式@s:=sec@m:=mrk都被評估,然後通過=比較它們的值。結果可以是0(false)或1(true),但肯定不等於5,這是NULLIF函數的另一個參數,因此最終只返回第一個參數(5)。我選擇了這個構造來完成這兩個變量賦值而不返回任何內容。好吧,也許不是最直接的解決方案;-),但我確實注意爲每個正在處理的記錄只定義一個變量一次,因爲「涉及用戶變量的表達式的評估順序是不確定的「mysql manual。該select確實給了我想要的

結果:

| ID | SEC | GRP | MRK | PTS | 
|----|-----|-----|-----|--------| 
| 6 | cl1 | ga | 55 |  5 | 
| 2 | cl1 | gb | 22 |  3 | 
| 3 | cl1 | gd | 22 |  3 | 
| 4 | cl1 | ge | 18 |  1 | 
| 9 | cl1 | gc | 12 | (null) | 
| 7 | cl2 | gb | 66 |  5 | 
| 11 | cl2 | ge | 66 |  5 | 
| 1 | cl2 | ge | 32 |  3 | 
| 5 | cl2 | ga | 26 |  1 | 
| 8 | cl2 | gc | 15 | (null) | 
| 10 | cl2 | gf | 5 | (null) | 

現在,我的問題是:

我怎樣寫沿,將上面的計算結果存儲在同一行的UPDATE聲明列pts

我嘗試到目前爲止都失敗了:

UPDATE tbl SET pts= 
CASE WHEN @s=sec THEN 
CASE WHEN @m=mrk THEN @i ELSE 
    CASE WHEN IF(@m:=mrk,@i,@i)>2 THEN @i:[email protected] 
           ELSE @i:=null 
    END 
END 
ELSE NULLIF(@i:=5,(@s:=sec)=(@m:=mrk)) 
END 
ORDER BY sec,mrk desc 

結果:

| ID | SEC | GRP | MRK | PTS | 
|----|-----|-----|-----|-----| 
| 6 | cl1 | ga | 55 | 5 | 
| 2 | cl1 | gb | 22 | 5 | 
| 3 | cl1 | gd | 22 | 5 | 
| 4 | cl1 | ge | 18 | 5 | 
| 9 | cl1 | gc | 12 | 5 | 
| 7 | cl2 | gb | 66 | 5 | 
| 11 | cl2 | ge | 66 | 5 | 
| 1 | cl2 | ge | 32 | 5 | 
| 5 | cl2 | ga | 26 | 5 | 
| 8 | cl2 | gc | 15 | 5 | 
| 10 | cl2 | gf | 5 | 5 | 

爲什麼更新語句只獲得PTS單一值(5)?!?

您可以在我的SQLfiddle中找到所有數據和SQL語句。

+0

你希望的更新結果。 –

+0

@echo_Me我希望的更新結果列在我的帖子下的「選擇的確給了我想要的結果:」。僅供參考:我也嘗試將'SELECT'輸出插入到(臨時)表格中 - >與我的帖子底部顯示的結果相同:-( – cars10m

回答

1

我試圖調試這種情況。
我已經添加了6分新列到tbl表:B_S,B_M,b_i和A_S,A_M,A_I
B_ * - 「之前」,A_ *手段 - 手段 「後」,
和我修改查詢到:

UPDATE tbl SET 
    b_s = @s, 
    b_m = @m, 
    b_i = @i, 
pts= 
CASE WHEN @s=sec THEN 
CASE WHEN @m=mrk THEN @i ELSE 
    CASE WHEN IF(@m:=mrk,@i,@i)>2 THEN @i:[email protected] 
           ELSE @i:=null 
    END 
END 
ELSE NULLIF(@i:=5,(@s:=sec)=(@m:=mrk)) 
END, 
a_s = @s, 
a_m = @m, 
a_i = @i 
ORDER BY sec,mrk desc 

我的意圖是記錄表達式評估前後的變量值。

這很奇怪 - 我不知道爲什麼,但看起來如果在執行更新之前將值分配給所有變量,那麼更新將按預期工作。
比較這兩種演示:

1 - 錯:http://sqlfiddle.com/#!2/2db3e4/1
2 - 精細:http://sqlfiddle.com/#!2/37ff5/1

唯一的區別是更新之前的代碼段:

set @i='alamakota'; 
set @m='alamakota'; 
set @s='alamakota'; 

某種類型的「魔術字符串「:) :)

+0

有趣的觀察和前後列的好主意!我會玩弄小提琴也是...... – cars10m

+0

奇怪的是,它是否被記錄在任何地方?!?是否有可能在單個語句中寫入所有內容(之前沒有'SET ...'命令)? – cars10m

+0

嗯,可能*是*答案是:**你想在'UPDATE'中使用的變量必須在聲明之前使用某種'SET'聲明*(它們也被綁定到一個char型)。**('SET @s: = @ m:= @ i:='a''也可以工作。)儘管我在MySQL手冊的UPDATE部分下的帖子中找到了一個用於切換列的更簡單的例子:'UPDATE tbl SET sec =(@ v := sec),sec = grp,grp = @ v;'。(這個語句在沒有*之前的'SET'的情況下工作*)。然而,在這個例子中,變量'@ v'從未被測試過*值檢查)在一個'CASE'構造。 – cars10m

相關問題