2009-11-30 57 views
2
的任意序列

假設我們有一個表維護SQL Server中,找到值

Customer LastLogin ActionType 
1  12/1/2007 2 
1  12/2/2007 2 
etc. 

我們希望所有的客戶名單誰在過程中某一年的任何一點有一個或多個連續的序列,14天很長時間,用動作類型2登錄。

我當然可以很容易地用代碼來做到這一點,甚至可以在小集合上做到這一點。有沒有在SQL中使用非遊標方式?

+0

編輯以清晰的傢伙。我們正在尋找很長的(呃)連續序列,而不僅僅是連續兩次。 – 2009-11-30 16:41:14

+0

你這樣做後,我發佈我的代碼?你知道我必須寫代碼坐在我的椅子上,但面對UPHILL? – 2009-11-30 16:42:54

回答

4

這將選擇所有的客戶提供相同類型的至少兩個連續的動作。

WITH rows AS 
     (
     SELECT customer, action, 
       ROW_NUMBER() OVER (PARTITION BY customer ORDER BY lastlogin) AS rn 
     FROM mytable 
     ) 
SELECT DISTINCT customer 
FROM rows rp 
WHERE EXISTS 
     (
     SELECT NULL 
     FROM rows rl 
     WHERE rl.customer = rp.customer 
       AND rl.rn = rp.rn + 1 
       AND rl.action = rp.action 
     ) 

下面是正義行動2更高效的查詢:

WITH rows AS 
     (
     SELECT customer, ROW_NUMBER() OVER (PARTITION BY customer ORDER BY lastlogin) AS rn 
     FROM mytable 
     WHERE action = 2 
     ) 
SELECT DISTINCT customer 
FROM rows rp 
WHERE EXISTS 
     (
     SELECT NULL 
     FROM rows rl 
     WHERE rl.customer = rp.customer 
       AND rl.rn = rp.rn + 1 
     ) 

更新2:

要選擇不受干擾範圍:

WITH rows AS 
     (
     SELECT customer, action, lastlogin 
       ROW_NUMBER() OVER (PARTITION BY customer ORDER BY lastlogin) AS rn 
       ROW_NUMBER() OVER (PARTITION BY customer, action ORDER BY lastlogin) AS series 
     FROM mytable 
     ) 
SELECT DISTINCT customer 
FROM (
     SELECT customer 
     FROM rows rp 
     WHERE action 
     GROUP BY 
       customer, actioncode, series - rn 
     HAVING 
       DETEDIFF(day, MIN(lastlogin), MAX(lastlogin)) >= 14 
     ) q 

這個查詢計算兩個系列:一個返回c ontiguous ORDER BY lastlogin,第二個分區由action另外:

action logindate rn series diff = rn - series 
1  Jan 01 1 1  0 
1  Jan 02 2 2  0 
2  Jan 03 3 1  2 
2  Jan 04 4 2  2 
1  Jan 05 5 3  2 
1  Jan 06 6 4  2 

只要兩個方案之間的差別是相同的,該系列是不間斷的。每次中斷都會打破系列。 (action, diff)定義了不間斷的組。

我們可以按action, diff進行分組,在組內找到MAXMIN並對它們進行過濾。

如果您需要選擇14行而不是14連續幾天,則只需篩選COUNT(*)而不是DATEDIFF

+0

我應該更具體!你如何做N行動?特別是14(最好沒有14個不同子查詢) – 2009-11-30 16:45:14

+0

看起來不錯,我會盡快測試。我絕對需要序列,而不只是數(*)。我們正在尋找行爲模式。 – 2009-11-30 19:11:18

1

編輯:這將有關原來的問題連續兩個。在連續14是一個不同的答案

首先你需要一個序列,所以你要使用ROWNUMBER

可以使用ROWNUMBER = ROWNUMBER + 1

任何做自聯接維護支持自身兩個具有相同客戶ID的後續行,並且兩行都帶有「2」ActionType將會給你列表CUSTOMER作爲你的答案。

試試這個

WITH Maintenance AS 
(
SELECT 1 as Customer, CONVERT (DateTime, '1/1/2008') DateTimeStamp, 1 ActionType 
UNION 
SELECT 1, '3/1/2009', 1 
UNION 
SELECT 1, '3/1/2006', 2 
UNION 
SELECT 2, '3/1/2009', 1 
UNION 
SELECT 2, '3/1/2006', 2 
) 
,RowNumberMaintenance AS 
(SELECT ROW_NUMBER() OVER (ORDER BY Customer, DateTimeStamp) AS RowNumber, * 
FROM Maintenance) 
SELECT m1.Customer 
From RowNumberMaintenance M1 
    INNER JOIN RowNumberMaintenance M2 
     ON M1.Customer = M2.Customer 
     AND M1.RowNumber = M2.RowNumber + 1 
WHERE 1=1 
     AND M1.ActionType <> 2 
     AND M2.ActionType <> 2 
0
select customerID, count(customerID) 
from maintenance 
where actiontype = 2 
group by customerID 
having count(customerID) >= 1 
0

我打算假設,對於具有不同操作類型的同一用戶,通過一個序列來表示兩個或多個具有連續日期時間值的行,其間沒有其他行。既然如此,這應該給你,你希望得到什麼:

SELECT DISTINCT 
    T1.customer 
FROM 
    Maintenance T1 
INNER JOIN Maintenance T2 ON 
    T2.customer = T1.customer AND 
    T2.action_type = 2 AND 
    T2.last_login > T1.last_login 
LEFT OUTER JOIN Maintenance T3 ON 
    T3.customer = T1.customer AND 
    T3.last_login > T1.last_login AND 
    T3.last_login < T2.last_login AND 
    T3.action_type <> 2 
WHERE 
    T1.actiontype = 2 AND 
    T3.customer IS NULL 

SQL的功能正是我上面所說的 - 之後(T2)發現一排(T1)與另一列都與ACTION_TYPE = 2,其間沒有行(T3)與不同的動作類型。 T3.customer IS NULL檢查NULL,因爲如果列爲NULL(我假設它是一個NOT NULL列),那麼這意味着LEFT OUTER JOIN一定不能找到符合條件的行。

1

用途:

WITH dates AS (
    SELECT CAST('2007-01-01' AS DATETIME) 'date' 
    UNION ALL 
    SELECT DATEADD(dd, 1, t.date) 
    FROM dates t 
    WHERE DATEADD(dd, 1, t.date) <= GETDATE()) 
    SELECT m.customer, 
      m.actiontype 
    FROM dates d 
LEFT JOIN MAINTENANCE m ON m.last_login = d.date 
    WHERE m.last_login IS NULL