如果外键不存在,如何创建外键?

Art*_*lin 12 postgresql postgresql-9.1

我正在使用PostgreSQL 9.1.

我有一个表common.client_contact,我使用此代码创建外键:

ALTER TABLE common.client_contact 
ADD FOREIGN KEY (contact_id) REFERENCES common.contact_item(id);
Run Code Online (Sandbox Code Playgroud)

如果我执行这个代码,我会用不同的名称(如一些外国键client_contact_contact_id_fkey1,client_contact_contact_id_fkey2,client_contact_contact_id_fkey3等).

因此,在创建新约束之前,我需要检查它是否存在.

我检查pg_constraint表中是否存在此约束:

SELECT * FROM pg_constraint WHERE conname = 'client_contact_contact_id_fkey'
Run Code Online (Sandbox Code Playgroud)

现在我需要将它们组合在一起.就像是

IF NOT EXISTS
    (SELECT * FROM pg_constraint WHERE conname = 'client_contact_contact_id_fkey')
ALTER TABLE common.client_contact
    ADD CONSTRAINT client_contact_contact_id_fkey
    FOREIGN KEY (contact_id) REFERENCES common.contact_item(id)
Run Code Online (Sandbox Code Playgroud)

要不就

ALTER TABLE common.client_contact 
ADD FOREIGN KEY IF NOT EXISTS (contact_id) REFERENCES common.contact_item(id)
Run Code Online (Sandbox Code Playgroud)

但是这两个查询都会产生语法错误.那么,我怎么能在PostgreSQL中做到这一点?

Cra*_*ger 20

使用DO块在PL/PgSQL中执行它.

DO $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'client_contact_contact_id_fkey') THEN
        ALTER TABLE common.client_contact
            ADD CONSTRAINT client_contact_contact_id_fkey
            FOREIGN KEY (contact_id) REFERENCES common.contact_item(id);
    END IF;
END;
$$;
Run Code Online (Sandbox Code Playgroud)

您似乎依赖于默认约束名称生成,这不是理想的.使用它information_schema来检查是否存在链接两列的约束可能更安全.

以下查询检查两个表之间的外键,而不依赖于生成的约束名称:

SELECT 1
FROM information_schema.table_constraints tc 
INNER JOIN information_schema.constraint_column_usage ccu 
  USING (constraint_catalog, constraint_schema, constraint_name) 
INNER JOIN information_schema.key_column_usage kcu 
  USING (constraint_catalog, constraint_schema, constraint_name) 
WHERE constraint_type = 'FOREIGN KEY' 
  AND ccu.table_name = 'contact_item' 
  AND ccu.table_schema = 'common'  
  AND ccu.column_name = 'contact_id' 
  AND tc.table_schema = 'common' 
  AND tc.table_name = 'client_contact'
  AND kcu.column_name = 'id';
Run Code Online (Sandbox Code Playgroud)


小智 6

解决您遇到的问题的一种方法是在创建约束之前删除它

ALTER TABLE common.client_contact DROP CONSTRAINT IF EXISTS  client_contact_contact_id_fkey; 

ALTER TABLE common.client_contact
    ADD CONSTRAINT client_contact_contact_id_fkey
    FOREIGN KEY (contact_id) REFERENCES common.contact_item(id)
Run Code Online (Sandbox Code Playgroud)

添加命名约束将通过。