在GROUP BY之后获取多个表的“最新”行

时间:2012-11-29 13:41:03

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

我最好先查看下面列出的查询,然后按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。我希望根据file获得每个故事的最新panels.updated_at

   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

2 个答案:

答案 0 :(得分: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 BYp.updated_at DESC的效果是每个故事都会选择“最新”file。在这个相关问题下完整地解释了查询技术:
Select first row in each GROUP BY group?

答案 1 :(得分:0)

你可以这样写:

   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"只能获得1条记录。

添加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"

只会留一行