Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Cách xác định khoảng cách đầu tiên trong nhiều phạm vi ngày bắt đầu và ngày kết thúc cho từng thành viên riêng biệt trong T-SQL

Hãy thử cách này: http://www.sqlfiddle.com/#!3/c3365/ 20

with s as
(
  select *, row_number() over(partition by membercode order by startdate) rn
  from tbl
)
,gaps as
(
select a.membercode, a.startdate, a.enddate, b.startdate as nextstartdate
  ,datediff(d, a.enddate, b.startdate) as gap
from s a
join s b on b.membercode = a.membercode and b.rn = a.rn + 1
)
select membercode 
from gaps
group by membercode
having sum(case when gap <= 1 then 1 end) = count(*);

Xem tiến trình truy vấn tại đây: http://www.sqlfiddle.com/#!3/ c3365 / 20

Cách hoạt động, so sánh ngày kết thúc hiện tại với ngày bắt đầu tiếp theo và kiểm tra khoảng cách ngày:

with s as
(
  select *, row_number() over(partition by membercode order by startdate) rn
  from tbl
)
select a.membercode, a.startdate, a.enddate, b.startdate as nextstartdate
  ,datediff(d, a.enddate, b.startdate) as gap
from s a
join s b on b.membercode = a.membercode and b.rn = a.rn + 1;

Đầu ra:

| MEMBERCODE |  STARTDATE |    ENDDATE | NEXTSTARTDATE | GAP |
--------------------------------------------------------------
|          1 | 2010-01-15 | 2010-01-20 |    2010-01-19 |  -1 |
|          1 | 2010-01-19 | 2010-01-22 |    2010-01-20 |  -2 |
|          1 | 2010-01-20 | 2010-01-25 |    2010-01-26 |   1 |
|          2 | 2010-01-20 | 2010-01-25 |    2010-01-30 |   5 |
|          2 | 2010-01-30 | 2010-02-05 |    2010-02-04 |  -1 |

Sau đó, kiểm tra xem một thành viên có cùng số lượng yêu cầu mà không có khoảng cách so với tổng số yêu cầu của họ:

with s as
(
  select *, row_number() over(partition by membercode order by startdate) rn
  from tbl
)
,gaps as
(
select a.membercode, a.startdate, a.enddate, b.startdate as nextstartdate
  ,datediff(d, a.enddate, b.startdate) as gap
from s a
join s b on b.membercode = a.membercode and b.rn = a.rn + 1
)
select membercode, count(*) as count, sum(case when gap <= 1 then 1 end) as gapless_count
from gaps
group by membercode;

Đầu ra:

| MEMBERCODE | COUNT | GAPLESS_COUNT |
--------------------------------------
|          1 |     3 |             3 |
|          2 |     2 |             1 |

Cuối cùng, lọc họ, những thành viên không có lỗ hổng trong tuyên bố của họ:

with s as
(
  select *, row_number() over(partition by membercode order by startdate) rn
  from tbl
)
,gaps as
(
select a.membercode, a.startdate, a.enddate, b.startdate as nextstartdate
  ,datediff(d, a.enddate, b.startdate) as gap
from s a
join s b on b.membercode = a.membercode and b.rn = a.rn + 1
)
select membercode 
from gaps
group by membercode
having sum(case when gap <= 1 then 1 end) = count(*);

Đầu ra:

| MEMBERCODE |
--------------
|          1 |

Lưu ý rằng bạn không cần thực hiện COUNT(*) > 1 để phát hiện các thành viên có từ 2 yêu cầu trở lên. Thay vì sử dụng LEFT JOIN , chúng tôi sử dụng JOIN , điều này sẽ tự động loại bỏ các thành viên chưa có yêu cầu thứ hai. Đây là phiên bản (dài hơn) nếu bạn chọn sử dụng LEFT JOIN thay vào đó (đầu ra tương tự như trên):

with s as
(
select *, row_number() over(partition by membercode order by startdate) rn
from tbl
)
,gaps as
(
select a.membercode, a.startdate, a.enddate, b.startdate as nextstartdate
,datediff(d, a.enddate, b.startdate) as gap
from s a
left join s b on b.membercode = a.membercode and b.rn = a.rn + 1
)
select membercode 
from gaps
group by membercode
having sum(case when gap <= 1 then 1 end) = count(gap)
and count(*) > 1; -- members who have two ore more claims only

Đây là cách xem dữ liệu của truy vấn trên trước khi lọc:

with s as
(
  select *, row_number() over(partition by membercode order by startdate) rn
  from tbl
)
,gaps as
(
select a.membercode, a.startdate, a.enddate, b.startdate as nextstartdate
  ,datediff(d, a.enddate, b.startdate) as gap
from s a
left join s b on b.membercode = a.membercode and b.rn = a.rn + 1
)
select * from gaps;

Đầu ra:

| MEMBERCODE |  STARTDATE |    ENDDATE | NEXTSTARTDATE |    GAP |
-----------------------------------------------------------------
|          1 | 2010-01-15 | 2010-01-20 |    2010-01-19 |     -1 |
|          1 | 2010-01-19 | 2010-01-22 |    2010-01-20 |     -2 |
|          1 | 2010-01-20 | 2010-01-25 |    2010-01-26 |      1 |
|          1 | 2010-01-26 | 2010-01-30 |        (null) | (null) |
|          2 | 2010-01-20 | 2010-01-25 |    2010-01-30 |      5 |
|          2 | 2010-01-30 | 2010-02-05 |    2010-02-04 |     -1 |
|          2 | 2010-02-04 | 2010-02-15 |        (null) | (null) |
|          3 | 2010-02-15 | 2010-03-02 |        (null) | (null) |

CHỈNH SỬA về việc làm rõ yêu cầu:

Khi bạn làm rõ, bạn cũng muốn bao gồm những thành viên chưa có yêu cầu thứ hai, hãy làm điều này thay thế: http://sqlfiddle.com/#!3/c3365/22

with s as
(
select *, row_number() over(partition by membercode order by startdate) rn
from tbl
)
,gaps as
(
select a.membercode, a.startdate, a.enddate, b.startdate as nextstartdate
,datediff(d, a.enddate, b.startdate) as gap
from s a
left join s b on b.membercode = a.membercode and b.rn = a.rn + 1
)
select membercode 
from gaps
group by membercode
having sum(case when gap <= 1 then 1 end) = count(gap)
-- members who have yet to have a second claim are valid too
or count(nextstartdate) = 0; 

Đầu ra:

| MEMBERCODE |
--------------
|          1 |
|          3 |

Kỹ thuật này là đếm nextstartdate của thành viên , nếu họ không có ngày bắt đầu tiếp theo (tức là count(nextstartdate) = 0 ) thì chúng chỉ là những xác nhận quyền sở hữu duy nhất và cũng hợp lệ, sau đó chỉ cần đính kèm OR này điều kiện:

or count(nextstartdate) = 0; 

Trên thực tế, điều kiện bên dưới cũng sẽ đủ, mặc dù vậy, tôi muốn làm cho truy vấn tự ghi lại nhiều hơn, do đó tôi khuyên bạn nên tính vào ngày bắt đầu tiếp theo của thành viên. Đây là một điều kiện thay thế để tính các thành viên chưa có yêu cầu thứ hai:

or count(*) = 1;

Btw, chúng ta cũng phải thay đổi so sánh từ cái này:

sum(case when gap <= 1 then 1 end) = count(*)

về điều này (vì chúng tôi đang sử dụng LEFT JOIN bây giờ):

sum(case when gap <= 1 then 1 end) = count(gap)


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Ví dụ về Chuyển đổi 'time' thành 'datetime' trong SQL Server (T-SQL)

  2. Phục hồi cơ sở dữ liệu được tăng tốc trong SQL Server 2019

  3. Cách tốt nhất cho khóa chính trong bảng là gì?

  4. Xóa tài khoản thư cơ sở dữ liệu trong SQL Server (T-SQL)

  5. Tìm thứ tự nút trong tài liệu XML trong SQL Server