2013-08-30 41 views
5

現場有像我如何重新計算GROUP

f1|f2|fk 
1 | 0|100 
1 | 1|200 
1 | 2|300 
1 | 3|400 
2 | 0|300 
2 | 1|400 
2 | 2|500 

(f1,f2)表是PK和FK是一個外鍵。 fk的值並不是很多,大約爲20.f2從不超過3.但是,有很多(f1,f2)對。 (f1,fk)UNIQUE

現在,假設我們正在映射100和200至A,300和400到B,500到C - 在給定的這種映射。我們想(f1_new,fk_mapped)UNIQUE。這是迄今爲止

INSERT INTO mapped (f1_new,f2_new,fk_new) 
SELECT f1, MIN(f2), CASE fk WHEN 100 THEN A WHEN 200 THEN A END AS fk 
FROM origin 
GROUP BY f1, fk 

大致解決現在的問題是,我們需要保持F2值0,1,2中的映射表,所以這是期望的結果:

f1_new|f2_new|fk_mapped 
1  | 0 |A 
1  | 1 |B 
2  | 0 |B 
2  | 1 |C 

我真的想保持在MySQL內。

+1

我很困惑 - 你說你想保持f2'的'所有三個值中的映射表,但你想要的結果show沒有'f2 == 2'的實例嗎? – Air

+1

他想分配'f2'的新值,所以它們保存在0,1,2,...中,爲'f1'的特定值排序。這是一個按f1排名的專欄。 – Barmar

+0

啊。得到它了。我猜測第一個示例表中的第四行應該有'f2 == 3',然後。特別是如果'(f1,f2)'是主鍵。 – Air

回答

3

我想這應該這樣做:

INSERT INTO mapped (f1_new, f2_new, fk_new) 
SELECT f1_new, f2_new, fk_new from (
    SELECT f1_new, @f2 := if(f1_new = @prev_f1, @f2+1, 0) f2_new, fk_new, @prev_f1 := f1_new 
    FROM (select f1 AS f1_new, CASE WHEN fk IN (100, 200) THEN 'A' 
            WHEN fk in (300, 400) THEN 'B' 
            WHEN fk = 500 THEN 'C' 
           END AS fk_new 
      FROM origin 
      GROUP BY f1_new, fk_new 
      ORDER BY f1_new, fk_new) new, 
     (SELECT @f2 := NULL, @prev_f1 := NULL) vars 
    ) x 

FIDDLE

+0

我相信以上是偉大的,但「不可預測」,你不知道@ prev_f1:=先發射。但'@ F2:= IF(f1_new = @ prev_f1,@ F2 + 1,0)+ LEAST(0,@ prev_f1:= f1_new)'應該工作,因爲'+'是左到右。從[在MySQL如何優化排名數據](http://www.oreillynet.com/pub/a/mysql/2007/03/01/optimize-mysql-rank-data.html) – chx

+1

此外,每[手冊想法(http://dev.mysql.com/doc/refman/5.0/en/select.html):如果您使用GROUP BY,輸出行根據GROUP BY列,如果你有一個ORDER BY的排序相同的列。 – chx

+0

@chx我已經看過並使用了很多次的變體。儘管可能無法保證,但實際上我認爲它總是從左到右。 – Barmar