Reputation: 5306
Lets say I have the following table variable:
DECLARE @DevicesAndStatuses TABLE (Id BIGINT,[Status] INT);
DECLARE @myId BIGINT;
SET @myId = 1;
Inside above table I can have thousands of Ids(Id can be repeated) and statuses ranging between 1-50. What is the most efficient way of getting the count of all the statuses for a particular Id?
The traditional method which I have is as follows:
SELECT
(SELECT COUNT(*) FROM @DevicesAndStatuses WHERE Id = @myId AND [Status] = 1) AS Status1,
(SELECT COUNT(*) FROM @DevicesAndStatuses WHERE Id = @myId AND [Status] = 2) AS Status2,
(SELECT COUNT(*) FROM @DevicesAndStatuses WHERE Id = @myId AND [Status] = 3) AS Status3,
(SELECT COUNT(*) FROM @DevicesAndStatuses WHERE Id = @myId AND [Status] = 4) AS Status4,
...
(SELECT COUNT(*) FROM @DevicesAndStatuses WHERE Id = @myId AND [Status] = 50) AS Status50,
FROM @DevicesAndStatuses WHERE Id = @myId
Are there potentially any better solution for getting the count of all the statuses [1-50] for a particular id?
Final result should be a single row containing 50 columns showing the count() of every status as Status1,Status2,...,Status50.*
Upvotes: 0
Views: 424
Reputation: 109
Here you go
SELECT MAX(id) AS Id, status, COUNT(*)
FROM @DevicesAndStatuses
WHERE Id = @myId
GROUP BY status;
or
SELECT id AS Id, status, COUNT(*)
FROM @DevicesAndStatuses
WHERE Id = @myId
GROUP BY id,status;
Upvotes: 0
Reputation: 276
You'll need to use a Dynamic Pivot Query to achieve this:
I've done it using a generic example but poke me if you need a more specific version. You'll need to use a Temp Table instead of a Table Variable though.
The STUFF
command is there to remove the ,
from the beginning of the strings.
CREATE TABLE #Items
(
Item INT IDENTITY(1,1),
[Status] INT
)
INSERT #Items
(Status)
VALUES
(1),(1),(1),(1),(1),(1),(1),(2),(2),(2),(2),(3),(3),(4),(4),(4),(4),(4),(4),(4),(4),(5);
DECLARE @StatusList NVARCHAR(MAX) = N'',
@SumSelector NVARCHAR(MAX) = N''
SELECT @StatusList = CONCAT(@StatusList, N',', QUOTENAME(s.Status)),
@SumSelector = CONCAT(@SumSelector, N',', N'SUM(', QUOTENAME(s.Status), N') AS Status_', s.Status)
FROM (SELECT DISTINCT [Status] FROM #Items) AS s
SELECT @StatusList = STUFF(@StatusList, 1, 1, N''),
@SumSelector = STUFF(@SumSelector, 1, 1, N'')
DECLARE @StatusPivotQuery NVARCHAR(MAX) = CONCAT(N'
SELECT ', @SumSelector, N'
FROM #Items AS s
PIVOT
(
COUNT(s.[Status])
FOR s.[Status] IN(', @StatusList, N')
) AS pvt ')
EXEC sys.sp_executesql @StatusPivotQuery
DROP TABLE #Items
Upvotes: 0
Reputation: 1269503
My first suggestion is to use a group by
:
SELECT status, count(*)
FROM @DevicesAndStatuses
WHERE Id = @myId
GROUP BY status;
The simplest way to get the information you want, but in multiple rows.
If you want multiple columns, then use conditional aggregation:
SELECT SUM(CASE WHEN [Status] = 1 THEN 1 ELSE 0 END) AS Status1,
SUM(CASE WHEN [Status] = 2 THEN 1 ELSE 0 END) AS Status2,
SUM(CASE WHEN [Status] = 3 THEN 1 ELSE 0 END) AS Status3,
SUM(CASE WHEN [Status] = 4 THEN 1 ELSE 0 END) AS Status4,
. . .
FROM @DevicesAndStatuses
WHERE Id = @myId
Upvotes: 2
Reputation: 754268
Sure:
SELECT Status, COUNT(*)
FROM @DevicesAndStatuses
WHERE Id = @myId
GROUP BY Status
This returns all Status
values for Id = @myId
, and their count - in one simple statement
Upvotes: 1