2013-08-30 16 views
5

Mam tabeli jakJak przeliczyć na pole GRUPY

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

Gdzie (f1,f2) jest PK i FK jest kluczem obcym. Nie ma zbyt wielu wartości dla fk, około 20. f2 nigdy nie jest większe niż 3. Istnieje jednak wiele par (f1,f2). (f1,fk) to UNIQUE.

Teraz powiedzmy, że mapujemy 100 i 200 na A, 300 i 400 na B, 500 na C - to odwzorowanie jest podane. Chcielibyśmy, aby (f1_new,fk_mapped) pozostało UNIQUE. Jest to jak dotąd rozwiązany grubsza przez

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 

Teraz problemem jest to, że musimy zachować wartości f2 0, 1, 2 w odwzorowanym tabeli, więc jest to pożądany rezultat:

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

Naprawdę chciałbym zachować to w MySQL.

+1

Jestem zdezorientowany - mówisz, że chcesz, aby wszystkie trzy wartości 'f2' w odwzorowanym stole, ale pożądany rezultat ty show nie ma przykładów gdzie 'f2 == 2'? – Air

+1

Chce przypisać nowe wartości 'f2', więc są przechowywane w 0, 1, 2, ... porządkując określoną wartość' f1'. Jest to kolumna na jeden stopień f1. – Barmar

+0

Ah. Rozumiem. Zgaduję, że czwarty wiersz w pierwszej przykładowej tabeli powinien mieć "f2 == 3", wtedy. Zwłaszcza jeśli '(f1, f2)' jest kluczem podstawowym. – Air

Odpowiedz

3

myślę, że to powinno wystarczyć:

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

Wierzę, że powyższe jest wspaniałe, ale "nie do przewidzenia", nie możesz wiedzieć, czy @ prev_f1: = najpierw strzela. Ale '@ f2: = if (f1_new = @ prev_f1, @ f2 + 1, 0) + LEAST (0, @ prev_f1: = f1_new)' powinno działać, ponieważ '+' jest od lewej do prawej. Pomysł z [Jak zoptymalizować dane rangowe w MySQL] (http://www.oreillynet.com/pub/a/mysql/2007/03/01/optimize-mysql-rank-data.html) – chx

+1

Również za [instrukcja ] (http://dev.mysql.com/doc/refman/5.0/en/select.html): Jeśli używasz GROUP BY, wiersze wyjściowe są sortowane zgodnie z kolumnami GROUP BY, tak jakbyś miał ORDER BY dla te same kolumny. – chx

+0

@chx Widziałem i używałem warianty tego wiele razy. Chociaż może nie być to gwarantowane, w praktyce myślę, że zawsze działa od lewej do prawej. – Barmar