假設我們有一個表維護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