说我有下表:
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 server 2008上。此主题有一篇帖子,但是它使用了oracle的lag()函数。
答案 0 :(得分:23)
这被称为“岛屿”问题。使用Itzik Ben Gan的方法:
;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 :(得分: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
答案 2 :(得分: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