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

Giải pháp Gaps and Islands trong Oracle - sử dụng đệ quy

Đây là một biến thể của bài toán khoảng trống và đảo, với sự phức tạp thêm của số hàng tối đa trong mỗi đảo. Điều này hơi dài dòng nhưng bạn có thể bắt đầu bằng cách xác định các nhóm gây ra bởi thứ tự trình tự:

select t.*,
  row_number() over (partition by "Description" order by "Start") as rn,
  case when lag("SequentialOrder")
    over (partition by "Description" order by "Start") < "SequentialOrder"
    then 1 else 0 end as newblock
from test t
order by "Start";

Start     Description MaximunRow SequentialOrder  RN   NEWBLOCK
--------- ----------- ---------- --------------- --- ----------
12-JUN-15 A                    3               3   1          0
13-JUN-15 A                    3               4   2          1
14-JUN-15 A                    3               5   3          1
01-JUL-15 A                    3               4   4          0
02-JUL-15 A                    3               3   5          0
04-JUL-15 A                    3               4   6          1
01-AUG-15 B                    2               5   1          0
16-AUG-15 B                    2               7   2          1

Sau đó, bạn có thể sử dụng CTE đệ quy (từ 11gR2 trở đi) dựa trên đó:

with u as (
  select t.*,
    row_number() over (partition by "Description" order by "Start") as rn,
    case when lag("SequentialOrder")
      over (partition by "Description" order by "Start") < "SequentialOrder"
      then 1 else 0 end as newblock
  from test t
),
r ("Start", "Description", "MaximunRow", "SequentialOrder", rn, blocknum,
  pos, lastmaxrow) as (
  select u."Start", u."Description", u."MaximunRow", u."SequentialOrder", u.rn,
    1, 1, u."MaximunRow"
  from u
  where rn = 1
  union all
  select u."Start", u."Description", u."MaximunRow", u."SequentialOrder", u.rn,
    case when r.pos = r.lastmaxrow or u.newblock = 0
      then r.blocknum + 1 else r.blocknum end,
    case when r.pos = r.lastmaxrow or u.newblock = 0
      then 1 else r.pos + 1 end,
    case when r.pos = r.lastmaxrow or u.newblock = 0
      then r.lastmaxrow else u."MaximunRow" end
  from r
  join u on u."Description" = r."Description" and u.rn = r.rn + 1
)
select * from r
order by "Start";

Start     Description MaximunRow SequentialOrder  RN   BLOCKNUM  POS LASTMAXROW
--------- ----------- ---------- --------------- --- ---------- ---- ----------
12-JUN-15 A                    3               3   1          1    1          3
13-JUN-15 A                    3               4   2          1    2          3
14-JUN-15 A                    3               5   3          1    3          3
01-JUL-15 A                    3               4   4          2    1          3
02-JUL-15 A                    3               3   5          3    1          3
04-JUL-15 A                    3               4   6          3    2          3
01-AUG-15 B                    2               5   1          1    1          2
16-AUG-15 B                    2               7   2          1    2          2

Đây là chỉ định một blocknum cho mỗi hàng, bắt đầu từ một cho mỗi mô tả trong thành viên neo và được tăng lên trong thành viên đệ quy nếu newblock bằng 0 (chỉ ra sự phá vỡ trình tự) hoặc số lượng thành viên trong khối là số tối đa trước đó. (Tôi có thể không hiểu đúng logic cho 'mức tối đa trước đó' vì nó không rõ ràng trong câu hỏi.)

Sau đó, bạn có thể nhóm theo mô tả và số khối được tạo:

with u as (
  select t.*,
    row_number() over (partition by "Description" order by "Start") as rn,
    case when lag("SequentialOrder")
      over (partition by "Description" order by "Start") < "SequentialOrder"
      then 1 else 0 end as newblock
  from test t
),
r ("Start", "Description", "MaximunRow", "SequentialOrder", rn, blocknum,
  pos, lastmaxrow) as (
  select u."Start", u."Description", u."MaximunRow", u."SequentialOrder", u.rn,
    1, 1, u."MaximunRow"
  from u
  where rn = 1
  union all
  select u."Start", u."Description", u."MaximunRow", u."SequentialOrder", u.rn,
    case when r.pos = r.lastmaxrow or u.newblock = 0
      then r.blocknum + 1 else r.blocknum end,
    case when r.pos = r.lastmaxrow or u.newblock = 0
      then 1 else r.pos + 1 end,
    case when r.pos = r.lastmaxrow or u.newblock = 0
      then r.lastmaxrow else u."MaximunRow" end
  from r
  join u on u."Description" = r."Description" and u.rn = r.rn + 1
)
select min(r."Start") as "Start", max(r."Start") as "End", r."Description"
from r
group by r."Description", r.blocknum
order by r."Description", r.blocknum;

Start     End       Description
--------- --------- -----------
12-JUN-15 14-JUN-15 A          
01-JUL-15 01-JUL-15 A          
02-JUL-15 04-JUL-15 A          
01-AUG-15 16-AUG-15 B          

Dữ liệu mẫu của bạn không kích hoạt ngắt hàng tối đa vì bạn không có bất kỳ chuỗi nào dài hơn 3. Với một số dữ liệu bổ sung:

Insert into TEST ("Start","Description","MaximunRow","SequentialOrder") values (to_date('15-JUN-15','DD-MON-RR'),'A',3,7);
Insert into TEST ("Start","Description","MaximunRow","SequentialOrder") values (to_date('16-JUN-15','DD-MON-RR'),'A',3,8);
Insert into TEST ("Start","Description","MaximunRow","SequentialOrder") values (to_date('17-JUN-15','DD-MON-RR'),'A',3,10);
Insert into TEST ("Start","Description","MaximunRow","SequentialOrder") values (to_date('18-JUN-15','DD-MON-RR'),'A',3,12);
Insert into TEST ("Start","Description","MaximunRow","SequentialOrder") values (to_date('19-JUN-15','DD-MON-RR'),'A',3,13);

cùng một truy vấn nhận được:

Start     End       Description
--------- --------- -----------
12-JUN-15 14-JUN-15 A          
15-JUN-15 17-JUN-15 A          
18-JUN-15 19-JUN-15 A          
01-JUL-15 01-JUL-15 A          
02-JUL-15 04-JUL-15 A          
01-AUG-15 16-AUG-15 B          

vì vậy bạn có thể thấy nó tách ra khi thay đổi trình tự khi đánh ba hàng trong khối.

Bản trình diễn SQL Fiddle .

Bạn có thể thoát khỏi chỉ với CTE đệ quy chứ không phải CTE trung gian trước đó bằng cách so sánh trực tiếp thứ tự tuần tự trong các câu lệnh trường hợp thay vì sử dụng newblock; nhưng có rn để tìm hàng tiếp theo dễ hơn cố gắng tìm ngày tiếp theo vì chúng không liền nhau.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Truy xuất XMLType tiên tri được lưu trữ dưới dạng XML nhị phân từ tập kết quả trong Java

  2. Khắc phục “Không thể cài đặt trong Homebrew trên bộ xử lý ARM ở tiền tố mặc định của Intel (/ usr / local)!”

  3. Cách nhanh nhất để thực hiện so sánh trường trong cùng một bảng với lượng lớn dữ liệu trong oracle

  4. Gọi hàm pl / sql trong java?

  5. Làm thế nào để xác định tên máy chủ trong Oracle APEX?