调用函数,其中参数是(子)选择语句

Bei*_*eig 10 postgresql subquery set-returning-functions

我的函数接受一个int4作为参数并返回一个表:

SELECT * FROM test_function(545421); -- works fine

SELECT * FROM test_function(SELECT customerid
                            FROM tableX where id = 1); -- syntax error
Run Code Online (Sandbox Code Playgroud)

我怎样才能使这项工作?
服务器 PostgreSQL 9.3.1

Erw*_*ter 16

1.子查询表达式

您可以使用括号修复它,如@a_horse评论:

SELECT * FROM test_function((SELECT customerid FROM tableX where id = 1));
Run Code Online (Sandbox Code Playgroud)

但这种形式相当容易出错。代码中没有任何内容保证子选择只返回单行。我们不知道是否id唯一,Postgres也不知道(除非它查找系统目录)。我们必须依靠它并希望它不会破裂。

我们可以添加LIMIT 1以确保,但我们可能还应该添加ORDER BY以获得确定性结果......

2. JOIN LATERAL

这个(Postgres 9.3 +)的现代语法将是一个LATERAL连接:

SELECT f.* 
FROM   tableX t, test_function(t.customerid) f
WHERE  t.id = 1;
Run Code Online (Sandbox Code Playgroud)

这是以下的简短语法:

SELECT f.* 
FROM   tableX t
CROSS  JOIN LATERAL test_function(t.customerid) f
WHERE  t.id = 1;
Run Code Online (Sandbox Code Playgroud)

与上面的结果完全相同,除了一个微妙但可能很重要的区别

    1. 如果tableX没有行t.id = 1,该功能不会被调用和查询不返回任何内容(没有行)。另一方面,如果找到一行customerid IS NULL,则使用NULL输入调用该函数,我们得到该函数为 返回的任何内容NULL
      应该是这样。
    1. 带有子查询表达式的表单无法区分这两种情况。“无行”的结果在同一个NULL值customeridNULLNULL无论哪种方式都可以通过输入调用该函数。
      不是它应该的样子。

LATERAL如果id不是唯一的,查询也不会中断。tableX如果需要,您可以轻松返回其他列。