hussainsajid
hussainsajid

Reputation: 83

How do I use GROUP BY in SQL Server 2012

I've got two tables, one contains the list of bins and the second contains the weekdays where that bin is collected.

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')

What I want to do is return list of all the bins with their next collection day.

I've already created this query where if returns the next collection date but it only returns the next collection date for just one bin at a time. I don't want to run this query for each bin in the database.

Here's my query

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

If I remove top 1 and b.id = 1 condition, it'll return all the bins and next date for each weekday. If I try using group by, I get an error Column '@collectionDays.weekday' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

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

Any ideas on how I can return the next collection date for each bin in a single query?

EDIT: Updated the queries with join and other stuff

Upvotes: 3

Views: 97

Answers (1)

DrWrecker
DrWrecker

Reputation: 46

This should do it

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

Basically you want to group by the name as that's one of the results you're returning, then fetch the minimum date returned for each name.

For this example name appears to be unique. In a lot of cases this is not guaranteed, so you'd want to do something like this

;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

What this does is to group on ID rather than name.

The problem is that you can only include fields in grouped SQL queries that are either included in the group clause or passed into an aggregate function like Min or max. As Name might not be unique, we can't shouldn't group on it.

To get around that we take the result set of ID and Date returned and we join it to the Bin table to get the bin name .

Upvotes: 3

Related Questions