我目前有这张表:
╔════╦══════════╦════════════╗
║ ID ║ PartType ║ PartStatus ║
╠════╬══════════╬════════════╣
║ 1 ║ A ║ OK ║
║ 2 ║ A ║ BAD ║
║ 3 ║ A ║ OK ║
║ 4 ║ A ║ OK ║
║ 5 ║ B ║ OK ║
║ 6 ║ B ║ BAD ║
║ 7 ║ A ║ OK ║
╚════╩══════════╩════════════╝
我希望能够通过PartType UNTIL对它们进行分组。所以它应该像这样输出:
╔══════════╦══════════╗
║ PartType ║ Quantity ║
╠══════════╬══════════╣
║ A ║ 4 ║
║ B ║ 2 ║
║ A ║ 1 ║
╚══════════╩══════════╝
答案 0 :(得分:3)
你也可以使用row_number进行这种分组,由于你不需要进行任何连接,因此使用更大的数据集可以更好地工作。这也应该返回预期的结果:
select PartType, count(*)
from (
select *,
row_number() over (order by ID) as RN1,
row_number() over (partition by PartType order by ID) as RN2
from yourtable
) X
group by PartType, RN1 - RN2
order by min(ID)
这里的技巧是第一行编号对所有行进行编号,第二行按PartType对它们进行分区。因此,当RN1和RN2之间的差异发生变化时,它就是一种不同的类型。
答案 1 :(得分:3)
如果您使用的是SQL Server 2012或更高版本,那么值得一提的另一种方法是利用2012年提供的窗口函数。
您可以使用LAG函数检测数据集中何时发生状态更改,并且可以使用SUM OVER子句为数据生成分组ID。以下示例演示了如何完成此操作。
DECLARE @parts TABLE
(
ID int IDENTITY(1,1) NOT NULL PRIMARY KEY,
PartType nvarchar(1) NOT NULL,
PartStatus nvarchar(50) NOT NULL
)
INSERT INTO @parts (PartType,PartStatus)
VALUES
(N'A',N'OK'),
(N'A',N'BAD'),
(N'A',N'OK'),
(N'A',N'OK'),
(N'B',N'OK'),
(N'B',N'BAD'),
(N'A',N'OK');
WITH CTE_PartTypeWithStateChange
AS
(
SELECT ID
,PartType
,PartStatus
,(
CASE
WHEN (LAG(PartType, 1, '') OVER (ORDER BY ID) <> PartType) THEN 1
ELSE 0
END
) HasStateChanged
FROM @parts
)
,
CTE_PartTypeWithGroupID
AS
(
SELECT ID
,PartType
,PartStatus
,SUM(HasStateChanged) OVER (ORDER BY ID ROWS UNBOUNDED PRECEDING) AS GroupID
FROM CTE_PartTypeWithStateChange
)
SELECT MAX(PartType) AS PartType
,COUNT(PartType) AS Quantity
FROM CTE_PartTypeWithGroupID
GROUP BY GroupID
虽然代码更多,但这种方法确实可以减少源表上的读取次数,因为您没有执行任何自联接。此方法还减少了查询必须执行的排序数,这应该可以提高较大数据集的性能。
答案 2 :(得分:1)
使用您的样本输入考虑此测试表:
DECLARE @test TABLE
(
ID int IDENTITY(1,1) NOT NULL,
PartType nvarchar(1) NOT NULL,
PartStatus nvarchar(50) NOT NULL
)
INSERT INTO @test (PartType,PartStatus)
VALUES
(N'A',N'OK'),
(N'A',N'BAD'),
(N'A',N'OK'),
(N'A',N'OK'),
(N'B',N'OK'),
(N'B',N'BAD'),
(N'A',N'OK');
我在PartType更改时使用了apply来获取下一个ID:
SELECT t.PartType
, COUNT(t.ID) AS Quantity
FROM @test t
INNER JOIN (
SELECT MAX(ID) + 1 axID
FROM @test
) m
ON 1 = 1
OUTER APPLY (
SELECT TOP 1 s.ID as extID
FROM @test s
WHERE s.ID > t.ID
AND s.PartType <> t.PartType
ORDER BY s.ID ASC
) n
GROUP BY t.PartType, ISNULL(n.extID,m.axID)
ORDER BY ISNULL(n.extID,m.axID)
答案 3 :(得分:0)
使用递归CTE
尝试这个简单的脚本WITH cte_test as(
select *,1 as recno from @Table1 where id=1
union all
select t.*,(case when c.PartType = t.PartType then recno else recno+1 end )
from @Table1 t inner join cte_test c on t.ID = c.ID+1
)
select PartType,count(*) from cte_test
group by recno,PartType
order by recno
option (maxrecursion 0)