2012-09-19 27 views
7

Tôi có một bảng có tên là Chi tiết vắng mặt và tôi muốn nhóm các ngày tuần tự. Dưới đây, là các dữ liệuTruy vấn máy chủ SQL để nhóm các ngày tuần tự

EID  AbsenceType AbsenceStartDate    AbsenceEndDate 
769  Holiday  2012-06-25 00:00:00.000   2012-06-25 23:59:59.000 
769  Holiday  2012-06-26 00:00:00.000   2012-06-26 23:59:59.000 
769  Holiday  2012-09-03 00:00:00.000   2012-09-03 23:59:59.000 
769  Holiday  2012-09-04 00:00:00.000   2012-09-04 23:59:59.000 
769  Holiday  2012-09-05 00:00:00.000   2012-09-05 23:59:59.000 
769  Holiday  2012-09-06 00:00:00.000   2012-09-06 23:59:59.000 
769  Holiday  2012-09-07 00:00:00.000   2012-09-07 23:59:59.000 

Kết quả tôi đang cố gắng để có được là

EID  AbsenceType AbsenceStartDate   AbsenceEndDate 
769  Holiday  2012-06-25 00:00:00.000   2012-06-26 23:59:59.000 
769  Holiday  2012-09-03 00:00:00.000   2012-09-07 23:59:59.000 

Bất kỳ giúp đỡ được nhiều đánh giá cao.

+0

Bạn quên xóa cột AbsenceType khỏi tiêu đề hoặc thêm giá trị cho cột này. – Vikdor

+0

@ Vikdor - Đó là sự thật tôi đã quên xóa cột Lý do vắng mặt. Cảm ơn vì điều đó. – user1682461

+0

@podiluska - Tôi chưa bắt đầu viết bất kỳ truy vấn nào. Chỉ cần tìm con trỏ. – user1682461

Trả lời

0

Nếu tôi hiểu chính xác câu hỏi của bạn, bạn muốn tìm các khoảng thời gian liên tục trong hồ sơ của mình.
Vấn đề chính sẽ được xác định những gì thực sự tạo nên khoảng thời gian liên tục:
Nếu bạn đang xem xét sự vắng mặt tại nơi làm việc hơn bất kỳ chuỗi

date1.09:00 to date1.18:00 
date2.09:00 to date2.18:00 

nơi date2 là một ngày làm việc tiếp theo sau date1 có thể được coi liên tiếp.

Trong trường hợp của bạn, việc này tương đối dễ dàng, nhưng bạn sẽ không thể thực hiện điều đó trong một truy vấn. Ít nhất tôi không thể nghĩ ra một cách để làm điều đó ngay bây giờ.

P.S. Thuật toán "Islands and Gaps" được đề xuất bởi "podiluska" sẽ giúp bạn viết nó trong một truy vấn/thủ tục lưu sẵn.

1

tôi sẽ làm điều đó như sau:

  1. Xác định danh sách các chuỗi các số ngày vắng mặt.

    SELECT 
        ad1.EID, ad1.StartDate, ad2.EndDate 
    FROM 
        AbsenceDetails ad1 
        JOIN AbsenceDetails ad2 
        ON ad1.EID = ad2.EID 
    WHERE 
        DATEDIFF(ss, ad1.EndDate, ad2.StartDate) = 1 
    

    Kết quả sẽ như sau:

    769 2012-06-25 00:00:00.000 2012-06-26 23:59:59.000 
    769 2012-09-03 00:00:00.000 2012-09-04 23:59:59.000 
    769 2012-09-04 00:00:00.000 2012-09-05 23:59:59.000 
    769 2012-09-05 00:00:00.000 2012-09-06 23:59:59.000 
    769 2012-09-06 00:00:00.000 2012-09-07 23:59:59.000 
    
  2. Duyệt qua danh sách và xác định sự bắt đầu và kết thúc thời gian của mỗi đoạn. Điều này được thực hiện tốt hơn ở lớp ứng dụng.

4

Tôi đã đơn giản hóa kịch bản của bạn để tách biệt vấn đề chính. Chúng ta hãy giả sử bảng này với những khoảng trống:

with ns as (
select 1 as n union 
select 2 as n union 
select 3 as n union 
select 8 as n union --gap 
select 9 as n) 
select * 
into #ns 
from ns; 

Bây giờ, kết quả mà bạn đang mong đợi là:

ini fi 
--- -- 
1 3 
8 9 

Để có được kết quả này, tôi xoa bóp dữ liệu theo cách này: đầu tiên tôi tạo ra hai quan điểm với khởi đầu và thời gian kết thúc và thứ hai, tôi tham gia cả hai quan điểm để có được kết quả cuối cùng. Lưu ý rằng tôi tham gia bảng với chính nó để định vị thời gian bắt đầu và kết thúc:

with 
inis as          -- identifying start periods 
(
    select n1.n 
    from #ns n1 
    left outer join #ns n2 
     on n1.n = n2.n + 1 
    where n2.n is null 
    ), 
fis as          -- identifying ends periods 
( 
    select n1.n 
    from #ns n1 
    left outer join #ns n2 
     on n1.n = n2.n - 1 
    where n2.n is null 
    ) 
select inis.n as ini, min(fis.n) as fi -- joining starts and ends 
from inis 
inner join fis 
    on inis.n <= fis.n 
group by inis.n 
; 

Bạn có thể chuyển kỹ thuật này sang dữ liệu và loại dữ liệu của mình. Nếu bạn có bất kỳ vấn đề dịch truy vấn được miễn phí để yêu cầu.

Check query and results.

4

Dưới đây là giải pháp mà làm việc cho tôi.

SELECT EID, AbsenceType, MIN(AbsenceStartDate) AS AbsenceStartDate, MAX(AbsenceEndDate) AS AbsenceEndDate 
FROM (SELECT EID, AbsenceType, AbsenceStartDate, AbsenceEndDate, 
     DATEADD(dd, - ROW_NUMBER() OVER (PARTITION BY EID, AbsenceType ORDER BY EID,AbsenceStartDate), AbsenceStartDate) 
     FROM AbsenceDetails 
     GROUP BY EID,AbsenceType,AbsenceStartDate,AbsenceEndDate 
    ) a(EID, AbsenceType, AbsenceStartDate, AbsenceEndDate, Grp) 
GROUP BY EID, AbsenceType, Grp; 
+0

+1 Đây là câu trả lời rất hay. Lần tới hãy nhớ định dạng mã –

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