15

我正在使用 PostgreSQL 9.1。

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

ALTER TABLE common.client_contact 
ADD FOREIGN KEY (contact_id) REFERENCES common.contact_item(id);

如果我执行此代码,我将获得几个具有不同名称的外键(如client_contact_contact_id_fkey1client_contact_contact_id_fkey2client_contact_contact_id_fkey3)。

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

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

SELECT * FROM pg_constraint WHERE conname = 'client_contact_contact_id_fkey'

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

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)

要不就

ALTER TABLE common.client_contact 
ADD FOREIGN KEY IF NOT EXISTS (contact_id) REFERENCES common.contact_item(id)

但是这两个查询都会产生语法错误。那么,我该如何在 PostgreSQL 中做到这一点?

4

3 回答 3

27

Use a DO block to execute it in 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;
$$;

You seem to be relying on the default constraint name generation, which isn't ideal. It's probably safer to use information_schema to check for the presence of a constraint that links the two columns.

The following query checks for a foreign key between the two tables without relying on the generated constraint name:

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';
于 2012-10-12T09:15:44.503 回答
7

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

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)

添加命名约束将通过。

于 2017-04-03T18:33:53.940 回答
-7

我不确定这是否可行,但您可以尝试一下。

在执行查询之前触发

SET FOREIGN_KEY_CHECKS=0

然后您进行查询并

SET FOREIGN_KEY_CHECKS=1
于 2012-10-12T09:14:18.960 回答