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

Làm cách nào để tìm các bảng tham chiếu đến một hàng cụ thể thông qua khóa ngoại?

Giá trị NULL trong cột tham chiếu

Truy vấn này tạo ra câu lệnh DML để tìm tất cả các hàng trong tất cả các bảng, trong đó một cột có ràng buộc khóa ngoại tham chiếu đến một bảng khác nhưng giữ một NULL giá trị trong cột đó:

WITH x AS (
 SELECT c.conrelid::regclass    AS tbl
      , c.confrelid::regclass   AS ftbl
      , quote_ident(k.attname)  AS fk
      , quote_ident(pf.attname) AS pk
 FROM   pg_constraint c
 JOIN   pg_attribute  k ON (k.attrelid, k.attnum) = (c.conrelid, c.conkey[1])
 JOIN   pg_attribute  f ON (f.attrelid, f.attnum) = (c.confrelid, c.confkey[1])
 LEFT   JOIN pg_constraint p  ON p.conrelid = c.conrelid AND p.contype = 'p'
 LEFT   JOIN pg_attribute  pf ON (pf.attrelid, pf.attnum)
                               = (p.conrelid, p.conkey[1])
 WHERE  c.contype   = 'f'
 AND    c.confrelid = 'fk_tbl'::regclass  -- references to this tbl
 AND    f.attname   = 'fk_tbl_id'         -- and only to this column
)
SELECT string_agg(format(
'SELECT %L AS tbl
     , %L AS pk
     , %s::text AS pk_val
     , %L AS fk
     , %L AS ftbl
FROM   %1$s WHERE %4$s IS NULL'
                  , tbl
                  , COALESCE(pk 'NONE')
                  , COALESCE(pk 'NULL')
                  , fk
                  , ftbl), '
UNION ALL
') || ';'
FROM   x;

Tạo một truy vấn như sau:

SELECT 'some_tbl' AS tbl
     , 'some_tbl_id' AS pk
     , some_tbl_id::text AS pk_val
     , 'fk_tbl_id' AS fk
     , 'fk_tbl' AS ftbl
FROM   some_tbl WHERE fk_tbl_id IS NULL
UNION ALL
SELECT 'other_tbl' AS tbl
     , 'other_tbl_id' AS pk
     , other_tbl_id::text AS pk_val
     , 'some_name_id' AS fk
     , 'fk_tbl' AS ftbl
FROM   other_tbl WHERE some_name_id IS NULL;

Tạo ra đầu ra như thế này:

    tbl    |     pk       | pk_val |    fk        |  ftbl
-----------+--------------+--------+--------------+--------
 some_tbl  | some_tbl_id  | 49     | fk_tbl_id    | fk_tbl
 some_tbl  | some_tbl_id  | 58     | fk_tbl_id    | fk_tbl
 other_tbl | other_tbl_id | 66     | some_name_id | fk_tbl
 other_tbl | other_tbl_id | 67     | some_name_id | fk_tbl
  • Không bao gồm khóa ngoại hoặc khóa chính nhiều cột một cách đáng tin cậy . Bạn phải làm cho truy vấn phức tạp hơn cho việc này.

  • Tôi truyền tất cả các giá trị khóa chính thành text để bao gồm tất cả các loại.

  • Điều chỉnh hoặc loại bỏ các dòng này để tìm khóa ngoại trỏ đến khóa khác hoặc bất kỳ cột / bảng:

    AND    c.confrelid = 'fk_tbl'::regclass
    AND    f.attname = 'fk_tbl_id' -- and only this column
    
  • Đã thử nghiệm với PostgreSQL 9.1.4. Tôi sử dụng pg_catalog những cái bàn. Trên thực tế, không có gì tôi sử dụng ở đây sẽ thay đổi, nhưng điều đó không được đảm bảo trên các bản phát hành chính. Viết lại nó bằng các bảng từ information_schema nếu bạn cần nó hoạt động đáng tin cậy qua các bản cập nhật. Điều đó chậm hơn, nhưng chắc chắn.

  • Tôi đã không khử trùng tên bảng trong tập lệnh DML được tạo vì quote_ident() sẽ không thành công với các tên đủ điều kiện giản đồ. Bạn có trách nhiệm tránh những tên bảng có hại như "users; DELETE * FROM users;" . Với một số nỗ lực hơn, bạn có thể truy xuất tên lược đồ và tên bảng riêng biệt và sử dụng quote_ident() .

Giá trị NULL trong các cột được tham chiếu

Giải pháp đầu tiên của tôi thực hiện một điều gì đó khác biệt một cách tinh tế với những gì bạn yêu cầu, bởi vì những gì bạn mô tả (theo tôi hiểu) là không tồn tại. Giá trị NULL là "không xác định" và không thể được tham chiếu. Nếu bạn thực sự muốn tìm các hàng có NULL giá trị trong cột có ràng buộc FK trỏ tới nó (không phải hàng cụ thể có NULL tất nhiên), sau đó truy vấn có thể được đơn giản hóa nhiều:

WITH x AS (
 SELECT c.confrelid::regclass   AS ftbl
       ,quote_ident(f.attname)  AS fk
       ,quote_ident(pf.attname) AS pk
       ,string_agg(c.conrelid::regclass::text, ', ') AS referencing_tbls
 FROM   pg_constraint c
 JOIN   pg_attribute  f ON (f.attrelid, f.attnum) = (c.confrelid, c.confkey[1])
 LEFT   JOIN pg_constraint p  ON p.conrelid = c.confrelid AND p.contype = 'p'
 LEFT   JOIN pg_attribute  pf ON (pf.attrelid, pf.attnum)
                               = (p.conrelid, p.conkey[1])
 WHERE  c.contype = 'f'
 -- AND    c.confrelid = 'fk_tbl'::regclass  -- only referring this tbl
 GROUP  BY 1, 2, 3
)
SELECT string_agg(format(
'SELECT %L AS ftbl
     , %L AS pk
     , %s::text AS pk_val
     , %L AS fk
     , %L AS referencing_tbls
FROM   %1$s WHERE %4$s IS NULL'
                  , ftbl
                  , COALESCE(pk, 'NONE')
                  , COALESCE(pk, 'NULL')
                  , fk
                  , referencing_tbls), '
UNION ALL
') || ';'
FROM   x;

Tìm tất cả các hàng như vậy trong toàn bộ cơ sở dữ liệu (đã nhận xét hạn chế đối với một bảng). Đã thử nghiệm với Postgres 9.1.4 và phù hợp với tôi.

Tôi nhóm nhiều bảng tham chiếu cùng một cột ngoại thành một truy vấn và thêm danh sách các bảng tham chiếu để cung cấp một cái nhìn tổng quan.



  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ền nhiều giá trị trong một tham số

  2. PostgreSQL xóa tất cả trừ các bản ghi cũ nhất

  3. Thực hiện nâng cấp alembic trong nhiều lược đồ

  4. SQLalchemy không thực hiện các thay đổi khi thiết lập vai trò

  5. Thay đổi các cột PostgreSQL được sử dụng trong các dạng xem