SQL 数据透视表 Table - 子查询
SQL Pivot Table - Subqueries
我有一个程序可以记录用户在某些方面花费的时间,其中一些被标识为特定 "time"。我正在努力将每个月的多行分组查询结果作为 "summary".
我当前的查询:
SELECT
TotalMins = SUM(Minutes)
,DateMonth = MONTH(Date)
,ID1
,PC
FROM User_Time_Log
WHERE
(UserID = 1)
AND (YEAR(Date) = 2018)
GROUP BY
MONTH(Date)
,ID1
,PC1
当前结果:
TotalMins DateMonth ID1 PC1
192 1 0 0
306 1 0 100
113 2 0 0
365 2 0 100
14 2 1 0
3 2 1 100
75 3 0 0
253 3 0 100
3 3 1 0
300 4 0 0
233 4 0 100
10 4 1 0
23 4 1 100
438 5 0 0
134 5 0 100
19 5 1 0
49 5 1 100
0 9 1 0
11 10 0 0
21 10 0 60
167 10 1 100
从这一点开始我想做的是创建一个 table 显示所有 12 个月,无论该月内是否有信息,并在每一行内显示该月的相关信息月。例如:
DateMonth NonID1 TimeID1 TimePC1 (Round((PC1/100)*TotalMins)) TimePC1ID1
1 192 0 306 0
2 113 14 365 3
3 75 3 253 0
4 300 10 233 23
5 438 19 134 49
6 0 0 0 0
7 0 0 0 0
8 0 0 0 0
9 0 0 0 0
10 11 0 13 167
11 0 0 0 0
12 0 0 0 0
最有效的方法是什么?
注意:我还创建了一个 table 来给我 1-12 作为我可以用来给我需要使用的月份的行,其中信息不在 user_time_log.
这里有一个简单的方法来完成您正在寻找的事情:
首先,创建您的 table 月份值。我用单列制作了一个简单的临时 table。
CREATE TABLE #Dates (MonthNum INT)
INSERT INTO #Dates
(
MonthNum
)
VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
接下来,您可以将您现有的查询放入一个 CTE,然后 LEFT JOIN
到您的 table 个月。您需要将列放入 SUM
的 CASE
语句中,如下所示:
;WITH Aggregation AS
(
SELECT
TotalMins = SUM(Minutes)
,DateMonth = MONTH(Date)
,ID1
,PC1
FROM #User_Time_Log
WHERE
(UserID = 1)
AND (YEAR(Date) = 2018)
GROUP BY
MONTH(Date)
,ID1
,PC1
)
SELECT
d.MonthNum
,NonID1 = SUM(CASE WHEN ID1 = 0 THEN TotalMins ELSE 0 END)
,TimeID1 = SUM(CASE WHEN ID1 = 1 THEN TotalMins ELSE 0 END)
,TimePC1 = SUM(CASE WHEN ID1 = 0 THEN ROUND((PC1/100)*TotalMins,0) ELSE 0 END)
,TimePC1ID1 = SUM(CASE WHEN ID1 = 1 THEN ROUND((PC1/100)*TotalMins,0) ELSE 0 END)
FROM #Dates d
LEFT JOIN Aggregation a ON d.MonthNum = a.DateMonth
GROUP BY d.MonthNum
输出将如下所示:
MonthNum NonID1 TimeID1 TimePC1 TimePC1ID1
1 498 0 306 0
2 478 17 365 3
3 328 3 253 0
4 533 33 233 23
5 572 68 134 49
6 0 0 0 0
7 0 0 0 0
8 0 0 0 0
9 0 0 0 0
10 32 167 0 167
11 0 0 0 0
12 0 0 0 0
编辑:
ROUND()
函数调用可以稍微更改以适应您对小数结果的需要。 ROUND()
的第一个参数是要四舍五入的表达式,第二个参数是要四舍五入到的小数位数。正数表示小数点右边要四舍五入的位数。负数表示小数点左边要四舍五入的位数。因此,如果您将其设置为 2
,您将得到四舍五入到最接近的百分之一的答案。
但我们还需要进行一项调整。 PC1
和 TotalMins
在我的回答中都被假定为 INT
s。所以我们必须给 SQL 引擎一点帮助,让它计算出 DECIMAL
的答案。通过 CAST()
将 INT
s 转换为 DECIMAL
s,SQL 将执行算术运算作为十进制数学而不是整数数学。您只需要像这样更改 TimePC1
和 TimePC1ID1
:
,TimePC1 = SUM(CASE WHEN ID1 = 0 THEN ROUND((CAST(PC1 AS DECIMAL)/100)*CAST(TotalMins AS DECIMAL),2) ELSE 0 END)
,TimePC1ID1 = SUM(CASE WHEN ID1 = 1 THEN ROUND((CAST(PC1 AS DECIMAL)/100)*CAST(TotalMins AS DECIMAL),2) ELSE 0 END)
然后输出如下所示:
MonthNum NonID1 TimeID1 TimePC1 TimePC1ID1
1 498 0 306.000000 0.000000
2 478 17 365.000000 3.000000
3 328 3 253.000000 0.000000
4 533 33 233.000000 23.000000
5 572 68 134.000000 49.000000
6 0 0 0.000000 0.000000
7 0 0 0.000000 0.000000
8 0 0 0.000000 0.000000
9 0 0 0.000000 0.000000
10 32 167 12.600000 167.000000
11 0 0 0.000000 0.000000
12 0 0 0.000000 0.000000
我有一个程序可以记录用户在某些方面花费的时间,其中一些被标识为特定 "time"。我正在努力将每个月的多行分组查询结果作为 "summary".
我当前的查询:
SELECT
TotalMins = SUM(Minutes)
,DateMonth = MONTH(Date)
,ID1
,PC
FROM User_Time_Log
WHERE
(UserID = 1)
AND (YEAR(Date) = 2018)
GROUP BY
MONTH(Date)
,ID1
,PC1
当前结果:
TotalMins DateMonth ID1 PC1 192 1 0 0 306 1 0 100 113 2 0 0 365 2 0 100 14 2 1 0 3 2 1 100 75 3 0 0 253 3 0 100 3 3 1 0 300 4 0 0 233 4 0 100 10 4 1 0 23 4 1 100 438 5 0 0 134 5 0 100 19 5 1 0 49 5 1 100 0 9 1 0 11 10 0 0 21 10 0 60 167 10 1 100
从这一点开始我想做的是创建一个 table 显示所有 12 个月,无论该月内是否有信息,并在每一行内显示该月的相关信息月。例如:
DateMonth NonID1 TimeID1 TimePC1 (Round((PC1/100)*TotalMins)) TimePC1ID1 1 192 0 306 0 2 113 14 365 3 3 75 3 253 0 4 300 10 233 23 5 438 19 134 49 6 0 0 0 0 7 0 0 0 0 8 0 0 0 0 9 0 0 0 0 10 11 0 13 167 11 0 0 0 0 12 0 0 0 0
最有效的方法是什么?
注意:我还创建了一个 table 来给我 1-12 作为我可以用来给我需要使用的月份的行,其中信息不在 user_time_log.
这里有一个简单的方法来完成您正在寻找的事情:
首先,创建您的 table 月份值。我用单列制作了一个简单的临时 table。
CREATE TABLE #Dates (MonthNum INT)
INSERT INTO #Dates
(
MonthNum
)
VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
接下来,您可以将您现有的查询放入一个 CTE,然后 LEFT JOIN
到您的 table 个月。您需要将列放入 SUM
的 CASE
语句中,如下所示:
;WITH Aggregation AS
(
SELECT
TotalMins = SUM(Minutes)
,DateMonth = MONTH(Date)
,ID1
,PC1
FROM #User_Time_Log
WHERE
(UserID = 1)
AND (YEAR(Date) = 2018)
GROUP BY
MONTH(Date)
,ID1
,PC1
)
SELECT
d.MonthNum
,NonID1 = SUM(CASE WHEN ID1 = 0 THEN TotalMins ELSE 0 END)
,TimeID1 = SUM(CASE WHEN ID1 = 1 THEN TotalMins ELSE 0 END)
,TimePC1 = SUM(CASE WHEN ID1 = 0 THEN ROUND((PC1/100)*TotalMins,0) ELSE 0 END)
,TimePC1ID1 = SUM(CASE WHEN ID1 = 1 THEN ROUND((PC1/100)*TotalMins,0) ELSE 0 END)
FROM #Dates d
LEFT JOIN Aggregation a ON d.MonthNum = a.DateMonth
GROUP BY d.MonthNum
输出将如下所示:
MonthNum NonID1 TimeID1 TimePC1 TimePC1ID1
1 498 0 306 0
2 478 17 365 3
3 328 3 253 0
4 533 33 233 23
5 572 68 134 49
6 0 0 0 0
7 0 0 0 0
8 0 0 0 0
9 0 0 0 0
10 32 167 0 167
11 0 0 0 0
12 0 0 0 0
编辑:
ROUND()
函数调用可以稍微更改以适应您对小数结果的需要。 ROUND()
的第一个参数是要四舍五入的表达式,第二个参数是要四舍五入到的小数位数。正数表示小数点右边要四舍五入的位数。负数表示小数点左边要四舍五入的位数。因此,如果您将其设置为 2
,您将得到四舍五入到最接近的百分之一的答案。
但我们还需要进行一项调整。 PC1
和 TotalMins
在我的回答中都被假定为 INT
s。所以我们必须给 SQL 引擎一点帮助,让它计算出 DECIMAL
的答案。通过 CAST()
将 INT
s 转换为 DECIMAL
s,SQL 将执行算术运算作为十进制数学而不是整数数学。您只需要像这样更改 TimePC1
和 TimePC1ID1
:
,TimePC1 = SUM(CASE WHEN ID1 = 0 THEN ROUND((CAST(PC1 AS DECIMAL)/100)*CAST(TotalMins AS DECIMAL),2) ELSE 0 END)
,TimePC1ID1 = SUM(CASE WHEN ID1 = 1 THEN ROUND((CAST(PC1 AS DECIMAL)/100)*CAST(TotalMins AS DECIMAL),2) ELSE 0 END)
然后输出如下所示:
MonthNum NonID1 TimeID1 TimePC1 TimePC1ID1
1 498 0 306.000000 0.000000
2 478 17 365.000000 3.000000
3 328 3 253.000000 0.000000
4 533 33 233.000000 23.000000
5 572 68 134.000000 49.000000
6 0 0 0.000000 0.000000
7 0 0 0.000000 0.000000
8 0 0 0.000000 0.000000
9 0 0 0.000000 0.000000
10 32 167 12.600000 167.000000
11 0 0 0.000000 0.000000
12 0 0 0.000000 0.000000