簡體   English   中英

如何使用SQL在表中查找N個連續記錄

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM