【问题标题】:Select from PostgreSQL function that returns composite type从返回复合类型的 PostgreSQL 函数中选择
【发布时间】:2011-05-16 03:31:34
【问题描述】:

如何在SELECT 中包含返回复合类型的函数?
我有复合类型:

CREATE TYPE public.dm_nameid AS (
  id   public.dm_int,
  name public.dm_str
);

另外,我有一个返回这种类型fn_GetLinkedProject(integer)的函数。 我需要做这样的事情:

SELECT 
    p.id, p.data, p.name, 
    pl.id linked_id, pl.name linked_name
FROM tb_projects p
   left join "fn_GetLinkedProject"(p.id) pl

我该怎么做?

我已经阅读了this 的文章。

我不想要以下方法:

SELECT
 p.id, p.data, p.name, 
    (select pl1.id from "fn_GetLinkedProject"(p.id) pl1 ) linked_id,
    (select pl2.name from "fn_GetLinkedProject"(p.id) pl2 ) linked_name
FROM tb_projects p

【问题讨论】:

  • 那么这个老问题得到了正确的回答吗?

标签: sql postgresql left-join composite lateral-join


【解决方案1】:

Postgres 9.3 或更高版本

使用LATERAL 加入!

SELECT p.id, p.name, p.data, f.*
FROM   tb_projects p
LEFT   JOIN LATERAL fn_getlinkedproject(p.id) f(linked_id, lined_name) ON TRUE;

结果:

 id |  data  |  name  | linked_id | linked_name
----+--------+--------+-----------+-------------
  1 | data_1 | name_1 |         2 | name_2
  2 | data_2 | name_2 |         3 | name_3
  3 | data_3 | name_3 |         1 | name_1

见:

Postgres 9.2 或更早版本

劣质有几个原因。附加列别名并不那么简单。而是重命名其他冲突的名称:

SELECT p.id AS p_id, p.data AS p_data, p.name AS p_name, (fn_getlinkedproject(p.id)).*
FROM   tb_projects p;

结果:

 p_id | p_data | p_name | id |  name
------+--------+--------+----+--------
    1 | data_1 | name_1 |  2 | name_2
    2 | data_2 | name_2 |  3 | name_3
    3 | data_3 | name_3 |  1 | name_1

重命名结果列,您必须:

SELECT p.id, p.data, p.name
     ,(fn_getlinkedproject(p.id)).id   AS linked_id
     ,(fn_getlinkedproject(p.id)).name AS linked_name
FROM   tb_projects p;

两种旧的解决方案都解决了重复调用函数的相同(不良)查询计划。

为避免这种情况,请使用子查询:

SELECT p.id, p.data, p.name
    , (p.x).id AS linked_id, (p.x).name AS linked_name
FROM  (SELECT *, fn_getlinkedproject(id) AS x FROM tb_projects) p;

注意基本括号的位置。
阅读manual about composite types

演示

CREATE TYPE dm_nameid AS (
  id   int
, name text); -- types simplified for demo

CREATE TABLE tb_projects(
  id   int
, data text
, name text);

INSERT INTO tb_projects VALUES
  (1, 'data_1', 'name_1')
, (2, 'data_2', 'name_2')
, (3, 'data_3', 'name_3');

CREATE function fn_getlinkedproject(integer)  -- avoiding CaMeL-case for demo
  RETURNS dm_nameid LANGUAGE sql AS
'SELECT id, name FROM tb_projects WHERE id = ($1 % 3) + 1';

db小提琴here

【讨论】:

  • 你应该再等几个星期 :)
  • @muistooshort:一年后有特别奖励吗?
  • 我不知道,最接近的是revival and necromancer,我只是觉得在问题的第一个生日前几分钟得到答案会很有趣。
  • @muistooshort:该死,你是对的。一个生日快乐的答案! :) 那艘船现在正在航行。 :´(
猜你喜欢
  • 2020-08-03
  • 2014-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-03
  • 1970-01-01
  • 2012-08-10
  • 1970-01-01
相关资源
最近更新 更多