Convert rows to column headers with totals - sql-server

I have the following query:
SELECT
g.Gender,
a.AgeGroup,
count(*) as Count
FROM
client c
INNER JOIN AgeGroup a
ON c.age BETWEEN a.StartRange AND a.EndRange
INNER JOIN Gender G on
C.GenderID = G.GenderID
group by
g.Gender,
a.AgeGroup
order by AgeGroup, Gender
which gives the following results:
Gender AgeGroup Count
Male <=25 4
Unknown <=25 2
Female >35 2223
Male >35 6997
Transgender >35 43
Unknown >35 2
Female 26-35 413
Male 26-35 590
Transgender 26-35 5
What I'm needing to try and do though is convert the Gender column to column headers and include totals.
AgeGroup Male Female Trans Unknown Total
<= 25: 4 0 0 2 6
26 - 35: 590 413 5 0 1008
> 35: 6997 2223 43 2 9265
Total: 7591 2636 48 4 10279
I've got this far:
SELECT *
FROM (
SELECT
g.Gender as [Gender],
a.AgeGroup
FROM
client c
INNER JOIN AgeGroup a
ON c.age BETWEEN a.StartRange AND a.EndRange
INNER JOIN Gender G on
C.GenderID = G.GenderID
) as s
PIVOT
(
COUNT(Gender)
FOR [Gender] IN (Male,Female,Transgender,Unknown)
)AS pvt
which returns this:
AgeGroup Male Female Transgender Unknown
<=25 4 0 0 2
26-35 590 413 5 0
>35 6997 2223 43 2
But I don't have the totals.
Is there a way I can do this?

Try this ..
SELECT *,
(select sum(v)
from
(values(male),
(female),
(transgender),
(unknown))
as val(v)) as total
FROM (
SELECT
g.Gender as [Gender],
a.AgeGroup
FROM
client c
INNER JOIN AgeGroup a
ON c.age BETWEEN a.StartRange AND a.EndRange
INNER JOIN Gender G on
C.GenderID = G.GenderID
) as s
PIVOT
(
COUNT(Gender)
FOR [Gender] IN (Male,Female,Transgender,Unknown)
)AS pvt
For updated requirement:
i recommend putting entire table into Some temp table for readabilty and do this
So your above query would go like this
SELECT *,
(select sum(v)
from
(values(male),
(female),
(transgender),
(unknown))
as val(v)) as total
into #temp
from
rest of pivot query
and then do grouping for total
select
case when grouping(agegroup)=1 then 'total' else agegroup end agegroup,
sum(male) as male,
sum(female) as 'female',
sum(trans) as 'trans',
sum(unknown) as 'unknown',
sum(total) as 'Total'
from #temp
group by
grouping sets
(
(agegroup),
()
)

Related

Return a Date Is null as maximum value in t-sql

I have this table.
ID Date Value
___ ____ _____
3241 9/17/12 5
3241 9/16/12 100
3241 9/15/12 20
4355 9/16/12 12
4355 9/15/12 132
4355 9/14/12 4
1001 NULL 89
1001 9/16/12 125
5555 NULL 89
1234 9/16/12 45
2236 9/15/12 128
2236 9/14/12 323
2002 9/17/12 45
I would like to select the maximum date grouped by id and including NULL as maximum value that should be in the result to get something like that.
ID Date Value
___ ____ _____
3241 9/17/12 5
4355 9/16/12 12
1001 9/16/12 125
5555 NULL 89
1234 9/16/12 45
2236 9/15/12 128
2002 9/17/12 45
I found a solution but that not include NULL as maximum value
the solution by #bluefeet
Return value at max date for a particular id
SELECT t1.id,
t2.mxdate,
t1.value
FROM yourtable t1
INNER JOIN
( SELECT max(date) mxdate,
id
FROM yourtable
GROUP BY id) t2 ON t1.id = t2.id
AND t1.date = t2.mxdate
I also search for a solution to see how can we select NULL maximum value in t-sql so i found this solution by #Damien_The_Unbeliever How can I include null values in a MIN or MAX?
SELECT recordid,
MIN(startdate),
CASE
WHEN MAX(CASE
WHEN enddate IS NULL THEN 1
ELSE 0
END) = 0 THEN MAX(enddate)
END
FROM tmp
GROUP BY recordid
But i m stuck i don't know how to merge between this two solution to get what i want.
PS: I m using SQL SERVER 2008
You can use this
SELECT
ID
,[Date]
,[Value]
FROM(
SELECT
*
, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ISNULL([Date],'9999-12-31') DESC) AS Row#
FROM yourtable
) A WHERE Row# = 1

Distinct values with occurrences count

I want to count the number of times a vendor title occurs in a resultset, but if I use COUNT combined with GROUP BY, I only get either a 0 or 1 in the resultset
e.g. my results now look like this:
id vendortitle cnt
184 Hotel 1
198 A3 1
199 Las Vegas 1
200 Hotel-Restaurant 1
1252 Hansen 1
1253 Sunrise 1
1255 NULL 0
1256 Winsel 1
1257 Olde North 1
1258 A Castle 1
1259 A Castle 1
1262 Restaurant Rich 1
1263 NULL 0
1264 NULL 0
1265 NULL 0
1266 NULL 0
1269 My venue 1
1270 My venue 1
1271 My venue 1
1272 My venue 1
But I want this (I don't really actually need the NULL values):
id vendortitle cnt
184 Hotel 1
198 A3 1
199 Las Vegas 1
200 Hotel-Restaurant 1
1252 Hansen 1
1253 Sunrise 1
1255 NULL 5
1256 Winsel 1
1257 Olde North 1
1258 A Castle 2
1262 Restaurant Rich 1
1269 My venue 4
My SQL statement:
SELECT DISTINCT(vendortitle),id,COUNT(vendortitle) as cnt FROM (select ROW_NUMBER() OVER (ORDER BY vendortitle DESC) as RowNum,
id,vendortitle
FROM
(
SELECT
uf.id,coalesce(l.title, a.title) as vendortitle
FROM userfavorites uf
INNER JOIN vendor_photos vp ON uf.objectid = vp.id
LEFT JOIN homes l on vp.objecttype= 1 and vp.objectid = l.id
LEFT JOIN hotels a on vp.objecttype= 2 and vp.objectid = a.id
) as info
) as allinfo
WHERE RowNum > 0 AND RowNum <= 50
GROUP BY vendortitle,RowNum, id
There are a lot of things in your query that you don't need. The derived table isn't really needed, the DISTINCT and ROW_NUMBER either. This should do the work:
SELECT MIN(uf.id) id,
COALESCE(l.title, a.title) as vendortitle,
COUNT(*) as cnt
FROM userfavorites uf
INNER JOIN vendor_photos vp
ON uf.objectid = vp.id
LEFT JOIN homes l
ON vp.objecttype= 1
AND vp.objectid = l.id
LEFT JOIN hotels a
ON vp.objecttype = 2
AND vp.objectid = a.id
GROUP BY COALESCE(l.title, a.title);

Getting records from a table which have non-null values for a particular column in all months

I have a table:
Project_Id Period Value
123 Jan-15 0
123 Feb-15 34
123 Mar-15 78
123 Apr-15 56
456 Jan-15 0
456 Feb-15 0
456 Mar-15 0
456 Apr-15 0
789 Jan-15 45
789 Feb-15 4
789 Mar-15 18
789 Apr-15 26
I need to retrieve Project data only when i do not have 0 for Value field in all the months like:
Project_Id Period Value
123 Jan-15 0
123 Feb-15 34
123 Mar-15 78
123 Apr-15 56
789 Jan-15 45
789 Feb-15 4
789 Mar-15 18
789 Apr-15 26
Project no 456 should not come in my result because for all the months the value is 0 for that particular project.
Can someone help me with the query?
Use SUM and COUNT to determine the number of 0 Values:
SELECT *
FROM tbl
WHERE project_id IN(
SELECT project_id
FROM tbl
GROUP BY project_id
HAVING SUM(CASE WHEN Value = 0 THEN 1 ELSE 0 END) <> COUNT(*)
)
SQL Fiddle
Another solution is to use EXISTS:
SELECT *
FROM tbl t1
WHERE EXISTS(
SELECT 1 FROM tbl t2 WHERE t2.project_id = t1.project_id AND t2.Value > 0
)
SQL Fiddle
The inner select gets all project_ids that have a least one value that is not 0.
select * from your_table
where project_id in
(
select project_id
from your_table
group by project_id
having sum(case when value <> 0 then 1 else 0 end) > 0
)
Some test data but idea remains the same
create table #test123
(
pid int,
value int
)
insert into #test123
select 1,0
union all
select 1,1
union all
select 2,0
union all
select 2,0
union all
select 3,2
select * from #test123 t2 where exists (select 1 from #test123 t1
where t1.pid=t2.pid
group by pid
having sum(value)>0
)
For performance, I prefer not making a join to check for repeating values:
;WITH CTE as
(
SELECT
Project_Id,
Period,
Value,
max(abs(value)) over (Partition by Period) value
FROM YourTable
)
SELECT
Project_Id,
Period,
Value
FROM CTE
WHERE value > 0
*using abs to check for negative values. If all values are positive, the abs can be omitted.

Count field Pivot table In SQL Server

I have this table - Name : Mytable:
Amount Desc Month Sym code ID
$32,323.00 Bla1 1 121 3 2424221
$4,242.00 Bla1 1 121 3 2424221
$3,535.00 Bla1 1 121 1 3230824
$4,984.00 Bla2 1 433 1 3230824
$47,984.00 Bla2 2 433 1 3230824
$41.00 Bla2 2 433 1 3230824
$3,472.00 Bla6 1 D2 27 2297429
$3,472.00 Bla6 1 D2 27 2297429
$3,239.00 Bla6 2 D2 27 2297429
$4,249.00 Bla8 2 114 24 3434334
ID and Month Stands for for a paycheck. There are 6 paychecks : 1 + 3230824, 2+3230824 etc.
And I want to generate a pivot like this:
Jan Feb
count amount count amount
121 2 40100$ 0 0
433 1 52968$ 1 48025$
D2 1 6944$ 1 3239$
114 0 0 1 4249$
Explanation: 121 is two in Jan because ID = 2424221 got it twice and 3230824 got it one time. The number of of "occurrences" in the paychecks is two.
But, In the amount I sum every thing To get the total sum of money in the paycheck for that Sym.
Same, 433 got the value of 1 in Feb for example because only 3230824 got it (twice).
I started writing this:
SELECT *
FROM (
SELECT
[Sym] as Sym, [Month] as [month], [Amount] as Amount
FROM Mytable
) as T
PIVOT
(
Sum(Amount)
FOR [Month] IN ([1],[2])
)AS piv
Well, The amounts are correct But I don't know how can I pull this count as I explained near the amount in the pivot table.
SELECT
[Sym],
COALESCE(SUM(CASE WHEN [1] IS NULL THEN NULL ELSE [Cnt] END), 0) [Jan Count],
COALESCE(SUM(CASE WHEN [1] IS NULL THEN NULL ELSE [1] END), 0) [Jan Amount],
COALESCE(SUM(CASE WHEN [2] IS NULL THEN NULL ELSE [Cnt] END), 0) [Feb Count],
COALESCE(SUM(CASE WHEN [2] IS NULL THEN NULL ELSE [2] END), 0) [Feb Amount]
FROM (
SELECT
mt1.[Sym] as Sym, mt1.[Month] as [month], mt1.[Amount] as Amount, mt2.[Cnt]
FROM Mytable mt1
JOIN (SELECT COUNT(DISTINCT [ID]) [Cnt], [Sym], [Month]
FROM MyTable
GROUP BY [Sym], [Month]) mt2
ON mt1.[Sym] = mt2.[Sym] AND mt1.[Month] = mt2.[Month]
) as T
PIVOT
(
Sum(Amount)
FOR [Month] IN ([1],[2])
)AS piv
GROUP BY [Sym]
SQL Fiddle

a great select query including count

I have around 20 tables including examination records of students. I tried to figure out my question
(Student ID = sID, i.e. Score 1 : s1) :
StudentsTables : (student reg.data)
sID name surname regDate photo ........
891 Mike Jackson 01.01.2013 82342984.png ....
TableA : (student scores)
sID exam s1 s2 s3 s4
891 6 0 0 0 20 > student 891 attended exam 6
891 10 30 80 100 75 > student 891 attended exam 10
(count = 2)
TableB : (student documents , i.e. : document 1 : d1)
sID d1 d2 d3 d4 d5 d6
891 true false true true true true
(count = 1)
TableC : (student messages)
mID from to subject message
1 10 891 any sub. any message... > student 891 received messages (look "to")
1 10 891 mes2 other message...
1 29 891 mes3 another message...
(count = 3)
TableD : (student payments)
sID pID amount date details
(no student record in this table, count = 0)
..... and similar tables like above.
I want a result like below :
sID name surname scoreCount docCount messageCount paymentCount .....
891 Mike Jackson 2 1 3 0 ...
892 Susan Button 0 3 10 0 ...
893 Ahmad Malisi 1 0 5 2 ...
894 any any 4 1 0 0 ...
...
..
Have you tried this
Select sid,name,surname,
(Select count(*) From student_scores Where Sid = S.Sid ) as scoreCount ,
(Select count(*) From student_documents Where Sid = S.Sid ) as docCount ,
(Select count(*) From student_messages Where to= S.Sid ) as messageCount ,
(Select count(*) From student_payments Where Sid = S.Sid ) as paymentCount ,
.
.
.
From StudentsTables S
Where Sid=891
Select sid,name,surname,
isnull(sscnt,0) ,isnull(sdcnt ,0) ,isnull(spcnt ,0) ,isnull(smcnt,0)
From StudentsTables S
join (Select Sid,count(Sid) sscnt From student_scores group by Sid) ss
on ss.sid=s.sid
join (Select Sid,count(Sid) sdcnt From student_documents group by Sid) sd
on sd.sid=s.sid
join (Select Sid,count(Sid) spcnt From student_payments group by Sid) sp
on sp.sid=s.sid
join (Select Sid,count(Sid) smcnt From student_messages group by Sid) sm
on sm.sid=s.sid
this will query for all SId (s)

Resources