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

SQL Tìm bản sao với một số trường (không có ID duy nhất)

Cho phép có một số dữ liệu thú vị với các bản sao được xâu chuỗi trên các thuộc tính khác nhau:

CREATE TABLE data ( ID, A, B, C ) AS
  SELECT 1, 1, 1, 1 FROM DUAL UNION ALL -- Related to #2 on column A
  SELECT 2, 1, 2, 2 FROM DUAL UNION ALL -- Related to #1 on column A, #3 on B & C, #5 on C
  SELECT 3, 2, 2, 2 FROM DUAL UNION ALL -- Related to #2 on columns B & C, #5 on C
  SELECT 4, 3, 3, 3 FROM DUAL UNION ALL -- Related to #5 on column A
  SELECT 5, 3, 4, 2 FROM DUAL UNION ALL -- Related to #2 and #3 on column C, #4 on A
  SELECT 6, 5, 5, 5 FROM DUAL;          -- Unrelated

Bây giờ, chúng ta có thể nhận được một số mối quan hệ bằng cách sử dụng các hàm phân tích (không có bất kỳ phép nối nào):

SELECT d.*,
       LEAST(
         FIRST_VALUE( id ) OVER ( PARTITION BY a ORDER BY id ),
         FIRST_VALUE( id ) OVER ( PARTITION BY b ORDER BY id ),
         FIRST_VALUE( id ) OVER ( PARTITION BY c ORDER BY id )
       ) AS duplicate_of
FROM   data d;

Điều này mang lại:

ID A B C DUPLICATE_OF
-- - - - ------------
 1 1 1 1            1
 2 1 2 2            1
 3 2 2 2            2
 4 3 3 3            4
 5 3 4 2            2
 6 5 5 5            6

Nhưng điều đó không hiểu rằng số 4 liên quan đến số 5 liên quan đến số 2 và sau đó là số 1 ...

Điều này có thể được tìm thấy với một truy vấn phân cấp:

SELECT id, a, b, c,
       CONNECT_BY_ROOT( id ) AS duplicate_of
FROM   data
CONNECT BY NOCYCLE ( PRIOR a = a OR PRIOR b = b OR PRIOR c = c );

Nhưng điều đó sẽ tạo ra rất nhiều hàng trùng lặp (vì nó không biết bắt đầu phân cấp từ đâu nên sẽ lần lượt chọn từng hàng làm gốc) - thay vào đó, bạn có thể sử dụng truy vấn đầu tiên để cung cấp cho truy vấn phân cấp một điểm bắt đầu khi IDDUPLICATE_OF các giá trị giống nhau:

SELECT id, a, b, c,
       CONNECT_BY_ROOT( id ) AS duplicate_of
FROM   (
  SELECT d.*,
         LEAST(
           FIRST_VALUE( id ) OVER ( PARTITION BY a ORDER BY id ),
           FIRST_VALUE( id ) OVER ( PARTITION BY b ORDER BY id ),
           FIRST_VALUE( id ) OVER ( PARTITION BY c ORDER BY id )
         ) AS duplicate_of
  FROM   data d
)
START WITH id = duplicate_of
CONNECT BY NOCYCLE ( PRIOR a = a OR PRIOR b = b OR PRIOR c = c );

Điều này mang lại:

ID A B C DUPLICATE_OF
-- - - - ------------
 1 1 1 1            1
 2 1 2 2            1
 3 2 2 2            1
 4 3 3 3            1
 5 3 4 2            1
 1 1 1 1            4
 2 1 2 2            4
 3 2 2 2            4
 4 3 3 3            4
 5 3 4 2            4
 6 5 5 5            6

Vẫn có một số hàng bị trùng lặp do cực tiểu cục bộ trong tìm kiếm xảy ra lỗi # 4 ... có thể được xóa bằng GROUP BY đơn giản :

SELECT id, a, b, c,
       MIN( duplicate_of ) AS duplicate_of
FROM   (
  SELECT id, a, b, c,
         CONNECT_BY_ROOT( id ) AS duplicate_of
  FROM   (
    SELECT d.*,
           LEAST(
             FIRST_VALUE( id ) OVER ( PARTITION BY a ORDER BY id ),
             FIRST_VALUE( id ) OVER ( PARTITION BY b ORDER BY id ),
             FIRST_VALUE( id ) OVER ( PARTITION BY c ORDER BY id )
           ) AS duplicate_of
    FROM   data d
  )
  START WITH id = duplicate_of
  CONNECT BY NOCYCLE ( PRIOR a = a OR PRIOR b = b OR PRIOR c = c )
)
GROUP BY id, a, b, c;

Điều này cho kết quả:

ID A B C DUPLICATE_OF
-- - - - ------------
 1 1 1 1            1
 2 1 2 2            1
 3 2 2 2            1
 4 3 3 3            1
 5 3 4 2            1
 6 5 5 5            6


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Gặp sự cố lạ với hàm TO_NUMBER trong Oracle

  2. Tại sao sqlplus không kết nối?

  3. Làm cách nào để lấy COUNT (col) ... GROUP BY để sử dụng chỉ mục?

  4. Làm cách nào để lấy tất cả các tên kích hoạt từ cơ sở dữ liệu bằng Java JDBC?

  5. chạy mã sql oracle trực tuyến