2017-06-03 36 views
7

H: Làm cách nào để xếp hạng các bản ghi dựa trên giá trị thay đổi của 1 cột?Xếp hạng các bản ghi dựa trên giá trị thay đổi của 1 cột

tôi có các dữ liệu sau (https://pastebin.com/vdTb1JRT):

EmployeeID Date  Onleave 
ABH12345 2016-01-01 0 
ABH12345 2016-01-02 0 
ABH12345 2016-01-03 0 
ABH12345 2016-01-04 0 
ABH12345 2016-01-05 0 
ABH12345 2016-01-06 0 
ABH12345 2016-01-07 0 
ABH12345 2016-01-08 0 
ABH12345 2016-01-09 0 
ABH12345 2016-01-10 1 
ABH12345 2016-01-11 1 
ABH12345 2016-01-12 1 
ABH12345 2016-01-13 1 
ABH12345 2016-01-14 0 
ABH12345 2016-01-15 0 
ABH12345 2016-01-16 0 
ABH12345 2016-01-17 0 

Tôi muốn tạo ra kết quả như sau:

EmployeeID DateValidFrom DateValidTo  OnLeave 
ABH12345 2016-01-01  2016-01-09  0 
ABH12345 2016-01-10  2016-01-13  1 
ABH12345 2016-01-14  2016-01-17  0 

Vì vậy, tôi nghĩ nếu tôi bằng cách nào đó có thể tạo ra một cột đứng (như được hiển thị bên dưới) mà số gia tăng dựa trên giá trị trong cột Onleave - được phân đoạn theo cột EmployeeID.

EmployeeID Date  Onleave RankedCol 
ABH12345 2016-01-01 0   1 
ABH12345 2016-01-02 0   1 
ABH12345 2016-01-03 0   1 
ABH12345 2016-01-04 0   1 
ABH12345 2016-01-05 0   1 
ABH12345 2016-01-06 0   1 
ABH12345 2016-01-07 0   1 
ABH12345 2016-01-08 0   1 
ABH12345 2016-01-09 0   1 
ABH12345 2016-01-10 1   2 
ABH12345 2016-01-11 1   2 
ABH12345 2016-01-12 1   2 
ABH12345 2016-01-13 1   2 
ABH12345 2016-01-14 0   3 
ABH12345 2016-01-15 0   3 
ABH12345 2016-01-16 0   3 
ABH12345 2016-01-17 0   3 

Sau đó, tôi sẽ có thể làm như sau:

SELECT 
[EmployeeID] = [EmployeeID] 
,[DateValidFrom] = MIN([Date]) 
,[DateValidTo] = MAX([Date]) 
,[OnLeave]  = [OnLeave] 
FROM table/view/cte/sub-query 
GROUP BY 
[EmployeeID] 
,[OnLeave] 
,[RankedCol] 

giải pháp khác là rất đáng hoan nghênh ..

Dưới đây là các dữ liệu thử nghiệm:

WITH CTE AS (SELECT EmployeeID = 'ABH12345', [Date] = CAST(N'2016-01-01' AS Date), [Onleave] = 0 
UNION SELECT 'ABH12345', CAST(N'2016-01-02' AS Date), 0 
UNION SELECT 'ABH12345', CAST(N'2016-01-03' AS Date), 0 
UNION SELECT 'ABH12345', CAST(N'2016-01-04' AS Date), 0 
UNION SELECT 'ABH12345', CAST(N'2016-01-05' AS Date), 0 
UNION SELECT 'ABH12345', CAST(N'2016-01-06' AS Date), 0 
UNION SELECT 'ABH12345', CAST(N'2016-01-07' AS Date), 0 
UNION SELECT 'ABH12345', CAST(N'2016-01-08' AS Date), 0 
UNION SELECT 'ABH12345', CAST(N'2016-01-09' AS Date), 0 
UNION SELECT 'ABH12345', CAST(N'2016-01-10' AS Date), 1 
UNION SELECT 'ABH12345', CAST(N'2016-01-11' AS Date), 1 
UNION SELECT 'ABH12345', CAST(N'2016-01-12' AS Date), 1 
UNION SELECT 'ABH12345', CAST(N'2016-01-13' AS Date), 1 
UNION SELECT 'ABH12345', CAST(N'2016-01-14' AS Date), 0 
UNION SELECT 'ABH12345', CAST(N'2016-01-15' AS Date), 0 
UNION SELECT 'ABH12345', CAST(N'2016-01-16' AS Date), 0 
UNION SELECT 'ABH12345', CAST(N'2016-01-17' AS Date), 0 
) 

SELECT * FROM CTE 
+4

cộng 1 cho dữ liệu mẫu – TheGameiswar

+1

Mẹo: Nó rất hữu ích để gắn thẻ câu hỏi cơ sở dữ liệu với cả hai phần mềm thích hợp (MySQL, Oracle, DB2, ...) và phiên bản, ví dụ 'sql-server-2014'. Sự khác biệt về cú pháp và tính năng thường ảnh hưởng đến câu trả lời. Trong trường hợp này 'Lag' là một tính năng tương đối mới. – HABO

+0

đã thêm sql-server-2014, nhờ @HABO –

Trả lời

2

Đây là cách khác, đơn giản hơn một chút, để có được kết quả mong muốn - chỉ truy cập vào bảng một lần.

-- sample of data from your question 
with t1(EmployeeID, Date1, Onleave) as(
    select 'ABH12345', cast('2016-01-01' as date), 0 union all 
    select 'ABH12345', cast('2016-01-02' as date), 0 union all 
    select 'ABH12345', cast('2016-01-03' as date), 0 union all 
    select 'ABH12345', cast('2016-01-04' as date), 0 union all 
    select 'ABH12345', cast('2016-01-05' as date), 0 union all 
    select 'ABH12345', cast('2016-01-06' as date), 0 union all 
    select 'ABH12345', cast('2016-01-07' as date), 0 union all 
    select 'ABH12345', cast('2016-01-08' as date), 0 union all 
    select 'ABH12345', cast('2016-01-09' as date), 0 union all 
    select 'ABH12345', cast('2016-01-10' as date), 1 union all 
    select 'ABH12345', cast('2016-01-11' as date), 1 union all 
    select 'ABH12345', cast('2016-01-12' as date), 1 union all 
    select 'ABH12345', cast('2016-01-13' as date), 1 union all 
    select 'ABH12345', cast('2016-01-14' as date), 0 union all 
    select 'ABH12345', cast('2016-01-15' as date), 0 union all 
    select 'ABH12345', cast('2016-01-16' as date), 0 union all 
    select 'ABH12345', cast('2016-01-17' as date), 0 
) 
-- actual query 
select max(w.employeeid) as employeeid 
    , min(w.date1)  as datevalidfrom 
    , max(w.date1)  as datevalidto 
    , max(w.onleave) as onleave 
    from (
     select row_number() over(partition by employeeid order by date1) - 
       row_number() over(partition by employeeid, onleave order by date1) as grp 
      , employeeid 
      , date1 
      , onleave 
      from t1 s 
     ) w 
group by w.grp 
order by employeeid, datevalidfrom 

Kết quả:

employeeid datevalidfrom datevalidto onleave 
---------- ------------- ----------- ----------- 
ABH12345 2016-01-01 2016-01-09 0 
ABH12345 2016-01-10 2016-01-13 1 
ABH12345 2016-01-14 2016-01-17 0 
2

Đây là một ví dụ về vấn đề nhóm và đảo. Trong trường hợp này, bạn có thể sử dụng số học ngày. Quan sát chính là trừ một dãy số nguyên từ cột ngày xác định các đảo có giá trị tương tự.

Là một truy vấn, điều này có vẻ như:

SELECT EmployeeId, MIN([Date]) as DateValidFrom, MAX([Date]) as DateValidTo, 
     OnLeave 
FROM (SELECT t.*, 
      ROW_NUMBER() OVER (PARTITION BY EmployeeId, OnLeave ORDER BY [Date]) as seqnum 
     FROM t 
    ) t 
GROUP BY EmployeeID, DATEADD(day, - seqnum, [Date]), OnLeave; 

Bạn có thể chạy các subquery, nhìn chằm chằm vào các kết quả, và làm số học để xem lý do tại sao các công trình này.

Đây là example.

+0

Thú vị .. Kết quả đầu ra vẫn phần nào giống với nơi tôi bắt đầu. Làm thế nào tôi có thể tổng hợp kết quả chỉ trong 3 hàng mặc dù? –

3

Một cách khác để làm điều đó với lag. Chỉ định các nhóm bằng cách nhận giá trị Onleave trước đó cho mỗi employeeid và đặt lại nó khi tìm thấy một giá trị khác.

select employeeid,min(date) as date_from,max(date) as date_to,max(onleave) as onleave 
from (select t.*,sum(case when prev_ol=onleave then 0 else 1 end) over(partition by employeeid order by date) as grp 
     from (select c.*,lag(onleave,1,onleave) over(partition by employeeid order by date) as prev_ol 
      from cte c 
      ) t 
    ) t 
group by employeeid,grp 
+0

Làm việc như một sự quyến rũ! Chỉ định nhóm sử dụng độ trễ. Thật khéo léo. Cảm ơn rất nhiều! –

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