gpt4 book ai didi

sql - 查找表中值的最长序列

转载 作者:行者123 更新时间:2023-12-01 05:46:23 24 4
gpt4 key购买 nike

这是一个 SQL 问题,我认为这很困难 - 我不确定是否有可能在一个简单的 SQL 语句或存储过程中实现:

我想在表的列中找到相同(已知)数字的最长序列的数字:

例子:

TABLE: 
DATE SALEDITEMS
1/1/09 4
1/2/09 3
1/3/09 3
1/4/09 4
1/5/09 3

调用 sp/sentence 为 4 将得到 1 调用 sp/sentence 为 3 将得到 2
因为在第 3 行中有 2 次。

我正在运行 SQL Server 2008。

最佳答案

更新:我生成了一百万行随机数据,并放弃了递归 CTE 解决方案,因为它的查询计划没有很好地利用优化器中的索引。

但是我最初发布的非递归解决方案效果很好,只要在(SALEDITEMS,[DATE])上有一个额外的非聚集索引。这是有道理的,因为查询需要双向过滤(按日期和按 SALEDITEMS)。有了这个额外的索引,一百万行的查询在我的(不是很强大的)桌面计算机上在 2 秒内返回。如果没有这个索引,查询会很慢。

顺便说一句,这是 SQL Server 基于成本的查询优化如何在某些情况下完全崩溃的一个很好的例子。递归 CTE 解决方案的成本(在我的 PC 上)为 42,并且至少需要几分钟才能完成。非递归解决方案的成本为 15,446 (!!!) 并在 1.5 秒内完成。故事的寓意:在比较 SQL Server 查询计划时,不要假设成本必然与查询性能相关!

无论如何,这是我推荐的解决方案(我之前发布的相同的非递归 CTE):

DECLARE @SALEDITEMS INT = 3;

WITH SalesNoMatch ([DATE], SALEDITEMS, NoMatchDate)
AS
(
SELECT [DATE], SALEDITEMS,
(SELECT MIN([DATE]) FROM Sales s2 WHERE s2.SALEDITEMS <> @SALEDITEMS
AND s2.[DATE] > s1.[DATE]) as NoMatchDate
FROM Sales s1
)
, SalesMatchCount ([DATE], ConsecutiveCount) AS
(
SELECT [DATE], 1+(SELECT COUNT(1) FROM Sales s2 WHERE s2.[DATE] > s1.[DATE] AND s2.[DATE] < NoMatchDate)
FROM SalesNoMatch s1
WHERE s1.SALEDITEMS = @SALEDITEMS
)
SELECT MAX(ConsecutiveCount)
FROM SalesMatchCount;

这是我用来测试的 DDL,包括您需要的索引:
CREATE TABLE [Sales](
[DATE] date NOT NULL,
[SALEDITEMS] int NOT NULL
);
CREATE UNIQUE CLUSTERED INDEX IX_Sales ON Sales ([DATE]);
CREATE UNIQUE NONCLUSTERED INDEX IX_Sales2 ON Sales (SALEDITEMS, [DATE]);

以下是我创建测试数据的方式——1,000,001 行,日期升序,SALEDITEMS 随机设置在 1 到 10 之间。
INSERT INTO Sales ([DATE], SALEDITEMS)
VALUES ('1/1/09', 5)

DECLARE @i int = 0;

WHILE (@i < 1000000)
BEGIN
INSERT INTO Sales ([DATE], SALEDITEMS)
SELECT DATEADD (d, 1, (SELECT MAX ([DATE]) FROM Sales)), ABS(CHECKSUM(NEWID())) % 10 + 1

SET @i = @i + 1;
END

这是我放弃的递归 CTE 解决方案:
声明@SALEDITEMS INT = 3;
-- recursive CTE solution (remember to set MAXRECURSION!)
WITH SalesRowNum ([DATE], SALEDITEMS, RowNum)
AS
(
SELECT [DATE], SALEDITEMS, ROW_NUMBER() OVER (ORDER BY s1.[DATE]) as RowNum
FROM Sales s1
)
, SalesCTE (RowNum, [DATE], ConsecutiveCount)
AS
(
SELECT s1.RowNum, s1.[DATE], 1 AS ConsecutiveCount
FROM SalesRowNum s1
WHERE SALEDITEMS = @SALEDITEMS

UNION ALL

SELECT s1.RowNum, s1.[DATE], ConsecutiveCount + 1 AS ConsecutiveCount
FROM SalesRowNum s1
INNER JOIN SalesCTE s2 ON s1.RowNum = s2.RowNum + 1
WHERE SALEDITEMS = @SALEDITEMS
)
SELECT MAX(ConsecutiveCount)
FROM SalesCTE;

关于sql - 查找表中值的最长序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1658566/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com