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

Oracle SQL Ghép nối các số tuần tự trái phải với số nhận dạng

Đây là một giải pháp hoạt động tổng quát hơn, ngay cả khi các cặp không nhất thiết phải được tìm thấy ngay bên cạnh nhau. (Nếu điều đó trên thực tế là BẮT BUỘC, nếu các bộ phận không thể được ghép nối nếu ID của chúng không liên tiếp, thì điều kiện đó có thể được thêm vào truy vấn.)

with
     test_data ( id, lr, identifier ) as (
       select '001', 'L', 'B15A' from dual union all
       select '002', 'R', 'A15C' from dual union all
       select '003', 'L', 'A15C' from dual union all
       select '004', 'R', 'A15C' from dual union all
       select '005', 'L', 'A15C' from dual union all
       select '006', 'R', 'D5A2' from dual union all
       select '009', 'R', 'D5A2' from dual union all
       select '010', 'L', 'E5A6' from dual union all
       select '011', 'R', 'E5A6' from dual union all
       select '012', 'L', 'E5A6' from dual union all
       select '013', 'R', 'E5A6' from dual union all
       select '014', 'R', 'H9S5' from dual union all
       select '017', 'L', 'EE5A' from dual union all
       select '018', 'R', 'EE5A' from dual
     )
-- end of test data, the solution (SQL query) begins below this line
select id, lr, identifier
from ( select id, lr, identifier,
              row_number() over (partition by identifier, lr order by id) as rn,
              least( count(case when lr = 'L' then 1 end) over (partition by identifier),
                     count(case when lr = 'R' then 1 end) over (partition by identifier)
                   ) as least_count
       from   test_data
)
where rn <= least_count
order by id               --  ORDER BY is optional
;

Đầu ra :

ID  LR IDENTIFIER
--- -- ----------
002 R  A15C
003 L  A15C
004 R  A15C
005 L  A15C
010 L  E5A6
011 R  E5A6
012 L  E5A6
013 R  E5A6
017 L  EE5A
018 R  EE5A

 10 rows selected 

Giải thích:Trong truy vấn bên trong, tôi thêm hai cột nữa vào dữ liệu ban đầu. Một, rn , đếm riêng biệt (bắt đầu từ 1 và tăng dần 1) cho từng định danh, riêng cho 'L' và 'R'. Điều này sẽ được sử dụng để tạo thành các cặp. Và, ct đưa ra ít nhất trong tổng số lần đếm cho 'L' và 'R' cho mỗi số nhận dạng. Trong truy vấn bên ngoài, tôi chỉ lọc ra tất cả các hàng có rn > ct - đó là những hàng không có một cặp trong bảng đầu tiên. Những gì còn lại là các cặp.

ĐÃ THÊM :Với điều kiện bổ sung là một cặp phải được tạo từ các hàng "liên tiếp" (được đo bằng id cột), đây trở thành một câu hỏi thú vị hơn. Đó là vấn đề về khoảng trống và đảo (xác định các nhóm hàng liên tiếp có cùng đặc điểm), nhưng có một điểm khác biệt:LR giá trị phải xen kẽ trong nhóm, thay vì không đổi. Phương pháp "tabibitosan" rất hiệu quả không thể được áp dụng ở đây (tôi nghĩ); phương pháp "bắt đầu nhóm", nói chung hơn, hoạt động. Đây là những gì tôi đã sử dụng ở đây. Lưu ý rằng cuối cùng, tôi bỏ đi hàng cuối cùng trong một nhóm, nếu số lượng cho nhóm là một số lẻ. (Chúng tôi có thể tìm thấy hai hoặc bốn hoặc sáu hàng liên tiếp tạo thành một hoặc hai hoặc ba cặp, nhưng không phải là một số lẻ các hàng có LR xen kẽ). Cũng lưu ý rằng nếu hai hàng có cùng số nhận dạng VÀ LR, thì hàng thứ hai sẽ luôn bắt đầu một nhóm MỚI, vì vậy nếu nó trên thực tế là một phần của một cặp (với hàng SAU nó), thì điều đó sẽ được giải pháp này nắm bắt chính xác.

So sánh giải pháp này với giải pháp MATCH_RECOGNIZE dành cho Oracle 12 trở lên mà tôi đã đăng riêng - và đánh giá cao nó đơn giản hơn bao nhiêu!

with
     prep ( id, lr, identifier, flag ) as (
       select id, lr, identifier,
              case when identifier = lag(identifier) over (order by id) 
                    and lr        != lag(lr)         over (order by id)
                   then null else 1 end
       from test_data    --  replace "test_data" with actual table name
     ), 
     with_groups ( id, lr, identifier, gp ) as (
       select id, lr, identifier,
              sum(flag) over (order by id)
       from   prep
     ),
     with_rn ( id, lr, identifier, rn, ct ) as (
       select id, lr, identifier,
              row_number() over (partition by identifier, gp order by id),
              count(*)     over (partition by identifier, gp)
       from   with_groups
     )
select   id, lr, identifier
from     with_rn
where    rn < ct or mod(rn, 2) = 0
order by id               --  ORDER BY is optional
;


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ORA-12704:bộ ký tự không khớp

  2. chuỗi con trong oracle

  3. Cách đơn giản để chạy tập lệnh sqlplus từ java

  4. Cách chọn * cộng với một cột khác

  5. Trong PL / SQL, làm thế nào để bạn cập nhật một hàng dựa trên hàng tiếp theo?