从返回表(或记录集)的函数中检索列

Posted

技术标签:

【中文标题】从返回表(或记录集)的函数中检索列【英文标题】:Retrieval of columns from functions that returns table (or setof record) 【发布时间】:2016-03-17 15:54:43 【问题描述】:

一直以来我都有这个问题的变体,不记得如何解决,只有“oop 是如此简单,但如何?”......也许有一些模式和处理每种模式的最佳方法。让我们看看主要的,以unnest()ts_stat() 为例。

首先,好的例子,没有问题,因为unnest()只返回一列:

SELECT * FROM unnest(array[1,2,3]) t(id); -- is ok, the int columns there!
SELECT unnest(array[1,2,3]) t(id); -- is ok, the int columns

WITH t AS (SELECT unnest(array[1,2,3]) as id)
 SELECT id, unnest(array[4,id]) as x
 FROM t;  -- more complex, but ok!

现在是一个返回已定义SETOF RECORD的函数,

SELECT * FROM ts_stat('SELECT kx FROM terms where id=2') -- GOOD
-- show all word|ndoc|nentry columns

SELECT ts_stat('SELECT kx FROM terms where id=2') as x -- BAD
-- because lost columns, show only "x" column... but works

-- NOTE: you can imagine any other function, as json_each(), etc.

查看好/坏注意事项...所以,这就是问题:包含多于一列的 SETOF RECORD。在最简单的情况下(上面的unnest),解决方案是在“FROM 端”中使用,作为表格;但是,当 RECORD 有多个字段时,就会出现问题。

--MAIN EXAMPLE FOR THE DISCUSSION:
WITH t AS (SELECT unnest(array[1,2,3]) as id)
 SELECT id, ts_stat('SELECT kx FROM terms where id='||id) as x
 FROM t;  -- BAD, but works...

现在,在这个主要示例中,不可能在“FROM 端”中使用ts_stat(),因此,表征模式返回 TABLE 或 SETOF 的函数记录,在我们需要列的查询中,但函数不能在“FROM 端”

问题:这个模式的通用(也是最优雅的)解决方案是什么?如何(语法模式)显示列?


注意:另一个问题是,如果你不记得确切的解决方案的语法,你会尝试一些不起作用的东西......在这种情况下会出现错误:

WITH t AS (SELECT unnest(array[1,2,3]) as id)
 SELECT id, x.word, x.ndoc, x.nentry 
 FROM (
      SELECT t.nsid, 
             ts_stat('SELECT kx FROM terms where id='||id) as x
      FROM t
  ) s;

SQL PARSER ERROR (PostgreSQL 9.5): FROM 子句中没有表“x”

【问题讨论】:

【参考方案1】:

您应该永远不要SELECT 列表中使用 set-returning-function (SRF)。主要示例应使用隐式LATERAL JOIN

SELECT v.id, x.*
FROM (VALUES (1),(2),(3)) v(id)
JOIN ts_stat('SELECT kx FROM terms where id=' || v.id) x ON true;

lateral join 在这里是隐含的,因为 SRF 可以在不使用关键字 LATERAL 的情况下引用 FROM 子句之前指定的关系中的列。在上面的示例中,SRF ts_stat() 横向引用列和关系 v(id)。您也可以使用例如子查询,但您必须明确使用关键字LATERAL

请注意,虽然您可以在选择列表中使用 SRF,但不鼓励使用它。您提供了unnest(anyarray) 的示例,这很有趣,因为还有重载变体unnest(anyarray, ...)(即在一次调用中取消嵌套多个数组)在选择列表中使用时会引发错误; in 只能用作行源。不应在选择列表中使用 SRF 的原因是,在使用多个 SRF 时没有明显的解决方案,每个 SRF 产生不同的行数。

【讨论】:

好(!),这是“解决方案模式”。并且“永远不要在 SELECT 列表中使用 set-returning-function”是一个很好的规则。对于pg9+,不言而喻的理想解决方案是LATERAL JOIN,你能举个例子吗? (将相同的查询转换为横向连接查询) 答案中的示例已经是隐式横向连接。有关更多解释,请参阅更新的答案。 糟糕,抱歉,这个评论问题的正确文本是“你能展示和明确的例子吗?”,使用 LATERAL 子句 ...关于我的NOTE,PARSER ERROR,对你来说似乎是一个解析器BUG? 来吧,彼得。我添加了相关文档的链接并详细说明了横向连接。一点点自助在这里会有很长的路要走。如果您有一个特定与这篇文章相关的问题查看文档之后,那么我很乐意提供帮助,但 SO 不是school。

以上是关于从返回表(或记录集)的函数中检索列的主要内容,如果未能解决你的问题,请参考以下文章

Laravel:按列值检索记录

从Excel vba中的SQL Server数据中检索/创建记录集

从ADODB记录集复制数据时,Excel表丢失数字格式

检索 ADO 记录集字段名称(经典 ASP)

是否释放记录集返回的 BSTR

oracle 如何返回多条记录