2012-04-08 28 views
5

Tôi có một bảng với một loạt các giá trị (IP varchar (15), DateTime datetime2). Mỗi hàng tương ứng với yêu cầu HTTP do người dùng thực hiện. Tôi muốn chỉ định số phiên cho các hàng này. Các địa chỉ IP khác nhau có số phiên khác nhau. Cùng một IP sẽ được chỉ định một số phiên mới nếu yêu cầu cuối cùng cũ hơn 30 phút. Đây là đầu ra mẫu:Máy chủ SQL: row_number được phân đoạn theo timeout

IP,  DateTime,   SessionNumber, RequestNumber 
1.1.1.1, 2012-01-01 00:01, 1,    1 
1.1.1.1, 2012-01-01 00:02, 1,    2 
1.1.1.1, 2012-01-01 00:03, 1,    3 
1.1.1.2, 2012-01-01 00:04, 2,    1 --different IP => new session number 
1.1.1.2, 2012-01-01 00:05, 2,    2 
1.1.1.2, 2012-01-01 00:40, 3,    1 --same IP, but last request 35min ago (> 30min) 

Cột 1 và 2 là đầu vào, 3 và 4 là kết quả mong muốn. Bảng này hiển thị hai người dùng.

Vì bảng bên dưới là thực sự lớn, cách này có thể được giải quyết hiệu quả? Tôi muốn một số lượng nhỏ đi qua dữ liệu (một hoặc hai).

+0

Phiên bản SQL Server nào? Nếu năm 2012, chức năng điều khoản 'OVER' mới sẽ giúp ích. –

+0

Có, đó là SQL Server 2012. – usr

Trả lời

8

Đây là một vài lần thử.

;WITH CTE1 AS 
(
SELECT *, 
IIF(DATEDIFF(MINUTE, 
     LAG(DateTime) OVER (PARTITION BY IP ORDER BY DateTime), 
     DateTime) < 30,0,1) AS SessionFlag 
FROM Sessions 
), CTE2 AS 
(
SELECT *, 
     SUM(SessionFlag) OVER (PARTITION BY IP 
            ORDER BY DateTime) AS IPSessionNumber 
FROM CTE1 
) 
SELECT IP, 
     DateTime, 
     DENSE_RANK() OVER (ORDER BY IP, IPSessionNumber) AS SessionNumber, 
     ROW_NUMBER() OVER (PARTITION BY IP, IPSessionNumber 
           ORDER BY DateTime) AS RequestNumber 
FROM CTE2 

này có hai cuộc phẫu thuật loại (bởi IP, DateTime sau đó bởi IP, IPSessionNumber) nhưng giả định rằng SessionNumber có thể được gán tùy ý miễn là một số phiên khác nhau duy nhất được gán cho mỗi phiên làm việc mới mỗi địa chỉ ip/30 phút qui định.

Để chỉ định tuần tự SessionNumber theo thứ tự thời gian. Tôi đã sử dụng như sau.

;WITH CTE1 AS 
(
SELECT *, 
IIF(DATEDIFF(MINUTE, 
     LAG(DateTime) OVER (PARTITION BY IP ORDER BY DateTime), 
     DateTime) < 30,0,1) AS SessionFlag 
FROM Sessions 
), CTE2 AS(
SELECT *, 
     SUM(SessionFlag) OVER (ORDER BY DateTime) AS GlobalSessionNo 
FROM CTE1 
), CTE3 AS(
SELECT *, 
     MAX(CASE WHEN SessionFlag = 1 THEN GlobalSessionNo END) 
       OVER (PARTITION BY IP ORDER BY DateTime) AS SessionNumber 
FROM CTE2) 
SELECT IP, 
     DateTime, 
     SessionNumber, 
     ROW_NUMBER() OVER (PARTITION BY SessionNumber 
           ORDER BY DateTime) AS RequestNumber 
FROM CTE3 

Điều này làm tăng số hoạt động sắp xếp thành 4 tuy nhiên.

+0

Nếu các yêu cầu từ hai lần xen kẽ của IP, các phiên của chúng sẽ được trộn lẫn không? – Andomar

+0

@Andomar - Tốt! Đã sửa. –

+0

Sử dụng số cửa sổ là khéo léo! Tôi sẽ nhớ điều đó. – usr

2

Đây là phiên bản sử dụng biến bảng và row_number để tạo ID có thể được sử dụng trong CTE đệ quy. Nó có thể là đáng giá để so sánh hiệu suất với con trỏ và một phiên bản (được cung cấp bởi Martin).

CREATE TABLE #T 
(
    IP varchar(15), 
    DateTime datetime, 
    ID int, 
    primary key (IP, ID) 
) 

insert into #T(IP, DateTime, ID) 
select IP, DateTime, row_number() over(partition by IP order by DateTime) 
from #sessionRequests 

;with C as 
(
    select IP, 
     ID, 
     DateTime, 
     1 as Session 
    from #T 
    where ID = 1 
    union all 
    select T.IP, 
     T.ID, 
     T.DateTime, 
     C.Session + case when datediff(minute, C.DateTime, T.DateTime) >= 30 then 1 else 0 end 
    from #T as T 
    inner join C 
     on T.IP = C.IP and 
     T.ID = C.ID + 1 
) 
SELECT IP, 
     DateTime, 
     dense_rank() over(order by IP, Session) as SessionNumber, 
     row_number() over(partition by IP, Session order by DateTime) as RequestNumber 
from C 
order by IP, DateTime, SessionNumber, RequestNumber 
option (maxrecursion 0) 
+1

Tôi thích phiên bản này vì nó rất dễ mở rộng, gần giống như cách tiếp cận dựa trên con trỏ. Tôi đã thay đổi nó để sử dụng một bảng tạm thời mà cố định một vấn đề tối ưu hóa (biến bảng không có số liệu thống kê). Ngoài ra, tôi đã xác minh rằng mã này hoạt động. Cảm ơn! – usr

Các vấn đề liên quan