PostgreSQL - 执行SELECT时检查外键是否存在

时间:2015-03-19 21:17:40

标签: sql postgresql foreign-keys

假设我有以下数据:

some_table

some_table_id | value | other_table_id
--------------------------------------
1             | foo   | 1
2             | bar   | 2

other_table

other_table_id | value
----------------------
1              | foo
2              | bar

此处,some_tableother_table_idother_table的外键到某个名称的列。

在PostgreSQL中使用以下查询:

SELECT * 
FROM some_table 
WHERE other_table_id = 3;

如您所见,3中不存在other_table此查询显然会返回0结果。

不进行第二次查询,是否有办法知道other_table中是否存在我作为过滤器有效使用的外键?

理想情况下,作为以后可以解析的错误(例如,在使用错误的外键执行INSERTUPDATE时发生的错误)。

2 个答案:

答案 0 :(得分:4)

您可以利用PL / pgSQL的功能实现 非常便宜

CREATE OR REPLACE FUNCTION f_select_from_some_tbl(int)
  RETURNS SETOF some_table AS
$func$
BEGIN
   RETURN QUERY
   SELECT * 
   FROM   some_table 
   WHERE  other_table_id = $1;

   IF NOT FOUND THEN
      RAISE WARNING 'Call with non-existing other_table_id >>%<<', $1;
   END IF;
END
$func$  LANGUAGE plpgsql;

在这种情况下,最终RETURN;是可选的。

仅当您的查询未返回任何行时才会引发WARNING。我没有在示例中提出ERROR,因为这会回滚整个事务(但如果符合您的需要,您可以这样做)。

我们添加了一个代码示例to the manual with Postgres 9.3来证明这一点。

答案 1 :(得分:2)

如果您在INSERT上执行UPDATEsome_table,请指定other_table_id中实际上不存在的other_table值,那么您将获得违反外键约束引起的错误。因此,SELECT查询是您最关心的问题。

使用SELECT查询解决问题的一种方法是将查询转换为使用other_table执行外部联接,如下所示:

SELECT st.* 
FROM
  other_table ot
  LEFT JOIN some_table st ON st.other_table_id = ot.other_table_id
WHERE st.other_table_id = 3;

如果other_table行有other_table_id = 3,那么该查询将始终返回至少一行。在这种情况下,如果没有匹配的some_table行,那么它将只返回一行,该行包含所有列NULL(假设它只选择some_table中的列),甚至声明为非空的列。

如果您希望此类查询引发错误,那么您可能需要编写自定义函数来协助,但可以完成。我可能会使用该语言的RAISE语句在PL / pgSQL中实现它。