2009-10-22 17 views
6

Jak mogę zwrócić to, co faktycznie byłoby "przylegającym" GROUP BY w MySQL. Innymi słowy GRUPA BY, która respektuje kolejność zestawów rekordów?Jak mogę utworzyć grupę ciągłą w MySQL?

Przykładowo SELECT MIN(col1), col2, COUNT(*) FROM table GROUP BY col2 ORDER BY col1 z poniższej tabeli, w której kol1 jest unikalny uporządkowane index:

 
1 a 
2 a 
3 b 
4 b 
5 a 
6 a

zwrócone:

1 a 4 
3 b 2

ale trzeba zwrócić następujące:

1 a 2 
3 b 2 
5 a 2

Odpowiedz

5

Zastosowanie:

SELECT MIN(t.id) 'mi', 
      t.val, 
      COUNT(*) 
    FROM (SELECT x.id, 
       x.val, 
       CASE 
        WHEN xt.val IS NULL OR xt.val != x.val THEN 
        @rownum := @rownum+1 
        ELSE 
        @rownum 
       END AS grp 
      FROM TABLE x 
      JOIN (SELECT @rownum := 0) r 
     LEFT JOIN (SELECT t.id +1 'id', 
         t.val 
        FROM TABLE t) xt ON xt.id = x.id) t 
GROUP BY t.val, t.grp 
ORDER BY mi 

Kluczem było stworzenie sztucznej wartości, który pozwoliłby na grupy.

Wcześniej poprawione Guffa za odpowiedź:

SELECT t.id, t.val 
    FROM TABLE t 
LEFT JOIN TABLE t2 on t2.id + 1 = t.id 
    WHERE t2.val IS NULL 
     OR t.val <> t2.val 
+0

transpose +1 na prawą stronę, a następnie wprowadź -1. więc nie spowoduje to skanowania tabeli. mysql nie może mieć indeksu o wyrażeniu –

+0

To wszystko! Wielkie dzięki! – Kuyenda

+0

Jeśli użyjesz 'CASE WHEN xt.id IS NULL OR x.val = x.val', to SQL nie złamie się, gdy val jest celowo NULL, ale nadal przechwytuje pierwsze porównanie z offsetem. – Kuyenda

1

Jeśli liczby w kolumnie 1 są ciągłe, możesz to zrobić:

select x.col1, x.col2 
from table x 
left join table y on x.col1 = y.col1 + 1 
where x.col2 <> isnull(y.col2, '') 

To działa tak:

-x- -y- out 
1 a - - 1 a 
2 a 1 a 
3 b 2 a 3 b 
4 b 3 b 
5 a 4 b 5 a 
6 a 5 a 
+0

jak jest, że będzie tylko powrotu 2, 4b - Zobacz moją odpowiedź dla korekt. –

+0

@rexem: Tak, poprawiono wyrównanie, a porównanie z zerą wymagało poprawienia. – Guffa

0

To nie zadziała:

SELECT min_col1 = MIN(col1), col2 
FROM table 
GROUP BY col2 
ORDER BY min_col1 

może ten?

SELECT min_col1, col2 
FROM (SELECT min_col1 = MIN(col1), col2 
     FROM table 
     GROUP BY col2) x 
ORDER BY min_col1 
+0

GROUP BY ignoruje zamówienie. Skutecznie potrzebuję grupy według funkcjonalności, która respektuje kolejność zestawu rekordów. – Kuyenda

+0

[Pierwsze zapytanie działa na serwerze SQL.] –

1

samej logiki jak rexem, ale działa na wszelkich RDBMS okienkowych-stanie (nie będzie działać na MySQL jeszcze):

CREATE TABLE tbl 
(
id INT, 
val VARCHAR(1) 
); 

INSERT INTO tbl(id,val) 
VALUES(1,'a'),(2,'a'),(3,'a'),(4,'a'),(5,'b'),(6,'b'),(7,'a'),(8,'a'),(9,'a'); 

źródło:

1 a 
2 a 
3 a 
4 a 
5 b 
6 b 
7 a 
8 a 
9 a 

Zapytanie w stylu okna: (działa na windowing-c apable RDBMS):

WITH grouped_result AS 
(
    SELECT x.id, x.val, 
     COUNT(CASE WHEN y.val IS NULL OR y.val <> x.val THEN 1 END) 
     OVER (ORDER BY x.id) AS grp 
    FROM tbl x LEFT JOIN tbl y ON y.id + 1 = x.id 
) 

SELECT MIN(id) mi, val, COUNT(*) 
FROM grouped_result 
GROUP BY val, grp 
ORDER BY mi 

wyjściowa:

1 a 4 
5 b 2 
7 a 3 

BTW, jest to wynikiem grouped_result bez GROUP BY:

1 a 1 
2 a 1 
3 a 1 
4 a 1 
5 b 2 
6 b 2 
7 a 3 
8 a 3 
9 a 3 

Czuje się dobrze przepisywanie mysqlism-maila do ANSI -konfigurowanie jednego :-) Na razie, podczas gdy mysql nie ma jeszcze możliwości tworzenia okien, odpowiedź rexemu jest najlepsza. Rexem, to dobra technika mysql (JOIN (SELECT @rownum: = 0)) tam, a afaik MSSQL i PostgreSQL nie obsługują domyślnie zadeklarowanej zmiennej, kudos! :-)

0

Here jest dłuższym opisem zasadniczo tego samego (jak sądzę) rozwiązania oferowanego przez omg-kuce - "stwórz sztuczną wartość, która pozwoliłaby na grupowanie".

0

Wiem, że to pytanie zostało zadane dwa i pół roku temu (i nie spodziewam się żadnej propozycji), ale właśnie napotkałem ten sam problem, z tym że "tabela" była już bardzo skomplikowanym komunikatem SQL, więc nie mogłem przystąpić każdy bez kopiowaniem wklejanie go

Więc miałem inny pomysł: zamów przez col2 i odjąć bieżący numer wiersza do wartości col1

SELECT *, col1-(@rownum:[email protected]+1) FROM (SELECT * FROM table JOIN (SELECT @rownum:=0) AS i ORDER BY col2) AS t 

co daje rezultat takiego:

1 a 0 
2 a 0 
5 a 2 
6 a 2 
3 b -2 
4 b -2 

Teraz wystarczy do grupy przez wartość ostatniej kolumnie

SELECT MIN(col1) AS mi, col2, COUNT(*) FROM 
    (SELECT *, col1-(@rownum:[email protected]+1) AS grp FROM (SELECT * FROM table JOIN (SELECT @rownum:=0) AS i ORDER BY col2) AS t) AS x 
GROUP BY grp ORDER BY mi 
Powiązane problemy