具有多个值的数组列上的LEFT OUTER JOIN

具有多个值的数组列上的LEFT OUTER JOIN,第1张

具有多个值的数组列上的LEFT OUTER JOIN
&&
运算符和索引?

没错,重叠运算符

&&
可以在arrays上使用GIN索引。对于以下查询非常有用(在参与者之间查找人为1的行):

SELECt * FROM eg_assoc WHERe actors && '{1}'::int[]

但是 ,查询的逻辑是相反的,查找中的数组中列出的所有人员

eg_assoc
。GIN索引在这里 没有
帮助。我们只需要PK的btree索引
person.id

正确的查询

这不是一个小问题。首先阅读以下内容:

  • PostgreSQL unnest(),元素编号

以下查询将 完全按照给定的 顺序保留原始数组,包括可能重复的元素和元素的原始顺序。适用于 一维数组
。其他尺寸将折叠为一个尺寸。保留多个维度较为复杂(但完全可能):

相关子查询

对于Postgres 8.4+
(已在何处

generate_subsrcipts()
引入):

SELECt aid, actors     , ARRAY( SELECT name   FROM   generate_subscripts(e.actors, 1) i   JOIN   eg_person p ON p.id = e.actors[i]   ORDER  BY i) AS act_names     , benefactors     , ARRAY( SELECt name   FROM   generate_subscripts(e.benefactors, 1) i   JOIN   eg_person p ON p.id = e.benefactors[i]   ORDER  BY i) AS ben_namesFROM   eg_assoc e;

即使在第9.3页中,仍可能表现最佳。
使用比快的数组构造函数

array_agg()

LATERAL
询问

对于PostgreSQL 9.3+

SELECt e.aid, e.actors, a.act_names, e.benefactors, b.ben_namesFROM   eg_assoc e, LATERAL (   SELECt ARRAY( SELECT name      FROM   generate_subscripts(e.actors, 1) i      JOIN   eg_person p ON p.id = e.actors[i]      ORDER  BY i)   ) a(act_names), LATERAL (   SELECt ARRAY( SELECT name      FROM   generate_subscripts(e.benefactors, 1) i      JOIN   eg_person p ON p.id = e.benefactors[i]      ORDER  BY i)   ) b(ben_names);

SQL Fiddle 具有两个变体(第pg 9.4版除外)。

微妙的细节:如果找不到人,则将其遗漏。如果找不到整个数组,则这两个查询都会生成一个 空数组

'{}'
)。其他查询样式将返回
NULL
。我在小提琴中添加了变体。

WITH ORDINALITY
在Postgres 9.4+
SELECt aid, actors     , ARRAY(SELECT name  FROM   unnest(e.actors) WITH ORDINALITY a(id, i)  JOIN   eg_person p USING (id)  ORDER  BY a.i) AS act_names     , benefactors     , ARRAY(SELECt name  FROM   unnest(e.benefactors) WITH ORDINALITY b(id, i)  JOIN   eg_person USING (id)  ORDER  BY b.i) AS ben_namesFROM   eg_assoc e;
查询失败

@a_horse提供
的查询 似乎
可以完成任务,但是它不可靠,具有误导性,可能不正确且不必要地昂贵。

  1. 代理交叉联接,因为有两个不相关的联接。偷偷摸摸的反模式。细节:

    • 两个SQL LEFT JOINS产生不正确的结果

使用

DISTINCT
in固定在表面上,
array_agg()
以消除生成的重复项,但这实际上是在唇膏上涂上了猪。它还 消除了原件中的重复项,
因为此时无法分辨出差异-这可能是不正确的。

  1. 该表达式

    a_person.id = any(eg_assoc.actors)
    有效 ,但会从结果中 消除重复项 (在此查询中发生两次),除非指定,否则是错误的。

  2. 不保留数组元素的 原始 顺序 。一般来说,这很棘手。但这在查询中会加剧,因为参与者和恩人被相乘并再次变得不同,从而 保证了 任意顺序。

  3. 外部没有列别名会

    SELECT
    导致重复的列名,这会使某些客户端失败(在没有别名的小提琴中无法使用)。

  4. min(actors)
    而且
    min(benefactors)
    没有用。通常情况下,只需将列添加到其中,
    GROUP BY
    而不用假汇总它们。但是
    eg_assoc.aid
    无论如何PK列(在中包含整个表
    GROUP BY
    ),所以甚至没有必要。只是
    actors, benefactors

汇总整个结果会浪费时间和精力。使用更智能的查询,而不是将基本行相乘,则不必将它们汇总在一起。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5014063.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-15
下一篇 2022-11-15

发表评论

登录后才能评论

评论列表(0条)

保存