例子:
我:定義外鍵到目標表的子集
Table A:
int id
int table_b_id
Table B:
int id
text type
我想加上列table_b_id約束檢查將驗證它僅指向表中的行B它們的類型值是'X'。
我無法更改表格結構。
我明白它可以通過'CHECK'和一個postgres函數來完成,它會執行特定的查詢,但我看到有人建議避免它。
關於什麼是實施它的最佳方法的任何輸入將會有所幫助。
例子:
我:定義外鍵到目標表的子集
Table A:
int id
int table_b_id
Table B:
int id
text type
我想加上列table_b_id約束檢查將驗證它僅指向表中的行B它們的類型值是'X'。
我無法更改表格結構。
我明白它可以通過'CHECK'和一個postgres函數來完成,它會執行特定的查詢,但我看到有人建議避免它。
關於什麼是實施它的最佳方法的任何輸入將會有所幫助。
你所指的不是FOREIGN KEY
,在PostgreSQL中,它指的是在其他表中有一列(多個),其中有一個唯一的索引在那個/那些列上,當這些/那些列的值發生變化時(可能有相關的自動操作)(ON UPDATE
,ON DELETE
)。
您試圖執行特定類型的參照完整性,類似於FOREIGN KEY
所做的。您可以使用CHECK
子句和函數(因爲CHECK
子句不允許子查詢)執行此操作,您也可以使用table inheritance and range partitioning(請參閱只包含type = 'X'
的行的子表)執行此操作,但它可能是最簡單的一個觸發做到這一點:
CREATE FUNCTION trf_test_type_x() RETURNS trigger AS $$
BEGIN
PERFORM * FROM tableB WHERE id = NEW.table_b_id AND type = 'X';
IF NOT FOUND THEN
-- RAISE NOTICE 'Foreign key violation...';
RETURN NULL;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE tr_test_type_x
BEFORE INSERT OR UPDATE ON tableA
FOR EACH ROW EXECUTE PROCEDURE trf_test_type_x();
您可以在tableB
創建一個部分索引加快速度:
CREATE UNIQUE INDEX idx_type_X ON tableB(id) WHERE type = 'X';
最優雅的解決方案,在我看來,就是用inheritance獲得子類型的行爲:
PostgreSQL 9.3 Schema Setup with inheritance:
create table B (id int primary key);
-- Instead to create a 'type' field, inherit from B for
-- each type with custom properties:
create table B_X (-- some_data varchar(10),
constraint pk primary key (id)
) inherits (B);
-- Sample data:
insert into B_X (id) values (1);
insert into B (id) values (2);
-- Now, instead to reference B, you should reference B_X:
create table A (id int primary key, B_id int references B_X(id));
-- Here it is:
insert into A values (1, 1);
--Inserting wrong values will causes violation:
insert into A values (2, 2);
ERROR: insert or update on table "a" violates foreign key constraint "a_b_id_fkey" Detail: Key (b_id)=(2) is not present in table "b_x".
檢索從基表所有數據:
select * from B
| id |
|----|
| 2 |
| 1 |
個
與類型檢索數據:
SELECT p.relname, c.*
FROM B c inner join pg_class p on c.tableoid = p.oid
| relname | id |
|---------|----|
| b | 2 |
| b_x | 1 |
感謝您的教育解決方案,但由於我無法更改數據庫模式,它不會解決我目前的問題。這在未來的場景中肯定會很有用。 –
我可以定義一個子表繼承只包括原始錶行的一部分嗎? –