英文:
Using nested queries with COUNT function
问题
以下是您的翻译内容:
我正在使用一个SQL表来跟踪每天为学生提供的餐点数量。该表的结构如下:
学生ID | 餐点日期 | 餐点类型 |
---|---|---|
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 |
餐点类型列指定了餐点的类型:
- 1 = 早餐
- 2 = 午餐
- 3 = 晚餐
因此,每个学生每天最多可以有3条记录。
现在,我正在尝试使用表格"Meals"中的数据创建发票。为此,我需要一个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子句中的餐点类型有关,但我不知道如何限制COUNT(*)函数到特定的餐点类型。
英文:
I am using an SQL table to keep track of the number of meals given to students every day. The table is structured as follows:
ID_Student | MealDate | MealType |
---|---|---|
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 |
The MealType columns specifies the type of meal:
- 1 = Breakfast
- 2 = Lunch
- 3 = Dinner
Individual students can therefore have up to 3 records for each day.
I am now trying to create an invoice using the data in the table "Meals". For that, I need an SQL query that generates the total number of breakfasts, lunches and dinners for each day in a given month. Based on the table shown above it should look something like this:
MealDate | Breakfasts | Lunches | Dinners |
---|---|---|---|
2023-05-21 | 2 | 2 | 0 |
2023-05-22 | 1 | 0 | 0 |
2023-05-23 | 0 | 0 | 1 |
I assume nested queries are the best approach here, so this is how far I've got:
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
Problem is, the result is always empty. How can I make this work? The individual queries by themselves produce the expected results, but the nesting breaks it. I have a suspicion it has to do with the MealTypes in the WHERE clauses, but I don't know how else to restrict the COUNT(*) function to the specific meal type.
答案1
得分: 1
你的方法不错,虽然需要稍作调整才能使其正常工作。首先,将条件从WHERE
子句移到聚合函数中(条件聚合)。然后,你会注意到,你总是在相同的字段上进行分组:你可以将所有计数聚合放在一个查询中。
如果你想筛选记录为2023年5月,而不是使用LIKE
,最好使用日期函数(例如YEAR
和MONTH
),或者使用日期比较和月初进行比较。
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
WHERE YEAR(MealDate) = 2023 AND MONTH(MealDate) = 5
GROUP BY MealDate;
输出:
MealDate | Breakfasts | Lunches | Dinners |
---|---|---|---|
2023-05-21 | 2 | 2 | 0 |
2023-05-22 | 1 | 0 | 0 |
2023-05-23 | 0 | 0 | 1 |
在此查看演示链接。
英文:
Your approach is good, although shall be tweaked a little to make it working. First move your conditions from the WHERE
clauses to the aggregate functions (conditional aggregation). Then as you notice, you're grouping always on the same field: you can pull all your count aggregates in a single query.
If you want to filter your records to be on May 2023, instead of LIKE
, it would be better to use date functions (like YEAR
and MONTH
), or use date comparison with the first of the month.
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'
Output:
MealDate | Breakfasts | Lunches | Dinners |
---|---|---|---|
2023-05-21 | 2 | 2 | 0 |
2023-05-22 | 1 | 0 | 0 |
2023-05-23 | 0 | 0 | 1 |
Check the demo here.
答案2
得分: 0
你可以使用条件聚合来完成,如下所示:
select MealDate, COUNT(CASE WHEN MealType = 1 THEN ID_Student END) AS 早餐,
COUNT(CASE WHEN MealType = 2 THEN ID_Student END) AS 午餐,
COUNT(CASE WHEN MealType = 3 THEN ID_Student END) AS 晚餐
from mytable
group by MealDate
英文:
You can do it using the conditional aggregation as follows :
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论