我正在处理perl脚本,我需要运行更新查询。但我需要检查更新sql命令是否违反唯一键约束。
所以,如果我有一个表tb(C1,C2,C3)
,我的更新查询就像:
update tb set C1='b1' where C2='a1' ;
在尝试更新之前,有没有办法找到列C1,C2
是否存在唯一键约束?即:UNIQUE(C1,C2)
。
答案 0 :(得分:5)
您可以在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
有助于明确识别您的表格。
系统目录信息功能pg_get_constraintdef()
为您提供格式良好的信息,这对您的请求并非绝对必要。
还使用array operators <@
和@>
来确保数组完全匹配。 (列的顺序未知。)系统列分别为smallint
和smallint[]
。转换为integer
以使其与这些运营商一起使用。
直接在系统目录中查找列名称区分大小写。如果您在创建时没有引用C1
和C2
,则必须在此上下文中使用c1
和c2
。
还可能存在多列主键约束强制唯一性。要在查询中使用,请改为使用:
WHERE c.contype IN ('u', 'p')
在@ Roman的小提琴的基础上,这个也演示了pk案例:
<强> ->SQLfiddle 强>
以上两者(唯一和pk约束)都是通过唯一索引实现的。此外,还可以有唯一索引与正式声明的唯一约束有效地相同。要抓住所有人,请以类似的方式查询系统目录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[]
处理它。
请注意,目录表的实现可能会在主要内容中发生变化。不太可能这些查询中断,但可能。
答案 1 :(得分:1)
您可以通过检查pg_catalog.pg_constraint
表来查明约束是否存在(不可移植),但这不会告诉您插入是否会违反约束 ,即使可能,也很容易发生比赛。
正确的做法是尝试插入并适当地处理故障。