如何在 SQL Server 2012 中使用 GROUP BY

3
我有两个表格,一个包含垃圾桶列表,另一个包含该垃圾桶收集的工作日。
declare @bins table (
    id int IDENTITY(1,1) PRIMARY KEY,
    name nvarchar(255),
    collectionCode nvarchar(255)
)

declare @collectionDays table (
    id int IDENTITY(1,1) PRIMARY KEY,
    weekday int,
    collectionCode nvarchar(255)
)

insert into @bins (name, collectionCode) values
('Bin 1','MWF'),
('Bin 2','MWF'),
('Bin 3','ED'),
('Bin 4','ED'),
('Bin 5','ED'),
('Bin 6','ED'),
('Bin 7','ED'),
('Bin 8','ED'),
('Bin 9','ED'),
('Bin 10','MWF')

insert into @collectionDays (weekday, collectionCode) values
(0,'MWF'),
(2,'MWF'),
(4,'MWF'),
(0,'ED'),
(1,'ED'),
(2,'ED'),
(3,'ED'),
(4,'ED'),
(5,'ED'),
(6,'ED')

我想要做的是返回所有垃圾桶及其下一次收集日期的列表。
我已经创建了此查询,它可以返回下一次收集日期,但每次只能针对一个垃圾桶查询。我不想为数据库中的每个垃圾桶运行此查询。
以下是我的查询:
select top 1
    name,
    format(dateadd(day, (datediff(day, weekday, getdate()) / 7) * 7 + 7, weekday), 'dd/MM/yyyy') AS date
from @bins b
join @collectionDays c on b.collectionCode = c.collectionCode
where b.id = 1
order by date asc

如果我去掉top 1b.id = 1的条件,它将返回每个工作日的所有垃圾箱和下一个日期。如果我尝试使用group by,会出现错误:在选择列表中,列“@collectionDays.weekday”无效,因为它不包含在聚合函数或GROUP BY子句中。

select
    name,
    format(dateadd(day, (datediff(day, weekday, getdate()) / 7) * 7 + 7, weekday), 'dd/MM/yyyy') AS date
from @bins b
join @collectionDays c on b.collectionCode = c.collectionCode
group by b.id
order by date asc

有没有办法在单个查询中返回每个垃圾箱的下一个收集日期?
编辑:已经使用联接和其他东西更新了查询。

3
你为什么要使用GROUP BY,你的查询中没有聚合。此外,你为什么还在使用32年前的语法?它已经在1992年被明确的JOIN语法所取代;你现在已经有了29年可以采用它;真的应该改过来了。 - Thom A
进化 - 没有人应该使用旧式连接 - SMor
@Larnu 谢谢你,我已经用连接语法更新了问题。关于格式,工作日中的数字表示0为星期一,3为星期三,6为星期日等等。 - hussainsajid
我误读了格式,抱歉。不过,我建议使用样式代码为103CONVERT函数,它更快。 - Thom A
1个回答

3

这应该可以做到

select
    name,
    MIN(format(dateadd(day, (datediff(day, weekday, getdate()) / 7) * 7 + 7, weekday), 'dd/MM/yyyy')) AS [DATE]
from @bins b
join @collectionDays c on b.collectionCode = c.collectionCode
group by name
order by date asc

基本上,您希望按名称分组,因为这是您返回的结果之一,然后获取每个名称返回的最小日期。

在此示例中,名称似乎是唯一的。在许多情况下,这不能保证,因此您需要执行以下操作

;with cte_nextdates as
(
select
    b.id,
    MIN(format(dateadd(day, (datediff(day, weekday, getdate()) / 7) * 7 + 7, weekday), 'dd/MM/yyyy')) AS [DATE]
from @bins b
join @collectionDays c on b.collectionCode = c.collectionCode
group by b.id
)
SELECT B.name,
[date]
FROM cte_nextdates ND
INNER JOIN @bins B ON B.id = ND.id
order by date asc

这个操作是基于ID进行分组,而不是名称。

问题在于,只能在分组SQL查询中包含在group子句中或传递给聚合函数(如Min或max)的字段。由于名称可能不是唯一的,我们不能在其上进行分组。

为了解决这个问题,我们取回ID和日期的结果集,并将其与Bin表连接以获取垃圾箱名称。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接