【问题标题】:Group by limit per group (PostgreSQL)按每组限制分组 (PostgreSQL)
【发布时间】:2021-01-11 21:25:40
【问题描述】:

我有以下查询:

WITH relationships AS (
    SELECT related_user_id, count(*) AS trade_count
    FROM trade_history
    WHERE user_id = 487834568 
    GROUP BY related_user_id
    ORDER BY trade_count DESC
)
SELECT offers.*,
       relationships.trade_count
FROM offers
         LEFT JOIN user_stock
                   ON user_stock.user_id = 487834568 and offers.product_id = user_stock.product_id
         LEFT JOIN relationships
                   ON offers.user_id = relationships.related_user_id
WHERE offers.state = 'OPEN'
  AND offers.user_id != 487834568        
  AND offers.group BETWEEN 1 AND 3 
ORDER BY offers.created_at,
         relationships.trade_count DESC,
         user_stock.amount NULLS FIRST;

查询向我显示所有报价并按以下方式订购它们:

  • 首先显示较旧的优惠
  • 首先显示交易数量较高的报价(两个用户互相交易)
  • 用户存量

我还需要将每个product_id 的结果限制为最多 3 个。我做了一些谷歌搜索,发现这应该可以通过使用row_number() 和横向连接的窗口函数来实现。我不想使用row_number(),因为这些表包含很多条目,我很可能会遇到性能问题。我猜横向连接是正确的工具(在此处阅读 http://charlesnagy.info/it/postgresql/group-by-limit-per-group-in-postgresql),但由于我有限的 SQL 知识,我无法得到一个像样的结果。

如何以高效的方式进行分组?

编辑: 为了更清楚,我用窗口函数实现了解决方案:

WITH relationships AS (
    SELECT related_user_id, count(*) AS trade_count
    FROM trade_history
    WHERE user_id = 487834568 
    GROUP BY related_user_id
    ORDER BY trade_count DESC
)
SELECT * FROM (
    SELECT 
           offers.*,
           relationships.trade_count,
           row_number() OVER (
               PARTITION BY resource_id
               ORDER BY 
                   offers.created_at,
                   relationships.trade_count DESC,
                   user_stock.amount NULLS FIRST
        ) AS row_number
    FROM offers
             LEFT JOIN user_stock
                       ON user_stock.user_id = 487834568 and offers.product_id = user_stock.product_id
             LEFT JOIN relationships
                       ON offers.user_id = relationships.related_user_id
    WHERE offers.state = 'OPEN'
      AND offers.user_id != 487834568        
      AND offers.group BETWEEN 1 AND 3 
                  ORDER BY row_number
              ) AS ordered_offers
WHERE ordered_offers.row_number <= 3;

【问题讨论】:

    标签: sql postgresql lateral-join


    【解决方案1】:

    如果您可以在那里添加一些分组,请在 WHEREORDER BY 之间添加 HAVING count(offers.product_id) &lt;= 3

    把它们放在一起,感觉是对的。我将尝试基于不同的本地数据库进行类似的分组,看看它是否按预期工作,如果没有,将更新。

    WITH relationships AS (
      SELECT related_user_id, count(*) AS trade_count
      FROM trade_history
      WHERE user_id = 487834568 
      GROUP BY related_user_id
      ORDER BY trade_count DESC
    )
    SELECT
      offers.*,
      relationships.trade_count
    FROM offers
    LEFT JOIN user_stock ON
      user_stock.user_id = 487834568 AND
      offers.product_id = user_stock.product_id
    LEFT JOIN relationships ON
      offers.user_id = relationships.related_user_id
    LEFT JOIN (
      SELECT array_agg(offers.id) AS ids
      FROM offers
      JOIN user_stock ON
        user_stock.user_id = 487834568 AND
        offers.user_id = user_stock.user_id AND
        offers.product_id = user_stock.product_id
      GROUP BY offers.user_id
      HAVING count(offers.id) <= 3
    ) AS offers_limit ON
      offers.id = any(offers_limit.ids)
    WHERE
      offers.state = 'OPEN' AND
      offers.user_id != 487834568 AND
      offers.group BETWEEN 1 AND 3
    ORDER BY
      offers.created_at,
      relationships.trade_count DESC,
      user_stock.amount NULLS FIRST
    

    【讨论】:

    • 这也是我已经尝试过的,但我必须调整GROUP BY 子句并且不会选择我想要的列。至少在我的理解中。 [42803] ERROR: column "offers.id" must appear in the GROUP BY clause or be used in an aggregate function
    • @messy 可能会在id 上将offers 与自身连接,并仅在连接表上使用HAVING 子句,并选择有限的列。 JOIN offers AS offers_limit ON offers_limit.id = offers.id AND offers_limit.product_id = user_stock.product_id ... GROUP BY offers_limit.product_id ... HAVING count(offers_limit.id) &lt;= 3
    • 您是否有理由将 LEFT JOIN 替换为 JOIN?遗憾的是,您的查询没有给出我需要的结果。它什么也不返回。我将简化我的查询,并在接下来的几天内再试一次。
    • A LEFT JOIN 会在正确的表不符合标准的情况下为您提供结果,这似乎不是您想要的。你能确认有应该返回的数据吗,也许你可以把 3 的值放宽,然后检查一下。
    • 是的,如果正确的表格不符合标准,我需要数据。除了使用row_numbers()(参见编辑后的帖子)之外,我无法完成它。
    猜你喜欢
    • 1970-01-01
    • 2010-11-10
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多