sql - 使用具有不同 GROUP BY 的聚合函数后如何摆脱 JOIN 的重复结果
问题描述
我正在尝试在表上使用聚合函数来跟踪分配给用户的任务的时间进度。
表的一部分看起来像这样:
表tasks
:
TaskID | UserID | RegistrationDate | StartDate | EndDate | Status
--------------------------------------------------------------------------
tId1 | uId1 | dd/10/2000 | dd/10/2000 | dd/10/2000 | completed
tId2 | uId2 | dd/10/2000 | dd/10/2000 | dd/12/2000 | completed
tId3 | uId3 | dd/10/2000 | dd/12/2000 | dd/02/2001 | completed
tId4 | uId4 | dd/10/2000 | dd/11/2000 | dd/11/2000 | cancelled
tId5 | uId5 | dd/11/2000 | dd/11/2000 | dd/01/2001 | completed
tId6 | uId6 | dd/12/2000 | NULL | NULL | registered
tId7 | uId7 | dd/12/2000 | dd/12/2000 | NULL | in progress
tId8 | uId8 | dd/01/2001 | dd/01/2001 | dd/01/2001 | cancelled
tId9 | uId9 | dd/01/2001 | dd/01/2001 | dd/02/2001 | completed
tId10 | uId10 | dd/02/2001 | NULL | NULL | registered
tId11 | uId11 | dd/02/2001 | dd/02/2001 | dd/02/2001 | completed
tId12 | uId12 | dd/02/2001 | dd/02/2001 | dd/02/2001 | completed
......
我的目标是能够根据不同的标准使用聚合器,这样我就可以得到以下几点:
Year | Month | NewR | Completed_A| Completed_B | Cancelled_A | Cancelled_B | OpenR |
---------------------------------------------------------------------------------------
2000 | 10 | 4 | 3 | 1 | 1 | 0 | 0 |
2000 | 11 | 1 | 1 | 0 | 0 | 1 | 0 |
2000 | 12 | 2 | 0 | 1 | 0 | 0 | 2 |
2001 | 1 | 2 | 1 | 1 | 1 | 1 | 0 |
2001 | 2 | 3 | 1 | 4 | 0 | 0 | 3 |
......
RegistrationDate
,StartDate
并且EndDate
都是时间戳,我正在尝试按时间顺序每月对我的结果进行排序。我遇到的问题是我正在使用GROUP BY
声明来执行此操作,虽然我确实希望时间进度基于注册日期,但我不一定想按它对我的输出进行分组。例如,在上表NewR
中,所有发生在对应月份的注册RegistrationDate
,Completed_A
计算在任何时间注册RegistrationDate
并完成的任务,同时Completed_B
计算在任何时间注册但在 完成的任务EndDate
,从而获得A
我需要的标准GROUP BY RegistrationDate
,并获得B
我需要的标准GROUP BY EndDate
。
我需要能够在单个查询中执行此操作,我目前这样做的方式是嵌套在一个凌乱SELECT
的 aJOIN
中,但是我得到了我想摆脱的冗余列并且无法弄清楚如何. 我的代码看起来像这样:
SELECT *
FROM
(SELECT
TO_CHAR(RegistrationDate, 'yyyy-mm') AS MonthYear
, DATE_PART('year',RegistrationDate) AS rYear
, DATE_PART('month',RegistrationDate) AS rMonth
, COUNT(*) AS NewR
, SUM(CASE WHEN Status = 'Completed' THEN 1 ELSE 0 END) AS Completed_A
, SUM(CASE WHEN Status IN ('Registered','In Progress')
THEN 1 ELSE 0 END) AS OpenR
FROM Tasks
GROUP BY MonthYear, rYear, rMonth) AS T1
LEFT JOIN
(SELECT
TO_CHAR(EndDate, 'yyyy-mm') AS MonthYear
, DATE_PART('year', EndDate) AS EndYear
, DATE_PART('month', EndDate) AS EndMonth
, SUM(CASE WHEN Status = 'Completed' THEN 1 ELSE 0 END) AS Completed_B
FROM Tasks
GROUP BY MonthYear, EndYear, EndMonth) AS T2
ON T1.MonthYear = T2.MonthYear
ORDER BY MonthYear
我添加了一个同时包含月份和年份的列,因为这是我可以弄清楚如何简化最终连接输出的正确排序的唯一方法,而且我还得到了一些累积总和,所以它真的可以帮助我SUM (stuff) OVER (ORDER BY MonthYear)
- 总体上是否有更好的方法在具有不同
GROUP BY
s 的单个语句上使用聚合? - 如何摆脱重复的月份、年份和
'yyyy-mm'
列?我真的不想不使用SELECT *
顶部的,因为在我的实际表中,我有更多的列我无法一一选择,而且我也在为其他一些与时间相关的标准这样做(所以实际上我的表有与我使用的许多标准一样多的重复冗余月份和年份列)。我试过添加一个DISTINCT
,但没有帮助。
哦,我目前正在使用 PostgreSQL,但有可能将其迁移到 SQL Server。(不过,我试图尽可能多地使用标准 SQL 并避免使用特定的 SQL Server 功能)。
我确实注意到有类似的问题,但答案并没有真正帮助我解决这个问题。
解决方案
要获得结果,您需要使用subquery
而不能使用SELECT *
.
以下查询使用UNION SELECT
可能与您所说的类似。
SELECT
Year
, Month
, SUM(CASE WHEN DTYPE='R' THEN 1 ELSE 0 END) AS NewR
, SUM(CASE WHEN DTYPE='R' AND Status = 'Completed'
THEN 1 ELSE 0 END) AS Completed_A
, SUM(CASE WHEN DTYPE='E' AND Status = 'Completed'
THEN 1 ELSE 0 END) AS Completed_B
, SUM(CASE WHEN DTYPE='R' AND Status IN ('Registered','In Progress')
THEN 1 ELSE 0 END) AS OpenR
FROM
(SELECT
'R' AS DTYPE
, DATE_PART('year',RegistrationDate) AS Year
, DATE_PART('month',RegistrationDate) AS Month
, Status
FROM Tasks
UNION ALL
SELECT
'E' AS DTYPE
, DATE_PART('year',EndDate)
, DATE_PART('month',EndDate)
, Status
FROM Tasks) T
WHERE Year IS NOT NULL
GROUP BY Year, Month
ORDER BY Year, Month;
推荐阅读
- jquery - 当我选中复选框 A 时,为什么未启用复选框 B?
- r - 使用 ggplot2 geom_tile() 突出显示由集群定义的瓦片组
- java - 使用 JPA 和 Spring 连接到 mysql 数据库而不使用 persistence.XML
- node.js - 有条件地设置 pino DestinationStream
- python - 尝试安装 Anaconda 时出现 TypeError
- c# - 继承对象列表
- firebase - 尝试将 A 记录添加到自定义 Firebase 站点时出现“记录已在使用中”
- neo4j - 为什么我的 Neo4j 数据库的大小比上周小,即使我一直在添加节点、关系和属性而不是删除它们
- sql - 如何在SQL中分配多天的分钟差异
- javascript - 将 Javascript Map 函数返回的数组保存到新数组