当前位置: 首页 > 面试题库 >

将函数返回的记录拆分为多列

华永逸
2023-03-14
问题内容

在基本的Postgres函数教程中,有一个带有如下OUT参数的示例:

create or replace function hi_lo(a numeric, 
                                 b numeric, 
                                 c numeric, 
                                 OUT hi numeric, 
                                 OUT lo numeric)
as $$
begin
hi := greatest(a, b, c);
lo := least(a, b, c);
end; $$
language plpgsql;

然后结果看起来像

select hi_lo(2, 3, 4);
-- returns one column, "hi_lo" with value "(4, 2)".

select * from hi_lo(2, 3, 4);
-- returns two columns, "hi" / 4 and "lo" / 2.

但是,假设您要在执行连接所产生的列上执行该函数,并且您无权修改该函数或使用替代函数?例如,使用一些玩具数据

select hi_lo(a.actor_id, length(a.name), ma.movie_id) 
from 
    actors a 
join 
    movies_actors ma 
on 
    a.actor_id = ma.movie_id 
limit 10;

在单列“ hi_lo”中返回具有2元组值的结果。

将查询括在括号中并尝试从中查询select *不会更改输出的格式。所以

select *
from (
    select hi_lo(a.actor_id, length(a.name), ma.movie_id) 
    from 
        actors a 
    join 
        movies_actors ma 
    on 
        a.actor_id = ma.movie_id 
    limit 10;
) rr

不会影响结果形状。

以下尝试导致错误“子查询必须仅返回一列”

select (
    select * from hi_lo(a.actor_id, length(a.name), ma.movie_id)
) 
from 
    actors a 
join 
    movies_actors ma 
on
    a.actor_id = ma.movie_id 
limit 10;

最后,我也尝试过,unnest但是由于元组值不被视为数组,因此它给出了一个参数类型错误。

无法将函数求值移至该from部分时,如何在输出中获得多列?


问题答案:

在Postgres 9.3 或更高版本中,最好通过联接来解决LATERAL

SELECT *
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
LEFT   JOIN LATERAL hi_lo(a.actor_id, length(a.name), ma.movie_id) x ON true
LIMIT  10;

避免重复评估函数(对于输出中的每一列-必须以任何一种方式为每个输入行调用该函数)。
LEFT JOIN LATERAL ... ON true如果函数不返回行,则避免从左侧删除行

在您的评论中进行跟进:

仅由函数调用产生的扩展列

SELECT x.*  -- that's all!
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
LEFT   JOIN LATERAL hi_lo(a.actor_id, length(a.name), ma.movie_id) x ON true
LIMIT  10;

但是,由于您不关心其他列,因此可以简化为:

SELECT x.*
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
     , hi_lo(a.actor_id, length(a.name), ma.movie_id) x
LIMIT  10;

这是一个隐式的CROSS JOIN LATERAL。如果函数实际上偶尔会返回“ no
row”,则结果可能会有所不同:我们没有为这些行获取NULL值,这些行被消除了- LIMIT不再计数。

较旧的版本中 (或通常),您也可以使用正确的语法来分解复合类型:

SELECT *, **(** hi_lo(a.actor_id, length(a.name), ma.movie_id) **).***  -- note extra parentheses!
FROM   actors a 
JOIN   movies_actors ma on a.actor_id = ma.movie_id 
LIMIT  10;

缺点是由于Postgres查询计划程序的弱点,该函数对函数输出中的每一列都进行了一次评估。最好将调用移到子查询或CTE中,并在外部分解行类型SELECT。喜欢:

SELECT actor_id, movie_id, (x).*  -- explicit column names for the rest
FROM  (
   SELECT *, hi_lo(a.actor_id, length(a.name), ma.movie_id) AS x
   FROM   actors a 
   JOIN   movies_actors ma on a.actor_id = ma.movie_id 
   LIMIT  10
   ) sub;

但是,您必须命名单个列,SELECT *除非您对结果中的行类型有多余的理解,否则您将无法避免。



 类似资料:
  • 它是这样的: 插入some_table(col1,col2,col3,col4) 选择col1、col2、my_func(col3)为new_col3、col4 现在我需要使用相同的逻辑返回两个值而不是一个值。 我可以简单地编写另一个函数来执行相同的逻辑并返回第二个值,但这将是昂贵的,因为该函数从一个大的历史表中进行选择。 我不能与历史表进行连接,因为该函数没有执行简单的select。

  • 问题内容: 我有一个具有这种结构的表。 我无法弄清楚我将使用哪种SQL查询来获得这样的结果集: 我正在尝试将三列分为三个单独的行。这可能吗? 问题答案: SELECT Y.UserID, Y.UserName, QuestionName = ‘AnswerToQuestion’ + X.Which, Response = CASE X.Which WHEN ‘1’ THEN AnswerToQue

  • 我知道Postgres允许返回预定义的复合数据类型、记录和具有列定义的表。 然而,我没有返回一个定义了列的简单记录,所以我总是使用表,即使我知道这只返回一行。 我的函数定义如下: 如果我尝试以同样的方式返回记录,则返回失败: 这在博士后中不可能吗?我知道我可以只声明一个自定义复合数据类型,但我不想为每个返回记录的函数声明一个类型。

  • 问题内容: 我已经写了这个功能: 哪个有效,并在单列记录类型中返回结果。请注意,可能会返回多于一行。 现在的响应是: 我想获得的结果不是记录,而是多列 有没有一种方法可以从PostgreSQL函数返回多列 问题答案: 我可以通过以下查询看到它:

  • 问题内容: 我已使用从IMDB收集信息并将其传输到MYSQL数据库的应用程序导入了一些数据。 似乎这些字段尚未标准化,并且在1个字段中包含许多值 例如: 有没有办法将这些值分开,然后将它们插入到另一个表中,而不重复呢? 我进行了一些谷歌搜索,发现我应该使用PHP处理此数据。但是我一点都不了解PHP。 无论如何,仅使用MYSQL即可转换此​​数据? 问题答案: 您可以使用存储过程,该过程使用游标来解

  • 下面是一个提供两列结果的函数。 在这个函数中,有一个用于返回结果。 功能: 有没有可能不使用循环就返回行? 如果是这样的话,请与我分享我们如何做到这一点。 我是否能够编写一个函数,在不使用循环的情况下将记录插入到表中? 帮我解决这个问题。 提前谢谢。