這是一個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
要求4 SP /句話會給1調用SP/sentecne 3會給2 ,因爲在第3行中有2次。
我運行SQL Server 2008的
這是一個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
要求4 SP /句話會給1調用SP/sentecne 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和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
SALEDITEMS上升日期我的測試數據 - 1,000,001行
這是我放棄的遞歸CTE解決方案: DECLARE @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;
未經檢驗的,因爲你沒有提供DDL和樣本數據:
DECLARE @SALEDITEMS INT;
SET @SALEDITEMS=3;
SELECT MAX(cnt) FROM(
SELECT COUNT(*) FROM YourTable JOIN (
SELECT y1.[Date] AS d1, y2.[Date] AS d2
FROM YourTable AS y1 JOIN YourTable AS y2
ON [email protected] AND [email protected]
AND NOT EXISTS(SELECT 1 FROM YourTable AS y
WHERE y.SALEDITEMS<>@SALEDITEMS
AND y1.[Date] < y.[Date] AND y.[Date] < y2.[Date])
) AS t
WHERE [Date] BETWEEN t.d1 AND t.d2
) AS t;
我明白了......它可能工作,有一個錯誤附近最後的WHERE不知道什麼 – Dani 2009-11-01 23:14:21
謝謝!在一個小表(1400行)上嘗試了第二個代碼(非遞歸)。在30000行的表上嘗試過它,它永遠不會結束,但日期列上沒有索引,所以我想我需要先開始修復它。我可以在聲明中設置MaxRecursion嗎?我應該如何取消設置或將其恢復爲默認值?遞歸會更快嗎? – Dani 2009-11-02 00:08:02
我用更多信息更新瞭解決方案 - 一旦表格有很多行,非遞歸解決方案看起來就像是更好的解決方案。而且實際上你需要兩個索引 - 否則(正如你發現的那樣),當有很多行時,查詢會非常慢。添加第二個索引(見上面),你就可以在一秒鐘內完成你的30,000行查詢。 – 2009-11-02 01:57:37