How to flatten this multiple rows into one? - sql-server

I have data like this: (table name: Activities)
ActivityId CreatedOn TypeId
1 2017-01-01 1
1 2017-01-02 1
1 2017-01-02 2
2 2017-01-01 3
Where Type is a lookup value: (table name: Types)
TypeId Name
1 Question
2 Answer
3 Comment
Basically it's an activity history table.
I want to turn the above tables into a grouped sum row for types, for each ActivityId, like this:
ActivityId QuestionCount AnswerCount CommentCount
1 2 1 0
2 0 0 1
I know the answer is probably pretty simple, but it's eluding me for some reason.
Any help? Thanks in advance.

A simple join and conditional aggregation should do the trick (I suspect you were over-thinking it)
Select ActivityID
,QuestionCount = sum(case when Name='Question' then 1 else 0 end)
,AnswerCount = sum(case when Name='Answer' then 1 else 0 end)
,CommentCount = sum(case when Name='Comment' then 1 else 0 end)
From Activities A
Join Types B on A.TypeId=B.TypeId
Group By ActivityId
Returns
ActivityID QuestionCount AnswerCount CommentCount
1 2 1 0
2 0 0 1
You could also do it without the Join... Just less readable
Select ActivityID
,QuestionCount = sum(case when TypeId=1 then 1 else 0 end)
,AnswerCount = sum(case when TypeId=2 then 1 else 0 end)
,CommentCount = sum(case when TypeId=3 then 1 else 0 end)
From #Activities A
Group By ActivityId
You could also try a PIVOT
Select ActivityID
,[1] as QuestionCount
,[2] as AnswerCount
,[3] as CommentCount
From (Select ActivityId,TypeID,1 as Cnt From #Activities) A
Pivot (count(Cnt) For TypeId in ([1],[2],[3]) ) p

Related

How to make group by query with sum function

I have inventoryTransaction table in SQL Server Like this:
productID StockLocationID TransactionType Quantity
1046 1 "in" 100
1046 1 "out" 20
1046 2 "in" 70
1046 2 "out" 65
...
How to make a query, output like this:
productID StockLocationID stock
1046 1 80
1046 2 5
You can try:
SELECT
productID,
StockLocationID,
SUM(CASE
WHEN TransactionType = 'out' THEN -1
ELSE 1
END) * Quantity) AS stock
GROUP BY
productID,
StockLocationID
The same but a little shortened eliminating unnecessary multiplication:
SELECT
productID,
StockLocationID,
SUM(CASE TransactionType
WHEN 'out' THEN -Quantity
ELSE Quantity
END) AS stock
GROUP BY
productID,
StockLocationID

Distinct counts per year

hello I am trying to count a person only once even if a person has two enrollments in the same year:
select DISTINCT Year, School,
count (case when [Graduate]= 1 AND [Dropout]= 0 THEN ID END) As 'passed',
count (case when [Graduate]= 0 AND [Dropout]= 1 THEN ID END) as 'dropped',
count (case when [Graduate]= 0 AND [Dropout]= 0 THEN ID END) as 'Continued'
from Table where ID = '10'
group by Year, School
my output is
Year school passed dropped continued
2012 School 0 0 1
2013 School 0 0 1
2014 School 0 0 2
continued is 2 for ID=1 because student enrolled twice. How do i get a distinct count in this case?
You are using DISTINCT wrong, it should be inside each COUNT:
SELECT [Year],
School,
COUNT(DISTINCT CASE WHEN [Graduate] = 1 AND [Dropout] = 0 THEN ID END) Passed,
COUNT(DISTINCT CASE WHEN [Graduate] = 0 AND [Dropout] = 1 THEN ID END) Dropped,
COUNT(DISTINCT CASE WHEN [Graduate] = 0 AND [Dropout] = 0 THEN ID END) Continued
FROM YourTable
WHERE ID = '10'
GROUP BY [Year],
School;

Selecting count into multiple columns

I have a table like this
MonthYear JobType JobID
01-2014 FullTime 1
01-2014 PartTime 2
02-2014 FullTime 3
03-2014 FullTime 4
04-2014 PartTime 5
04-2014 PartTime 6
04-2014 FullTime 7
I want to select the count of each job type grouped by MonthYear as follows.
MonthYear FullTime PartTime
01-2014 1 1
02-2014 1 0
03-2014 1 0
04-2014 1 2
Can anyone suggest how to achieve this?
Thanks.
SELECT MonthYear,
SUM(CASE WHEN JobType='FullTime' THEN 1 ELSE 0 END) as FullTime ,
SUM(CASE WHEN JobType='PartTime' THEN 1 ELSE 0 END) as PartTime
FROM t
GROUP BY MonthYear
Pivot solution:
SELECT
[MonthYear],
[FullTime],
[PartTime]
FROM
(values
('01-2014', 'FullTime',1),
('01-2014', 'PartTime',2),
('02-2014', 'FullTime',3),
('03-2014', 'FullTime',4),
('04-2014', 'PartTime',5),
('04-2014', 'PartTime',6),
('04-2014', 'FullTime',7)) x(MonthYear, JobType, JobID)
PIVOT (count(JobType)
for JobType
in([FullTime],[PartTime])
)as p
ORDER BY MonthYear

SQL Server: Sum and inner join

I have two tables:
DepotSessions: ID (int), Date (date), StartTime (int), EndTime (int), TruckID (int)
DepotSessionDetails: ID (int), DepotSessionID (int), Status (varchar(20)), Duration (int)
I need to know how many times each truck was loaded (TotalLoadCount), how long it was loaded (TotalLoadTime) and how much time it spent in the depot (TotalDepotTime).
There can be multiple DepotSessionRows for a given TruckID and Date. Also, there can be multiple DepotSessionDetails rows for a given DepotSessionID.
Some sample data:
DepotSessions:
ID TruckID Date StartTime EndTime
-----------------------------------------------
1 1 '2013-04-01' 500 3000
2 1 '2013-04-01' 14000 25000
DepotSessionDetails:
ID DepotSessionID Status Duration
------------------------------------------
1 1 'Waiting' 40
2 1 'Loading' 25
3 1 'Waiting' 33
4 1 'Loading' 38
5 2 'Waiting' 100
6 2 'Loading' 167
7 2 'Waiting' 420
8 2 'Loading' 980
Based on this sample data, I need to get:
TotalDepotTime 13500 (as in 25000 - 14000 + 3000 - 500)
TotalLoadTime 1210
TotalLoadCount 4
Here's what I have at the moment:
SELECT
DS.Date, DS.TruckID,
MIN(DS.StartTime), MAX(DS.EndTime),
SUM(DS.EndTime-DS.StartTime) TotalDepotTime,
SUM(CASE WHEN DSD.Status = 'Loading' THEN DSD.Duration ELSE 0 END) TotalLoadTime,
COUNT(CASE DSD.Status = 'Loading' THEN 1 ELSE 0 END) TotalLoadCount
FROM
DepotSessions DS
INNER JOIN
DepotSessionDetails DSD on DS.ID = DSD.DepotSessionID
GROUP BY
Date, TruckID
TotalDepotTime 54000 (incorrect, should be 13500)
TotalLoadTime 1210
TotalLoadCount 8 (incorrect, should be 4)
Try this:
SELECT DS.Date, DS.TruckID,
MIN(DS.StartTime), MAX(DS.EndTime),
sum(distinct(DS.EndTime))-sum(distinct(DS.StartTime)) as TotalDepotTime,
SUM( CASE DSD.Status WHEN 'Loading' THEN DSD.Duration ELSE 0 END) TotalLoadTime,
SUM(CASE DSD.Status WHEN 'Loading' THEN 1 ELSE 0 END) TotalLoadCount
FROM DepotSessions DS
INNER JOIN DepotSessionDetails DSD on DS.ID = DSD.DepotSessionID
GROUP BY TruckID, date;
fiddle
divided by the number of DepotSessions rows for that Date and TruckID.
Above line is not clear .
you can try this way,
select
*, TotalDepotTime * TotalLoadCount
from
(SELECT
DS.Date, DS.TruckID, MIN(DS.StartTime), MAX(DS.EndTime),
SUM(DS.EndTime-DS.StartTime) TotalDepotTime,
SUM(CASE DSD.Status WHEN 'Loading' THEN DSD.Duration ELSE 0 END) TotalLoadTime,
COUNT(CASE DSD.Status WHEN 'Loading' THEN 1 ELSE 0 END) TotalLoadCount
FROM
DepotSessions DS
INNER JOIN
DepotSessionDetails DSD ON DS.ID = DSD.DepotSessionID
GROUP BY Date, TruckID) tbl

Sql Query to find Counts

I have a table as below .
Id Product1 Product2 Product3
1 1 null null
2 1 2 null
3 3 1 null
4 2 3 1
Now I would like to write a query to count the entries with Product 1.
In the above case it is 2 for Product1 , 1 for Product2 and 1 for Product 3
I came up with a query something like this.
select
Count(Product1) +
Count(Product2) +
Count(Product3)
from
Table
where Product1 = 1
But it gives me an inaccurate result.
Is there a way I can get the number of occurances for each product ?
Group By
Desired output would be something like this :
ProductID Product1Count Product2Count Product3Count
1 2 1 1
2 1 1 0
3 1 1 0
select Count(CASE WHEN Product1 = 1 THEN 1 END) +
Count(CASE WHEN Product2 = 1 THEN 1 END) +
Count(CASE WHEN Product3 = 1 THEN 1 END)
from Table1
where 1 IN (Product1, Product2, Product3)
SQLFIddle Demo
The reason for adding this line: where 1 IN (Product1, Product2, Product3) is to count only on the affected rows, thus making it more faster than running through all records.
Something like this would work:
SELECT
SUM(CASE WHEN Product1 = 1 THEN 1 ELSE 0 END)
+ SUM(CASE WHEN Product2 = 1 THEN 1 ELSE 0 END)
+ SUM(CASE WHEN Product3 = 1 THEN 1 ELSE 0 END)
FROM Table

Resources