[英]How to find N Consecutive records in a table using SQL
我有以下表定義和示例數據。 在下表中,“客戶產品和日期”是關鍵字段
Table One
Customer Product Date SALE
X A 01/01/2010 YES
X A 02/01/2010 YES
X A 03/01/2010 NO
X A 04/01/2010 NO
X A 05/01/2010 YES
X A 06/01/2010 NO
X A 07/01/2010 NO
X A 08/01/2010 NO
X A 09/01/2010 YES
X A 10/01/2010 YES
X A 11/01/2010 NO
X A 12/01/2010 YES
在上表中,我需要查找沒有銷售的N條或N條連續記錄,銷售值為'NO'例如,如果N為2,則結果集將返回以下內容
Customer Product Date SALE
X A 03/01/2010 NO
X A 04/01/2010 NO
X A 06/01/2010 NO
X A 07/01/2010 NO
X A 08/01/2010 NO
有人可以幫助我進行SQL查詢以獲得所需的結果。 我使用的是SQL Server2005。我開始使用ROW_NUMBER()和PARTITION子句進行游戲,但是沒有運氣。 謝謝你的幫助
您需要將表與其自身進行匹配,就好像其中有2個表一樣。 因此,您使用兩個別名o1和o2來引用您的表:
SELECT DISTINCT o1.customer, o1.product, o1.datum, o1.sale
FROM one o1, one o2
WHERE (o1.datum = o2.datum-1 OR o1.datum = o2.datum +1)
AND o1.sale = 'NO'
AND o2.sale = 'NO';
customer | product | datum | sale
----------+---------+------------+------
X | A | 2010-01-03 | NO
X | A | 2010-01-04 | NO
X | A | 2010-01-06 | NO
X | A | 2010-01-07 | NO
X | A | 2010-01-08 | NO
請注意,我是在postgresql數據庫上執行查詢的-也許語法在ms-sql-server上有所不同,也許在別名“ FROM one AS o1”上,也許您不能以這種方式添加/減去。
一種不同的方法,靈感來自吃午飯的最后一行。
獲取-對於給定日期,第一個日期晚於YES,最后一個日期晚於YES。 這些構成了邊界,我們的日期將在此邊界內。
SELECT (o1.datum),
MAX (o3.datum) - MIN (o2.datum) AS diff
FROM one o1, one o2, one o3
WHERE o1.sale = 'NO'
AND o3.datum <
(SELECT MIN (datum)
FROM one
WHERE datum >= o1.datum
AND SALE = 'YES')
AND o2.datum >
(SELECT MAX (datum)
FROM one
WHERE datum <= o1.datum
AND SALE = 'YES')
GROUP BY o1.datum
HAVING MAX (o3.datum) - MIN (o2.datum) >= 2
ORDER BY o1.datum;
也許它需要某種優化,因為表1是查詢的5倍。 :)
好的,我們需要一個可變的答案。 我們搜索一個日期,在該日期中,我們有N個后續日期,而銷售字段均為“ NO”。
SELECT d1.datum
FROM one d1, one d2, i
WHERE d1.sale = 'NO' AND d2.sale = 'NO'
AND d1.datum = (d2.datum - i)
AND i > 0 AND i < 4
GROUP BY d1.datum
HAVING COUNT (*) = 3;
這將給我們提供日期,我們將其用於子查詢。
筆記:
我用'datum'代替了date,因為date是postgresql的保留關鍵字。
在Oracle中,您可以使用虛擬表虛擬對象,其中包含您所要求的任何內容,例如“(1,2,3)中的SELCT foo FROM dual WHERE foo;”。 如果我沒記錯的話,它會給你1、2、3。 根據供應商的不同,可能還有其他技巧可以使序列1到N。我創建了一個帶有列i的表i,並用值1到100填充了該表,我希望N不超過100; 由於有幾個版本,postgresql包含一個函數'generate_series(from,to),它也可以解決該問題,並且可能與特定數據庫的解決方案相似。 但是表我應該獨立於供應商工作。
如果N == 17,則必須將3個位置從3修改為17。
最終查詢將是:
SELECT o4.*
FROM one o3, one o4
WHERE o3.datum = (
SELECT d1.datum
FROM one d1, one d2, i
WHERE d1.sale = 'NO' AND d2.sale = 'NO'
AND d1.datum = (d2.datum - i)
AND i > 0 AND i <= 3
GROUP BY d1.datum
HAVING COUNT (*) = 3)
AND o4.datum <= o3.datum + 3
AND o4.datum >= o3.datum;
customer | product | datum | sale
----------+---------+------------+------
X | A | 2010-02-06 | NO
X | A | 2010-02-07 | NO
X | A | 2010-02-08 | NO
X | A | 2010-02-09 | NO
感謝大家發布您的解決方案。 我想,我也將與大家分享我的解決方案。 正如供參考,我從另一個SQL Server Central論壇成員那里收到了此解決方案。 我絕對不會為這種解決方案而贊揚。
DECLARE @CNT INT
SELECT @CNT = 3
SELECT * FROM
(
SELECT
[Customer], [Product], [Date], [Sale], groupID,
COUNT(*) OVER (PARTITION BY [Customer], [Product], [Sale], groupID) AS groupCnt
FROM
(
SELECT
[Customer], [Product], [Date], [Sale],
ROW_NUMBER() OVER (PARTITION BY [Customer], [Product] ORDER BY [Date])
- ROW_NUMBER() OVER (PARTITION BY [Customer], [Product], [Sale] ORDER BY [Date]) AS groupID
FROM
[TableSales]
) T1
) T2
WHERE
T2.[Sale] = 'NO' AND T2.[groupCnt] >= @CNT
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.