2011-10-31 76 views
2

我有3列1指示代理ID,一個指示它們是哪個級別(初學者,中級,高級),並指示他們達到該級別的月結束日期。SQL確定是否已經過去連續幾個月

如果樣本數據看起來像這樣

360123, Beginner, 1/22/2011 
360123, Null, 2/22/2011 
360123, Beginner, 3/22/2011 
360123, Intermediate, 4/22/2011 
360123, Beginner, 5/22/2011 
360123, Beginner, 6/22/2011 

如何設計一個查詢它會告訴我哪些代理進行的所有初學者目標從3/22連續4個月的6/22?

哇,謝謝大家的幫忙!

在6個月的時間裏,4個月的情況如何?第一個月是哪一個月你碰到其中一個目標?

+0

在這種情況下,您正在尋找連續4個月,您的'WHERE'子句僅涵蓋4個月(3月,4月,5月,6月)。情況總是如此嗎? –

回答

1

下面的示例數據和示例。基本上,通過ID進行分組並搜索不同月份的計數。

DECLARE @T table (id int, lvl varchar(100), datefield smalldatetime) 
INSERT INTO @T 
VALUES 
(360123, 'Beginner', '1/22/2011'), 
(360123, Null, '2/22/2011'), 
(360123, 'Beginner', '3/22/2011'), 
(360123, 'Intermediate', '4/22/2011'), 
(360123, 'Beginner', '5/22/2011'), 
(360123, 'Beginner', '6/22/2011') 

SELECT ID 
FROM @T 
WHERE Lvl = 'Beginner' 
AND datefield BETWEEN '3/1/2011' AND '6/30/2011 23:59:59' 
GROUP BY ID 
HAVING COUNT(DISTINCT(MONTH(DateField))) = 4 
+0

似乎錯過了**連續**要求(使用當前的WHERE條款) –

+0

@MartinSmith - 好點,我半數使用他的數據,一半使用他的發佈邏輯。現在只使用邏輯! – JNK

+0

Nitpicking:它可以工作4或5甚至12個月,但不是13或更多。 –

0
(Select id from table_name where date ='6/22/2011' and level ='Beginner') 
intersect 
(Select id from table_name where date ='5/22/2011' and level ='Beginner') 
intersect 

(Select id from table_name where date ='4/22/2011' and level ='Beginner') 
intersect 

(Select id from table_name where date ='3/22/2011' and level ='Beginner') 
+0

-1 - 'Intersects'不是一個有效的關鍵字,你在每個查詢中都使用相同的日期(其中沒有一個是有效的日期),並且即使使用正確的語法,這也要求他手動輸入每個日期,每個子查詢日/月。 – JNK

+0

@JNK謝謝,這是複製粘貼錯誤 – xsari3x

+0

DV刪除。儘管如此,這仍然是一種超級低效的方式。 – JNK

0
SELECT id 
FROM TableX 
WHERE level = 'Beginner' 
    AND datefield >= '2011-03-22' 
    AND datefield < '2011-06-23' 
GROUP BY id 
HAVING COUNT(DISTINCT YEAR(datefield), MONTH(datefield)) = 4 
    AND (YEAR(MAX(datefield))*12+MONTH(MAX(datefield))) 
    - (YEAR(MIN(datefield))*12+MONTH(MIN(datefield))) = 4 - 1 
0

主要伎倆是創建 「人工」 標識使用它作爲錨在遞歸CTE:

DECLARE @T TABLE( ID INT, 拉特VARCHAR(100) , Datefield SMALLDATETIME);

INSERT INTO @T 
VALUES (360123, 'Beginner', '1/22/2011'), 
(360123, NULL, '2/22/2011'), 
(360123, 'Beginner', '3/22/2011'), 
(360123, 'Intermediate', '4/22/2011'), 
(360123, 'Beginner', '12/22/2011'), 
(360123, 'Beginner', '01/22/2012'); 

DECLARE @BeginTime AS DATETIME = '1/22/2011'; 

DECLARE @EndTime AS DATETIME = '6/22/2012'; 

WITH M 
AS  (SELECT DISTINCT Id, 
         MONTH(datefield) AS Mth, 
         YEAR(datefield) AS Yr, 
         ROW_NUMBER() OVER (PARTITION BY Id ORDER BY YEAR(datefield), MONTH(datefield)) AS RN 
     FROM @T AS T 
     WHERE Lvl = 'Beginner' 
       AND T.Datefield >= @BeginTime 
       AND T.Datefield <= @EndTime), 
     C (Id, RN, MonthsInARow, Mth, Yr) 
AS  (SELECT M.Id, 
       RN, 
       CAST (1 AS INT), 
       Mth, 
       Yr 
     FROM M 
     WHERE RN = 1 
     UNION ALL 
     SELECT M.Id, 
       M.RN, 
       CASE 
       WHEN M.Mth = C.Mth + 1 
         OR (M.Mth = 1 
          AND C.Mth = 12 
          AND M.Yr = C.yr + 1) THEN C.MonthsInARow + 1 ELSE 1 
       END, 
       M.Mth, 
       M.Yr 
     FROM M 
       INNER JOIN 
       C 
       ON M.Id = C.Id 
        AND M.RN = C.RN + 1) 
SELECT [C].[Id],MAX([C].[MonthsInARow]) MAXMonth 
FROM C 
GROUP BY [Id]