2009-11-30 59 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