如何在 JSON_AGG 中使用 ORDER BY 和 LIMIT

lra*_*rai 3 postgresql order-by sorting limits group-by

我有一个返回所需输出的查询。

SELECT 
    shop,
    JSON_AGG(item_history.* ORDER BY created_date DESC) as data
FROM item_history
GROUP BY
    shop;
Run Code Online (Sandbox Code Playgroud)

结果:

[
  {
    "shop": "shop1",
    "data": [
      {
        "id": 226,
        "price": "0",
        "shop": "shop1.com",
        "country": "UK",
        "item": "item1",
        "created_date": "2021-06-07T08:48:42.338201",
      },
      {
        "id": 224,
        "price": "0",
        "shop": "shop1.com",
        "country": "UK",
        "item": "item 1",
        "created_date": "2021-06-07T07:53:25.030621",
      },
      ...
  },
  {
    "shop": "shop2",
    "data": [
      {
        "id": 225,
        "price": "0",
        "shop": "shop2.com",
        "country": "DE",
        "item": "Item 2",
        "created_date": "2021-06-07T08:48:36.443849",
      },
      ...
]
Run Code Online (Sandbox Code Playgroud)

这正是我想要的输出,但问题是它获取data数组下的所有项目,最好限制该数组。我尝试添加LIMIT

SELECT 
    shop,
    JSON_AGG(item_history.* ORDER BY created_date DESC LIMIT 5) as data
FROM item_history
GROUP BY
    shop;
Run Code Online (Sandbox Code Playgroud)

但我明白了syntax error at or near "limit"。是否可以限制 的输出JSON_AGG

And*_*y M 6

ORDER BY里面的语法JSON_AGG不接受LIMIT选项。我不知道有什么方法可以以这种方式限制任何聚合函数的范围。作为替代方案,您可以尝试以下ROW_NUMBER+FILTER方法:

  • shop分配分区内的行号
  • 在条件聚合中使用行号。

在 SQL 中它看起来像这样:

SELECT 
    shop,
    JSON_AGG(derived.* ORDER BY created_date DESC) FILTER (WHERE rn <= 5) AS data
FROM
    (
        SELECT
            *,
            ROW_NUMBER() OVER (PARTITION BY shop ORDER BY created_date DESC) AS rn
        FROM
            item_history
    ) AS derived
GROUP BY
    shop;
Run Code Online (Sandbox Code Playgroud)

或者您可以使用 CTE 而不是派生表:

WITH
    cte AS
    (
        SELECT
            *,
            ROW_NUMBER() OVER (PARTITION BY shop ORDER BY created_date DESC) AS rn
        FROM
            item_history
    )
SELECT 
    shop,
    JSON_AGG(cte.* ORDER BY created_date DESC) FILTER (WHERE rn <= 5) AS data
FROM
    cte
GROUP BY
    shop;
Run Code Online (Sandbox Code Playgroud)

结果是相同的。差异(如果有的话)仅在于效率,因为 PostgreSQL 中的 CTE 可能会具体化,而派生表通常不会具体化。您应该亲自测试一下,看看哪个选项更适合您。

注意:在这两种情况下,聚合函数仍然具有相同的ORDER BY,但您现在可以根据需要更改它,或者完全删除它:该FILTER子句确保您无论如何都只有最后五个条目shop