【问题标题】:SQL get products and messages group bySQL 获取产品和消息分组依据
【发布时间】:2021-04-10 13:51:37
【问题描述】:

我需要编写一个 Oracle SQL 查询。我有两个表产品和消息。产品表如下所示:

product_id creation_date user_id category_id
p1 2017-03-01 u1 c1
p2 2018-05-23 u1 c3
p3 2019-06-21 u2 c1

消息表如下所示:

message_id creation_date product_id user_from
m1 2018-03-01 p1 u2
m2 2019-08-19 p1 u5
m3 2020-10-10 p3 u7

我想列出一个类别中的所有产品,按消息总数排序,以及每个产品的前 5 位买家(联系这些产品的用户按发送消息总数排序)

示例输出表:

category_id product_id total_messages_for_product user_id messages
c1 p1 200 u1 10
c1 p1 200 u2 9
c1 p1 200 u3 7
c1 p1 200 u4 5
c1 p1 200 u5 4
c1 p2 150 u7 11
c1 p2 150 u8 10
c1 p2 150 u9 9
c1 p2 150 u10 7
c1 p2 150 u4 6

【问题讨论】:

  • 那么,你尝试了什么?
  • 您现有的输入数据没有意义。为什么products表中有user_id列?
  • 我知道如何使用内部连接获取 category_id、product_id 和 group by sum 消息,但我不知道如何获取最后两列 @Russ
  • @mathguy 该产品是由某个用户创建的,但是此 user_id 与显示发送消息的用户的消息 user_from 列不同。希望它澄清
  • 但是,我只是在猜测,您希望在输出(来自第二个表)中出现 user_from,而不是 user_id。对吗?

标签: sql oracle greatest-n-per-group


【解决方案1】:

你似乎想要:

SELECT p.category_id,
       p.product_id,
       m.total_messages_for_product,
       m.user_from AS user_id,
       m.messages
FROM   products p
       INNER JOIN (
         SELECT product_id,
                user_from,
                COUNT(*) AS messages,
                SUM( COUNT(*) ) OVER ( PARTITION BY product_id )
                  AS total_messages_for_product,
                RANK() OVER (
                  PARTITION BY product_id ORDER BY COUNT(*) DESC
                ) AS messages_rank
         FROM   messages
         GROUP BY product_id, user_from
       ) m
       ON ( p.product_id = m.product_id )
WHERE  m.messages_rank <= 5;

(注意:您可以改为使用 ROW_NUMBER 来获取前 5 个没有关系的条目,而不是使用 RANK 来返回前 5 个有关系的条目。)

对于您的示例数据:

CREATE TABLE products ( product_id, creation_date, user_id, category_id ) AS
SELECT 'p1', DATE '2017-03-01', 'u1', 'c1' FROM DUAL UNION ALL
SELECT 'p2', DATE '2018-05-23', 'u1', 'c3' FROM DUAL UNION ALL
SELECT 'p3', DATE '2019-06-21', 'u2', 'c1' FROM DUAL;

CREATE TABLE messages( message_id, creation_date, product_id, user_from ) AS
SELECT 'm1', DATE '2018-03-01', 'p1', 'u2' FROM DUAL UNION ALL
SELECT 'm2', DATE '2019-08-19', 'p1', 'u5' FROM DUAL UNION ALL
SELECT 'm3', DATE '2020-10-10', 'p3', 'u7' FROM DUAL;

输出:

类别 ID | PRODUCT_ID | TOTAL_MESSAGES_FOR_PRODUCT | USER_ID |留言 :------------ | :--------- | --------------------------: | :-------- | --------: c1 | p1 | 2 | u5 | 1 c1 | p1 | 2 | u2 | 1 c1 | p3 | 1 | u7 | 1

db小提琴here

【讨论】:

    【解决方案2】:

    类似这样的东西(未测试,因为您没有以可用的形式提供测试数据):

    with
      agg (product_id, user_from, messages, total_messages_for_product) as (
        select product_id, user_from, count(*),
               sum(count(*)) over (partition by product_id)
        from   messages
        group  by product_id, user_from
      )
    select p.category_id, a.product_id, a.total_messages_for_product,
           a.user_from, a.messages
    from   products p join agg a on p.product_id = a.product_id
    order  by product_id, user_from   --  if/as needed
    ;
    

    主要工作在agg 子查询中完成(仅使用messages 表)。请注意使用按产品分区的分析sum() 函数来按产品获取总消息。然后通过加入products 表获得@9​​87654325@。

    【讨论】:

      猜你喜欢
      • 2019-11-06
      • 1970-01-01
      • 1970-01-01
      • 2019-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多