2010-12-01 2 views
13

Скажем, у меня есть следующая таблица:SQL группы лишь на строки, которые находятся в последовательности

MyTable 
--------- 
| 1 | A | 
| 2 | A | 
| 3 | A | 
| 4 | B | 
| 5 | B | 
| 6 | B | 
| 7 | A | 
| 8 | A | 
--------- 

Мне нужен SQL запрос для вывода следующих:

--------- 
| 3 | A | 
| 3 | B | 
| 2 | A | 
--------- 

В основном я делаю group by но только для строк, которые вместе находятся в последовательности. Есть идеи?

Обратите внимание, что база данных находится на сервере sql 2008. В этой теме есть сообщение, но оно использует функцию lag() оракула.

ответ

22

Это известно как проблема «островов». Используя подход Ицик Бен ГАН:

;WITH YourTable AS 
(
SELECT 1 AS N, 'A' AS C UNION ALL 
SELECT 2 AS N, 'A' AS C UNION ALL 
SELECT 3 AS N, 'A' AS C UNION ALL 
SELECT 4 AS N, 'B' AS C UNION ALL 
SELECT 5 AS N, 'B' AS C UNION ALL 
SELECT 6 AS N, 'B' AS C UNION ALL 
SELECT 7 AS N, 'A' AS C UNION ALL 
SELECT 8 AS N, 'A' AS C 
), 
    T 
    AS (SELECT N, 
       C, 
       DENSE_RANK() OVER (ORDER BY N) - 
       DENSE_RANK() OVER (PARTITION BY C ORDER BY N) AS Grp 
     FROM YourTable) 
SELECT COUNT(*), 
     C 
FROM T 
GROUP BY C, 
      Grp 
ORDER BY MIN(N) 
+1

Фантастическое решение! Это происходит в панели инструментов. – 2010-12-01 13:30:46

0

это будет работать для вас ...

SELECT 
    Total=COUNT(*), C 
FROM 
(
SELECT 
NGroup = ROW_NUMBER() OVER (ORDER BY N) - ROW_NUMBER() OVER (PARTITION BY C ORDER BY N), 
N, 
C 
FROM MyTable 
)RegroupedTable 
GROUP BY C,NGroup 
0

Просто для удовольствия, без каких-либо SQL-функции и не предполагая, что столбец ID монотонно возрастает:

WITH starters(name, minid, maxid) AS (
    SELECT 
     a.name, MIN(a.id), MAX(a.id) 
    FROM 
     mytable a RIGHT JOIN 
     mytable b ON 
      (a.name <> b.name AND a.id < b.id) 
    WHERE 
     a.id IS NOT NULL 
    GROUP BY 
     a.name 
), 
both(name, minid, maxid) AS (
    SELECT 
     name, minid, maxid 
    FROM 
     starters 
    UNION ALL 
    SELECT 
     name, MIN(id), MAX(id) 
    FROM 
     mytable 
    WHERE 
     id > (SELECT MAX(maxid) from starters) 
    GROUP BY 
     name 
) 
SELECT 
    COUNT(*), m.name, minid 
FROM 
    both INNER JOIN 
    mytable m ON 
     id BETWEEN minid AND maxid 
GROUP BY 
    m.name, minid 

Результат (игнорировать midid столбец):

(No column name) name minid 
3 A 1 
3 B 4 
2 A 7 

 Смежные вопросы

  • Нет связанных вопросов^_^