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ụngquote_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.