我正在编写一个 perl 脚本,我需要在其中运行更新查询。但是我需要检查 update sql 命令是否不违反唯一键约束。
因此,如果我有一个表 tb(C1,C2,C3)
并且我的更新查询如下:
update tb set C1='b1' where C2='a1' ;
有没有一种方法可以在 尝试更新之前,确定 C1,C2
列是否存在唯一键约束?即:UNIQUE(C1,C2)
。
最佳答案
可以查询system catalogs对于唯一约束,特别是 pg_constraint
和 pg_attribute
:
SELECT c.conname, pg_get_constraintdef(c.oid)
FROM pg_constraint c
JOIN (
SELECT array_agg(attnum::int) AS attkey
FROM pg_attribute
WHERE attrelid = 'tb'::regclass -- table name optionally schema-qualified
AND attname = ANY('{c1,c2}')
) a ON c.conkey::int[] <@ a.attkey AND c.conkey::int[] @> a.attkey
WHERE c.contype = 'u'
AND c.conrelid = 'tb'::regclass;
object identifer type
regclass
有助于明确识别您的 table 。系统目录信息函数
pg_get_constraintdef()
获取格式良好的信息,这对于您的请求而言并非绝对必要。同时使用 array operators
<@
和@>
确保数组完全匹配。 (列的顺序未知。)系统列是smallint
和smallint[]
分别。转换到integer
使其与这些运营商合作。直接在系统目录中查找时,列名区分大小写。如果你没有双引号
C1
和C2
在创建时,你必须使用c1
和c2
在这种情况下。也可能有一个多列主键约束 强制唯一性。要在查询中覆盖它,请改用:
WHERE c.contype IN ('u', 'p')
建立在@Roman 的 fiddle 上,这个也演示了 pk 案例:
唯一索引
以上两个(unique & pk constraints)都是通过unique index的方式实现的。此外,还可以有唯一索引有效地与正式声明的唯一约束相同。要捕获所有,请查询系统目录 pg_index
相反,以类似的方式:
SELECT c.relname AS idx_name
FROM (
SELECT indexrelid, string_to_array(indkey::text, ' ')::int[] AS indkey
FROM pg_index
WHERE indrelid = 'tb'::regclass
AND indisunique -- contains "indisprimary"
) i
JOIN (
SELECT array_agg(attnum::int) AS attkey
FROM pg_attribute
WHERE attrelid = 'tb'::regclass
AND attname = ANY('{c1,c2}')
) a ON i.indkey <@ a.attkey AND i.indkey @> a.attkey
JOIN pg_class c ON c.oid = i.indexrelid;
这里的特殊困难是内部类型 int2vector
.我通过转换文本并转换为 int[]
来处理它.
请注意,目录表的实现可能会因专业而异。这些查询不太可能中断,但有可能。
关于sql - 如何查找给定列是否存在唯一键约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20087259/