【问题标题】:SQL SUM TOP 5 values per category then SUM category totals per IDSQL SUM TOP 5 每个类别的值,然后 SUM 类别总计每个 ID
【发布时间】:2019-05-17 16:29:36
【问题描述】:

我正在尝试生成一个 SQL 语句来对每个用户 ID 的类别中的前 5 个值求和,以创建一个总体总数。这可能吗?我该如何实现?我可以对单个类别或所有类别的前 5 个进行求和,但很难了解如何将每个单独的类别加在一起。

例如,

ID           Cater   Weight
--------------------------------
1            Cheese    10
2            Bacon     15
1            Cheese    5
2            Bacon     10
1            Cheese    22
2            Cheese    5
1            Bacon     10
1            Cheese    10
2            Cheese    5
1            Cheese    20
2            Bacon     10
1            Cheese    30

我正在寻找的结果是,

ID      Total_Weight
-------------------
1            102    Top 5 Cheese (10+22+10+20+30) + Top 5 Bacon (10)
2            45     Top 5 Cheese (5+5) + Top 5 Bacon (15+10+10)

前 5 名之外的任何值都将被忽略。

下面的代码显示所有类别的前 5 个权重的总和作为总权重。我可以从一个声明中实现我想要的吗?

$log = "SELECT id, cater,
    SUM(weight) AS total_weight
   FROM   (   SELECT id,
                 CASE WHEN @ID = ID THEN @ROW_NUMBER := @ROW_NUMBER + 1
                      ELSE @ROW_NUMBER := 1
                  END AS rn,
                 cater,
                 weight,
                 @id := id
            FROM individual,
                 (SELECT @ROW_NUMBER := 1, @ID := '') r
           ORDER
              BY
                 id, weight DESC
      ) TMP
 WHERE rn <= 5
   AND cater <> ''

   GROUP
BY id
 ORDER
BY total_weight DESC";

【问题讨论】:

  • 类似于this article 在外部查询中带有 SUM /GROUP。
  • 没有 PRIMARY KEY,你就没有真正的桌子

标签: mysql sql sum


【解决方案1】:

可能还有其他更好的解决方案。但这将提供您预期的结果-

SELECT B.id, 
SUM(T_weight) Total_Weight,
group_concat(concat('TOP 5 ',B.cater,' (',B.T,')') SEPARATOR ' ') Details
FROM
(
    SELECT ID,cater,SUM(Weight) T_weight,group_concat(weight SEPARATOR '+') T
    FROM 
    (    
        SELECT *    FROM
        (
            SELECT id,cater, CASE WHEN @ID = ID THEN @ROW_NUMBER := @ROW_NUMBER + 1 ELSE @ROW_NUMBER := 1 END AS rn,weight,@id := id
            FROM your_table,(SELECT @ROW_NUMBER := 1, @ID := ''
        ) r
        WHERE cater = 'Cheese' ORDER BY id, weight DESC
        )A WHERE rn < 6


        UNION ALL

        SELECT *    FROM
        (
            SELECT id,cater, CASE WHEN @ID = ID THEN @ROW_NUMBER := @ROW_NUMBER + 1 ELSE @ROW_NUMBER := 1 END AS rn,weight,@id := id
            FROM your_table,(SELECT @ROW_NUMBER := 1, @ID := ''
        ) r
        WHERE cater = 'Bacon' ORDER BY id, weight DESC
        )A WHERE rn < 6


        UNION ALL

        SELECT *    FROM
        (
            SELECT id,cater, CASE WHEN @ID = ID THEN @ROW_NUMBER := @ROW_NUMBER + 1 ELSE @ROW_NUMBER := 1 END AS rn,weight,@id := id
            FROM your_table,(SELECT @ROW_NUMBER := 1, @ID := ''
        ) r
        WHERE cater = 'Cat3' ORDER BY id, weight DESC
        )A WHERE rn < 6


        UNION ALL

        SELECT *    FROM
        (
            SELECT id,cater, CASE WHEN @ID = ID THEN @ROW_NUMBER := @ROW_NUMBER + 1 ELSE @ROW_NUMBER := 1 END AS rn,weight,@id := id
            FROM your_table,(SELECT @ROW_NUMBER := 1, @ID := ''
        ) r
        WHERE cater = 'Cat4' ORDER BY id, weight DESC
        )A WHERE rn < 6


        UNION ALL

        SELECT *    FROM
        (
            SELECT id,cater, CASE WHEN @ID = ID THEN @ROW_NUMBER := @ROW_NUMBER + 1 ELSE @ROW_NUMBER := 1 END AS rn,weight,@id := id
            FROM your_table,(SELECT @ROW_NUMBER := 1, @ID := ''
        ) r
        WHERE cater = 'Cat5' ORDER BY id, weight DESC
        )A WHERE rn < 6


        UNION ALL

        SELECT *    FROM
        (
            SELECT id,cater, CASE WHEN @ID = ID THEN @ROW_NUMBER := @ROW_NUMBER + 1 ELSE @ROW_NUMBER := 1 END AS rn,weight,@id := id
            FROM your_table,(SELECT @ROW_NUMBER := 1, @ID := ''
        ) r
        WHERE cater = 'Cat6' ORDER BY id, weight DESC
        )A WHERE rn < 6
    )A
    GROUP BY ID,Cater
)B
group by id

输出是-

1   191 TOP 5 Cheese (10+22+20+10+30) TOP 5 Cat3 (25+9+20+16+13) TOP 5 Bacon (10)
2   45  TOP 5 Cheese (5+5) TOP 5 Bacon (15+10+10)

【讨论】:

  • 谢谢伙计。我会试一试的。我必须以这种方式指定每个类别吗?我有 6 个类别类型。 2(奶酪和培根)只是示例。
  • 是的,我没有找到其他方法让它动态化:(
  • 好的,谢谢。您的代码似乎有效。您是否可以演示我将如何在声明中添加更多类别。即达到我的 6 类查询。我还在学习 SQL 的构造。
  • 等等...给我一些时间...我会回来的。
  • 查询已更新。只需根据您的原始值更改 Cat 名称即可。我在 ID 1 下添加了一个新类别 Cat3,输出也包含新值。请检查编辑后的答案。
【解决方案2】:

如果你有 MySql 8 或更高版本,你可以使用这个代码:

  SELECT id, SUM (weight)
    FROM (SELECT test.*,
                 ROW_NUMBER ()
                     OVER (PARTITION BY id, categ ORDER BY weight DESC)
                     rn
            FROM test) sub
   WHERE sub.rn < 6
GROUP BY id;

您需要 MySql 8+,因为我使用了函数 row_number 并且仅从版本 8 开始存在。 在下面的小提琴示例中,我使用了 Microsoft Sql Server 2017,因为他们没有 MySql 8 或更高版本。

你可以看到你的例子here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-13
    • 1970-01-01
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多