假设我们有一个表维护SQL Server中,找到值
Customer LastLogin ActionType
1 12/1/2007 2
1 12/2/2007 2
etc.
我们希望所有的客户名单谁在过程中某一年的任何一点有一个或多个连续的序列,14天很长时间,用动作类型2登录。
我当然可以很容易地用代码来做到这一点,甚至可以在小集合上做到这一点。有没有在SQL中使用非游标方式?
假设我们有一个表维护SQL Server中,找到值
Customer LastLogin ActionType
1 12/1/2007 2
1 12/2/2007 2
etc.
我们希望所有的客户名单谁在过程中某一年的任何一点有一个或多个连续的序列,14天很长时间,用动作类型2登录。
我当然可以很容易地用代码来做到这一点,甚至可以在小集合上做到这一点。有没有在SQL中使用非游标方式?
这将选择所有的客户提供相同类型的至少两个连续的动作。
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
进行分组,在组内找到MAX
和MIN
并对它们进行过滤。
如果您需要选择14
行而不是14
连续几天,则只需筛选COUNT(*)
而不是DATEDIFF
。
我应该更具体!你如何做N行动?特别是14(最好没有14个不同子查询) – 2009-11-30 16:45:14
看起来不错,我会尽快测试。我绝对需要序列,而不只是数(*)。我们正在寻找行为模式。 – 2009-11-30 19:11:18
编辑:这将有关原来的问题连续两个。在连续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
select customerID, count(customerID)
from maintenance
where actiontype = 2
group by customerID
having count(customerID) >= 1
我打算假设,对于具有不同操作类型的同一用户,通过一个序列来表示两个或多个具有连续日期时间值的行,其间没有其他行。既然如此,这应该给你,你希望得到什么:
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一定不能找到符合条件的行。
用途:
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
编辑以清晰的家伙。我们正在寻找很长的(呃)连续序列,而不仅仅是连续两次。 – 2009-11-30 16:41:14
你这样做后,我发布我的代码?你知道我必须写代码坐在我的椅子上,但面对UPHILL? – 2009-11-30 16:42:54