【问题标题】:Get "latest" row after GROUP BY over multiple tables在多个表的 GROUP BY 之后获取“最新”行
【发布时间】:2012-11-17 14:31:29
【问题描述】:

我最好先查询下面列出的查询,然后按stories.id 分组,但我收到以下错误:

ERROR: column "u.first_name" must appear in the GROUP BY clause or be used in an aggregate function LINE 1: SELECT "s".*, "u"."first_name", "u"."last_name", ("i"."filen...

第二个查询有效,但没有按stories.id 分组,并生成错误的结果。是否可以从多个表中选择而不是全部分组?

panels 也有一个列updated_at。我想根据panels.updated_at 获取每个故事的最新file

   SELECT 
        "s".*, 
        "u"."first_name", 
        "u"."last_name", 
        ("i"."filename" || '.' || "i"."extension") AS "file" 
    FROM 
        "stories" "s" 
    LEFT JOIN "panels" "p" ON("p"."story_id" = "s"."id") 
    LEFT JOIN "users" "u" ON("s"."user_id" = "u"."uid")
    LEFT JOIN "images" "i" ON ("p"."image_id" = "i"."id") 
    WHERE 
        "s"."complete" = false AND 
        "s"."created_by" = 205700489 
    GROUP BY 
        "s"."id", 
    ORDER BY 
        "s"."created_at" DESC

   SELECT 
        "s".*, 
        "u"."first_name", 
        "u"."last_name", 
        ("i"."filename" || '.' || "i"."extension") AS "file" 
    FROM 
        "stories" "s" 
    LEFT JOIN "panels" "p" ON("p"."story_id" = "s"."id") 
    LEFT JOIN "users" "u" ON("s"."user_id" = "u"."uid")
    LEFT JOIN "images" "i" ON ("p"."image_id" = "i"."id") 
    WHERE 
        "s"."complete" = false AND 
        "s"."created_by" = 205700489 
    GROUP BY 
        "s"."id", 
        "u"."first_name", 
        "u"."last_name", "i"."filename", 
        "i"."extension" 
    ORDER BY 
        "s"."created_at" DESC

【问题讨论】:

  • 第二次查询的结果怎么错了?
  • @Igor Romanchenko 它不按故事 ID 分组
  • 您的问题没有定论。如果您想按story.id 分组,您必须定义要从多行中选择的内容。

标签: sql postgresql greatest-n-per-group postgresql-9.1 rails-postgresql


【解决方案1】:

你可以这样写:

   SELECT 
        "s".*, 
        (SELECT "u"."first_name" 
         FROM "users" "u"
         WHERE "s"."user_id" = "u"."uid"
         LIMIT 1) , 
        (SELECT "u"."last_name" 
         FROM "users" "u"
         WHERE "s"."user_id" = "u"."uid"
         LIMIT 1), 
        (SELECT "i"."filename" || '.' || "i"."extension"
         FROM "panels" "p" 
         JOIN "images" "i" ON ("p"."image_id" = "i"."id")
         WHERE "p"."story_id" = "s"."id" 
         LIMIT 1) AS "file" 
    FROM 
        "stories" "s" 
    WHERE 
        "s"."complete" = false AND 
        "s"."created_by" = 205700489 
    ORDER BY 
        "s"."created_at" DESC

它只会从 "users""panels" JOIN "images" 中获得一条记录 "stories" 中的每条记录。

添加ORDER BY、额外的WHERE 或一些聚合以从"users""panels" JOIN "images" 获得您需要的内容

UPD 另外,您可以使用以下内容:

SELECT *
FROM (
SELECT DISTINCT ON ("s"."id") 
    "s".*, 
    "u"."first_name", 
    "u"."last_name", 
    ("i"."filename" || '.' || "i"."extension") AS "file" 
FROM 
    "stories" "s" 
LEFT JOIN "panels" "p" ON("p"."story_id" = "s"."id") 
LEFT JOIN "users" "u" ON("s"."user_id" = "u"."uid")
LEFT JOIN "images" "i" ON ("p"."image_id" = "i"."id") 
WHERE 
    "s"."complete" = false AND 
    "s"."created_by" = 205700489 
ORDER BY 
    "s"."id"
) t ORDER BY "t"."created_at" DESC

对于每个不同的"s"."id",它将只留下一行

【讨论】:

  • 使用这么多子选择有性能差异吗?
  • @stefan 大多数时候postgres会优化查询,所以不会有太大的性能差异。
  • @stefan:通常,相关子查询是性能的反模式。如果可以,请避免使用它们。但是正如@Igor 提到的,Postgres 可以在有利的条件下优化查询计划。使用EXPLAIN ANALYZE 测试您的查询并进行比较以获得明确的答案。多次运行以排除缓存效果。
【解决方案2】:

澄清问题后更新:

SELECT DISTINCT ON (s.created_at, s.id)
       s.*
      ,u.first_name
      ,u.last_name
      ,concat_ws('.', i.filename, i.extension) AS file
FROM   stories s 
LEFT   JOIN users  u ON u.uid = s.user_id
LEFT   JOIN panels p ON p.story_id = s.id
LEFT   JOIN images i ON i.id = p.image_id
WHERE  s.complete = false
AND    s.created_by = 205700489 
ORDER  BY s.created_at DESC, s.id, p.updated_at DESC;

Grouping by primary key 需要 PostgreSQL 9.1。
我使用concat_ws(),因为我不知道哪些列可能是NULL。如果i.filenamei.extension 都定义为NOT NULL,则可以简化。

附加ORDER BY 项目p.updated_at DESC 的效果是每个故事都会选择“最新”file。查询技术在这个相关问题下有完整的解释:
Select first row in each GROUP BY group?

【讨论】:

  • 这个查询工作正常,除了我得到一个文件列表97799.jpg, 5234.jpg 我真正在寻找的是最后一个文件面板有一个顺序并按列创建,我只需要最新的。
  • @stefan:您需要编辑您的问题并将所有信息放在那里。这是一个公共论坛,一个问题应该描绘一个完整的画面。评论根本不够好。在您的问题下方使用edit
猜你喜欢
  • 2017-09-03
  • 1970-01-01
  • 2018-07-14
  • 1970-01-01
  • 2016-05-15
  • 1970-01-01
  • 2020-09-23
  • 2021-11-21
相关资源
最近更新 更多