将嵌套查询与 COUNT 函数一起使用

Using nested queries with COUNT function

提问人:FanatSiar 提问时间:5/21/2023 最后编辑:lemonFanatSiar 更新时间:5/21/2023 访问量:45

问:

我正在使用 SQL 表来跟踪每天给学生的饭菜数量。该表的结构如下:

ID_Student 用餐日期 膳食类型
1 2023-05-21 1
2 2023-05-21 1
1 2023-05-21 2
2 2023-05-21 2
1 2023-05-22 1
1 2023-05-23 3

MealType 列指定膳食类型:

  • 1 = 早餐
  • 2 = 午餐
  • 3 = 晚餐

因此,单个学生每天最多可以有 3 条记录。

我现在正在尝试使用“膳食”表中的数据创建发票。为此,我需要一个 SQL 查询来生成给定月份中每天的早餐、午餐和晚餐总数。根据上面显示的表格,它应该如下所示:

用餐日期 早餐 午餐 晚餐
2023-05-21 2 2 0
2023-05-22 1 0 0
2023-05-23 0 0 1

我认为嵌套查询是这里最好的方法,所以这就是我所取得的成就:

SELECT MealDate, BreakfastCount, LunchCount, DinnerCount FROM 
(
    SELECT MealDate, LunchCount, DinnerCount, COUNT(*) AS "BreakfastCount" FROM 
    (
        SELECT MealDate, MealType, DinnerCount, COUNT(*) AS "LunchCount" FROM
        (
            SELECT MealDate, MealType, COUNT(*) AS "DinnerCount" FROM Meals
            WHERE MealType=3 AND MealDate LIKE '2023-05-%'
            GROUP BY MealDate
        ) Dinners
        WHERE MealType=2 AND MealDate LIKE '2023-05-%'
        GROUP BY MealDate
    ) Lunches
    WHERE MealType=1 AND MealDate LIKE '2023-05-%'
    GROUP BY MealDate
) Breakfasts
GROUP BY MealDate

问题是,结果总是空的。我怎样才能做到这一点?单个查询本身会产生预期的结果,但嵌套会破坏它。我怀疑它与 WHERE 子句中的 MealTypes 有关,但我不知道如何将 COUNT(*) 函数限制为特定的膳食类型。

SQL MySQL 嵌套 子查询 透视

评论

0赞 philipxy 5/21/2023
一个最小的可重现的例子包括:剪切、粘贴和可运行的代码,包括初始化;期望和实际输出(包括逐字错误消息);标签和版本;明确的规范和解释。对于 SQL,包括 DDL 和表格初始化代码。对于包含最少代码的调试,您可以提供显示的代码是正常的,由显示的代码扩展为不正常。
1赞 lemon 5/21/2023
与其他新贡献者相比,这个人是为数不多的能够创建写得很好的帖子的新贡献者之一,具有完整的描述、对他正在寻找的内容的清晰解释、示例表、预期输出和他们自己的尝试。对于这种质量来说,这是当之无愧的+1。他可能错过了“支点”这个词,这使他无法为这种任务找到类似的解决方案,我们都同意这一点。
0赞 FanatSiar 5/22/2023
感谢 Lemon,我以前确实没有听说过 SQL 上下文中的透视。我会调查的。

答:

1赞 lemon 5/21/2023 #1

你的方法很好,尽管应该稍微调整一下以使其正常工作。首先将条件从子句移动到聚合函数(条件聚合)。然后,正如你所注意到的,你总是在同一个字段上分组:你可以在单个查询中提取所有计数聚合。WHERE

如果要将记录筛选为 2023 年 5 月,而不是 ,最好使用日期函数(如 和 ),或使用与当月第一天的日期比较。LIKEYEARMONTH

SELECT MealDate, 
       COUNT(CASE WHEN MealType = 1 THEN ID_Student END) AS Breakfasts,
       COUNT(CASE WHEN MealType = 2 THEN ID_Student END) AS Lunches,
       COUNT(CASE WHEN MealType = 3 THEN ID_Student END) AS Dinners
FROM tab
GROUP BY MealDate
WHERE YEAR(MealDate) = 2023 AND MONTH(MealDate) = 5
# WHERE MealDate BETWEEN '2023-05-01' AND '2023-06-01'

输出

用餐日期 早餐 午餐 晚餐
2023-05-21 2 2 0
2023-05-22 1 0 0
2023-05-23 0 0 1

在此处查看演示。

0赞 SelVazi 5/21/2023 #2

您可以使用条件聚合来执行此操作,如下所示:

select MealDate, COUNT(CASE WHEN MealType = 1 THEN ID_Student END) AS Breakfasts,
                 COUNT(CASE WHEN MealType = 2 THEN ID_Student END) AS Lunches,
                 COUNT(CASE WHEN MealType = 3 THEN ID_Student END) AS Dinners
from mytable
group by MealDate

演示在这里

评论

1赞 FanatSiar 5/22/2023
谢谢!我已经尝试过了,它产生了我想要的结果!