【问题标题】:Using UNNEST with a JOIN将 UNNEST 与 JOIN 一起使用
【发布时间】:2013-04-09 21:55:25
【问题描述】:

我希望能够在具有许多JOINs 的复杂 SQL 查询中使用 PostgreSQL 中的unnest() 函数。这是示例查询:

SELECT 9 as keyword_id, COUNT(DISTINCT mentions.id) as total, tags.parent_id as tag_id
FROM mentions
INNER JOIN taggings ON taggings.mention_id = mentions.id
INNER JOIN tags ON tags.id = taggings.tag_id
WHERE mentions.taglist && ARRAY[9] AND mentions.search_id = 3
GROUP BY tags.parent_id

我想在这里消除taggings 表,因为我的mentions 表有一个名为taglist整数数组 字段,其中包含@ 的所有链接标签ID 987654326@.

我尝试了以下操作:

SELECT 9 as keyword_id, COUNT(DISTINCT mentions.id) as total, tags.parent_id as tag_id 
FROM mentions 
INNER JOIN tags ON tags.id IN (SELECT unnest(taglist))
WHERE mentions.taglist && ARRAY[9] AND mentions.search_id = 3 
GROUP BY tags.parent_id 

这可行,但会带来与第一个查询不同的结果。

所以我想做的是在JOIN 查询中使用SELECT unnest(taglist) 的结果来补偿taggings 表。

我该怎么做?

更新:taglist 与提及的相应标签 ID 列表相同。

【问题讨论】:

  • mentions table has an integer array field named taglist that includes tag ids of mention. 请定义“包含”。 taglist 是否与提及的相应标签 ID 列表完全相同?
  • 是的,taglist 与提及的相应标签 ID 列表相同。我正在更新我的问题。

标签: sql postgresql join naming-conventions unnest


【解决方案1】:

从技术上讲,您的查询可能会这样工作(不完全确定此查询的目标):

SELECT 9 AS keyword_id, count(DISTINCT m.id) AS total, t.parent_id AS tag_id
FROM  (
    SELECT  unnest(m.taglist) AS tag_id
    FROM    mentions m
    WHERE   m.search_id = 3
    AND     9 = ANY (m.taglist)
    ) m 
JOIN   tags t  USING (tag_id) -- assumes tag.tag_id!
GROUP  BY t.parent_id;

但是,在我看来,您在这里走错了方向。通常会删除冗余数组taglist 并保留规范化的数据库模式。那么你的原始查询应该很好用,只是用别名缩短了语法:

SELECT 9 AS keyword_id, count(DISTINCT m.id) AS total, t.parent_id AS tag_id
FROM   mentions m
JOIN   taggings mt ON mt.mention_id = m.id
JOIN   tags     t  ON t.id = mt.tag_id
WHERE  9 = ANY (m.taglist)
AND    m.search_id = 3
GROUP  BY t.parent_id;

解开谜团

<rant> 您的“不同结果”的根本原因是一些智力受到挑战的 ORM 强加给人们的不幸命名约定。
我说的是<b><strike>id</strike></b> 作为列名。切勿在具有多个表的数据库中使用此反模式。对,这基本上意味着 any 数据库。一旦你加入一堆表(这就是你在数据库中的操作),你最终会得到一堆名为id 的列。完全没有意义。
名为 tag 的表的 ID 列应为 tag_id(除非有其他描述性名称)。从不id&lt;/rant&gt;

您的查询无意中计入tags 而不是mentions

SELECT 25 AS keyword_id, count(m.id) AS total, t.parent_id AS tag_id
FROM  (
    SELECT unnest(m.taglist) AS id
    FROM   mentions m
    WHERE  m.search_id = 4
    AND    25 = ANY (m.taglist)
    ) m
JOIN   tags t USING (id)
GROUP  BY t.parent_id;

它应该这样工作:

SELECT 25 AS keyword_id, count(DISTINCT m.id) AS total, t.parent_id
FROM  (
    SELECT m.id, unnest(m.taglist) AS tag_id
    FROM   mentions m
    WHERE  m.search_id = 4
    AND    25 = ANY (m.taglist)
    ) m
JOIN   tags t ON t.id =  m.tag_id
GROUP  BY t.parent_id;

我还将DISTINCT 添加回您的count(),在您的查询过程中丢失了。

【讨论】:

  • 当我尝试运行您的第一个查询时,我收到以下错误:ERROR: column "tag_id" specified in USING clause does not exist in right table
  • 好的,我将代码更改为以下代码并且它可以工作:SELECT 25 AS keyword_id, count(m.id) AS total, t.parent_id AS tag_id FROM ( SELECT unnest(m.taglist) AS id FROM mentions m WHERE m.search_id = 4 AND 25 = ANY (m.taglist) ) m JOIN tags t USING (id) GROUP BY t.parent_id; 但它再次生成与原始查询不同的结果。
  • 很好的解释。感谢您的宝贵时间。
【解决方案2】:

这样的事情应该可以工作:

...
tags t INNER JOIN
(SELECT UNNEST(taglist) as idd) a ON t.id = a.idd
...

【讨论】:

    猜你喜欢
    • 2016-06-03
    • 2016-02-01
    • 2015-02-15
    • 2018-08-02
    • 1970-01-01
    • 2012-01-27
    • 1970-01-01
    • 2022-08-17
    • 2021-04-03
    相关资源
    最近更新 更多