Columns in sql query are not grouped - sql

I've a problem with the following sql select query. The columns are not aggregated by the group by command.
SELECT
Dept.Name AS DeptName, COUNT (T.Id) AS TotalServiceNumber,
(Case when SS.Status <> 'Resolved' then COUNT (T.Id) end) AS UnresolvedNumber,
(Case when T.FixTime < '120' then COUNT(T.FixTime) end) AS ResolvedLessThanTwoHoursNumber,
(Case when T.FixTime > '120' then COUNT(T.FixTime) end) AS ResolvedMoreThanTwoHoursNumber,
FROM
dbo.Tickets AS T,
dbo.ServiceStatuses AS SS,
dbo.ComputerDesks AS Desk,
dbo.Personnels AS Person,
dbo.Departments AS Dept
WHERE
SS.Id = T.ServiceStatusId
AND T.ComputerDeskId = Desk.Id
AND Desk.PersonnelId = Person.Id
AND Person.DepartmentId = Dept.Id
GROUP BY
Dept.Name, SS.Status, T.FixTime
I'm getting the following result:
DeptName | TotalServiceNr | UnresolvedNumber | LessThanTwo | MoreThanTwo
DeptA | 8 | NULL | 8 | NULL
DeptB | 1 | 1 | NULL | 1
DeptC | 4 | NULL | NULL | 4
DeptA | 38 | NULL | NULL | 38
DeptB | 55 | NULL | 55 | NULL
DeptC | 7 | NULL | 7 | NULL
...
Expected result:
DeptName | TotalServiceNr | UnresolvedNumber | LessThanTwo | MoreThanTwo
DeptA | 46 | NULL | 8 | 38
DeptB | 56 | 1 | 55 | NULL
DeptC | 11 | NULL | 7 | 4
What I need to change to get the expected result?

try this query:
SELECT
Dept.Name AS DeptName, COUNT (T.Id) AS TotalServiceNumber,
sum(Case when SS.Status <> 'Resolved' then 1 else 0 end) AS UnresolvedNumber,
sum(Case when T.FixTime <= '120' then 1 else 0 end) AS ResolvedLessThanTwoHoursNumber,
sum(Case when T.FixTime > '120' then 1 else 0 end) AS ResolvedMoreThanTwoHoursNumber,
FROM
dbo.Tickets AS T,
dbo.ServiceStatuses AS SS,
dbo.ComputerDesks AS Desk,
dbo.Personnels AS Person,
dbo.Departments AS Dept
WHERE
SS.Id = T.ServiceStatusId
AND T.ComputerDeskId = Desk.Id
AND Desk.PersonnelId = Person.Id
AND Person.DepartmentId = Dept.Id
GROUP BY
Dept.Name

Try this
SELECT TotalServiceNumber, SUM(UnresolvedNumber), SUM(ResolvedLessThanTwoHoursNumber), SUM(ResolvedMoreThanTwoHoursNumber)
FROM (
SELECT
Dept.Name AS DeptName, COUNT (T.Id) AS TotalServiceNumber,
(Case when SS.Status <> 'Resolved' then COUNT (C.Id) end) AS UnresolvedNumber,
(Case when T.FixTime < '120' then COUNT(T.FixTime) end) AS ResolvedLessThanTwoHoursNumber,
(Case when T.FixTime > '120' then COUNT(T.FixTime) end) AS ResolvedMoreThanTwoHoursNumber,
FROM
dbo.Tickets AS T,
dbo.ServiceStatuses AS SS,
dbo.ComputerDesks AS Desk,
dbo.Personnels AS Person,
dbo.Departments AS Dept
WHERE
SS.Id = T.ServiceStatusId
AND T.ComputerDeskId = Desk.Id
AND Desk.PersonnelId = Person.Id
AND Person.DepartmentId = Dept.Id
GROUP BY Dept.Name, SS.Status, T.FixTime
) GROUPED
GROUP BY
TotalServiceNumber

SELECT
Dept.Name AS DeptName
, COUNT (T.Id) AS TotalServiceNumber
,COUNT(Case when SS.Status <> 'Resolved' then 1 ELSE NULL end) AS UnresolvedNumber
,COUNT(Case when T.FixTime < '120' then 1 ELSE NULL end) AS ResolvedLessThanTwoHoursNumber
,COUNT(Case when T.FixTime > '120' then 1 ELSE NULL end) AS ResolvedMoreThanTwoHoursNumber
FROM
dbo.Tickets AS T INNER JOIN dbo.ServiceStatuses AS SS
ON SS.Id = T.ServiceStatusId
INNER JOIN dbo.ComputerDesks AS Desk
ON T.ComputerDeskId = Desk.Id
INNER JOIN dbo.Personnels AS Person
ON Desk.PersonnelId = Person.Id
INNER JOIN dbo.Departments AS Dept
Person.DepartmentId = Dept.Id
GROUP BY Dept.Name
Also use ON syntax for your joins.

Related

How to query all months from January to December

How to query all months from January to December for all values. The values of 0 should also be presented in query result.
My query:
SELECT *
FROM
(SELECT
MONTH(begin_ts) AS [Month],
SUM(CASE
WHEN bmktonr = '7'
THEN dauer
ELSE reserve1
END) + SUM(CASE
WHEN bmktonr = '11'
THEN dauer
ELSE reserve1
END) AS Prozess_Verfügbarkeit,
SUM(CASE
WHEN bmktonr = '1'
THEN dauer
ELSE reserve1
END) + SUM(CASE
WHEN bmktonr = '2'
THEN dauer
ELSE reserve1
END) AS Verfügbarkeit
FROM
[hydra1].[hydadm].[v_ereignis]
WHERE
masch_nr = 'FIMI1'
AND YEAR(begin_ts) = YEAR(CURRENT_TIMESTAMP)
GROUP BY
MONTH(begin_ts)) T
INNER JOIN
(SELECT
p.masch_nr,
SUM(b.ruest_zeit) AS SOLLRüsten,
SUM(b.bearb_zeit) AS SOLLProduktion,
SUM(b.ruest_zeit_zuschl) AS SOLLZuschlag,
SUM(p.bmk_07) AS ISTRüsten,
SUM(p.bmk_11) AS ISTProduktion,
MONTH(prot_dat) AS Month
FROM
[hydra1].[hydadm].[v_auftrag_status] p
JOIN
[hydra1].[hydadm].[v_auftrags_bestand] b ON b.auftrag_nr = p.auftrag_nr
WHERE
p.masch_nr = 'GEORG'
AND a_status = 'E'
AND YEAR(prot_dat) = YEAR(CURRENT_TIMESTAMP)
GROUP BY
p.masch_nr, MONTH(prot_dat)) T1 ON T.Month = T1.Month
ORDER BY
T.Month
This is how it should look then:
Month | Prozess_Verfügbarkeit | Verfügbarkeit
------+-----------------------+--------------
1 | 344 | 4556
2 | 0 | 0
3 | 0 | 0
4 | 0 | 0
5 | 0 | 0
6 | 0 | 0
7 | 0 | 0
8 | 0 | 0
9 | 0 | 0
10 | 0 | 0
11 | 0 | 0
12 | 0 | 0
Thanks a lot.
Something like this ought to do it:
WITH months AS (
SELECT 1 AS month_number
UNION ALL SELECT 2
UNION ALL SELECT 3
...
UNION ALL SELECT 12
)
SELECT months.month_number
, your_query.thing_a
, your_query.thing_b
FROM months
LEFT
JOIN your_query
ON your_query.Month = months.month_number
;

Formatting multiple SELECT statements with PIVOT

Currently have a script that unions around a dozen SELECT statements, and example of two of these along with an example of the results is shown below.
DECLARE #Age TABLE (name VARCHAR(30), total FLOAT, percentage FLOAT)
INSERT INTO #Age
SELECT '0-18', (SELECT COUNT(*) FROM tblPerson p
INNER JOIN tblClient c ON c.intPersonID = p.intPersonID
WHERE ISNULL(dbo.fncReportClient_Age(p.dteBirthdate, GETDATE()), '') >= 0 AND ISNULL(dbo.fncReportClient_Age(p.dteBirthdate, GETDATE()), '') <= 18), ''
UPDATE #Age
SET percentage = ROUND((SELECT total FROM #Age WHERE name = '0-18')/(SELECT SUM(total) FROM #Age) * 100, 2)
FROM #Age
WHERE name = '0-18'
Etc.
SELECT
g.nvhGenderName,
COUNT(*),
ROUND(COUNT(*) * 1.0 / SUM(COUNT(*)) OVER () * 100, 2)
FROM
tblClient c
LEFT JOIN tblPerson p ON p.intPersonID = c.intPersonID
LEFT JOIN tblGender g ON g.intGenderID = p.intGenderID
GROUP BY g.nvhGenderName
UNION ALL
SELECT * FROM #Age
Results example below:
Name | Total | % |
---------------------------------
Male | 6514 | 60.32 |
Female | 4285 | 39.68 |
0-18 | 279 | 1.58 |
19-24 | 1748 | 9.93 |
25-34 | 5423 | 30.80 |
35-64 | 9546 | 54.21 |
65+ | 614 | 3.50 |
I would like to display these results horizontally as opposed to vertically, I think it is possible to do this with PIVOT but have never really used them. An example of how I want the data to be displayed is shown below:
Gender | Total | % | Age | Total | % |
-------------------------------------------------------------
Male | 6514 | 60.32 | 0-18 | 279 | 1.58 |
Female | 4285 | 39.68 | 19-24 | 1748 | 9.93 |
| | | 25-34 | 5423 | 30.80 |
| | | 35-64 | 9546 | 54.21 |
| | | 65+ | 614 | 3.50 |
In particular I am not sure how I would use a pivot to combine the multiple (12) SELECT statements that require it.
Any help on how to format this would be much appreciated.
Whilst I believe the layout really should be achieved elsewhere, the following may work for you. Clearly I cannot test it so, without the benefit of testing here goes:
WITH myCTE AS (
SELECT
COUNT(CASE WHEN oa.age >= 0 AND oa.age < 19 THEN p.intPersonID ELSE NULL END) c0019
, COUNT(CASE WHEN oa.age >= 19 AND oa.age < 25 THEN p.intPersonID ELSE NULL END) c1925
, COUNT(CASE WHEN oa.age >= 25 AND oa.age < 35 THEN p.intPersonID ELSE NULL END) c2535
, COUNT(CASE WHEN oa.age >= 35 AND oa.age < 65 THEN p.intPersonID ELSE NULL END) c3565
, COUNT(CASE WHEN oa.age >= 65 THEN p.intPersonID ELSE NULL END) c65on
, COUNT(CASE WHEN g.nvhGenderName = 'Male' THEN p.intPersonID ELSE NULL END) cmale
, COUNT(CASE WHEN g.nvhGenderName = 'Female' THEN p.intPersonID ELSE NULL END) cfemale
, COUNT(*) ctotal
FROM tblClient c
LEFT JOIN tblPerson p ON p.intPersonID = c.intPersonID
OUTER APPLY (
SELECT
dbo.fncReportClient_Age(p.dteBirthdate) AS age
) AS oa
LEFT JOIN tblGender g ON g.intGenderID = p.intGenderID
)
SELECT
ca.Gender, ca.Total2, ca.Pct, ca.Age, ca.Total2, ca.Pct2
FROM myCTE
CROSS APPLY (
VALUES
(1, 'Male' , t.cmale , (cmale * 100.0 / ctotal), '0-18', c0019, (c0019 * 100.0 / ctotal))
, (2, 'Female',t.cfemale,(cfemale * 100.0 / ctotal), '19-24', c1925, (c1925 * 100.0 / ctotal))
, (3, NULL,NULL,NULL, '25-34', c2535, (c2535 * 100.0 / ctotal))
, (4, NULL,NULL,NULL, '35-64', c3565, (c3565 * 100.0 / ctotal))
, (5, NULL,NULL,NULL, '65+' , c65on, (c65on * 100.0 / ctotal))
) AS ca (rn, Gender, Total2, Pct, Age, Total2, Pct2)
ORDER BY ca.rn
;
The second (lower) part of the query above uses a technique for unpivoting data that combines cross apply with values and this allows us to "layout" each row of the wanted final result row by row.
Using a CTE (the upper part of the query above) isn't essential, it could be moved into a subquery instead, but the query inside the CTE should be trialed standalone first and it should produce all the numbers you need in one pass of the data (assuming that the gender table doesn't disturb the count results). Note that using count(case expression here) removes the need for multiple separate queries. I suspect you don't need left joins by the way, and if that is true you could also change the outer apply to a cross apply. Note that the apply is used to execute your function, and by doing it ths way we are able to reference the result of that function by an alias in the remainder of the query (I used "age" as that alias).
I am unsure why you involve a client table when counting the persons table. I suspect it isn't needed. If my suspicions are correct the CTE detail could be replaced by this:
SELECT
COUNT(CASE WHEN oa.age >= 0 AND oa.age < 19 THEN 1 ELSE NULL END) c0019
, COUNT(CASE WHEN oa.age >= 19 AND oa.age < 25 THEN 1 ELSE NULL END) c1925
, COUNT(CASE WHEN oa.age >= 25 AND oa.age < 35 THEN 1 ELSE NULL END) c2535
, COUNT(CASE WHEN oa.age >= 35 AND oa.age < 65 THEN 1 ELSE NULL END) c3565
, COUNT(CASE WHEN oa.age >= 65 THEN 1 ELSE NULL END) c65on
, COUNT(CASE WHEN g.nvhGenderName = 'Male' THEN 1 ELSE NULL END) cmale
, COUNT(CASE WHEN g.nvhGenderName = 'Feale' THEN 1 ELSE NULL END) cfemale
, COUNT(*) ctotal
FROM tblPerson p
CROSS APPLY (
SELECT
dbo.fncReportClient_Age(p.dteBirthdate) AS age
) AS oa
INNER JOIN tblGender g ON g.intGenderID = p.intGenderID
Create VIEW view_name AS
SELECT * FROM (
select ColumnName1,ColumnName2 from TableName
) as s
PIVOT (
Sum(ColumnName2)
FOR ColumnName3 in ("Row1","Row2","Row3"
)
) As pvt
DROP VIEW view_name;
Select * from view_name

Aggregative sum of objects belonging to objects residing inside hierarchy structure

My problem is similar in a way to this one, yet different enough in my understanding.
I have three tables:
Units ([UnitID] int, [UnitParentID] int)
Students ([StudentID] int, [UnitID] int)
Events ([EventID] int, [EventTypeID] int, [StudentID] int)
Students belong to units, units are stacked in a hierarchy (tree form - one parent per child), and each student can have events of different types.
I need to sum up the number of events of each type per user, then aggregate for all users in a unit, then aggregate through hierarchy until I reach the mother of all units.
The result should be something like this:
My tools are SQL Server 2008 and Report Builder 3.
I put up a SQL fiddle with sample data for fun.
Use this query:
;WITH CTE(Id, ParentId, cLevel, Title, ord) AS (
SELECT
u.UnitID, u.UnitParentID, 1,
CAST('Unit ' + CAST(ROW_NUMBER() OVER (ORDER BY u.UnitID) AS varchar(3)) AS varchar(max)),
CAST(RIGHT('000' + CAST(ROW_NUMBER() OVER (ORDER BY u.UnitID) AS varchar(3)), 3) AS varchar(max))
FROM
dbo.Units u
WHERE
u.UnitParentID IS NULL
UNION ALL
SELECT
u.UnitID, u.UnitParentID, c.cLevel + 1,
c.Title + '.' + CAST(ROW_NUMBER() OVER (PARTITION BY c.cLevel ORDER BY c.Id) AS varchar(3)),
c.ord + RIGHT('000' + CAST(ROW_NUMBER() OVER (ORDER BY u.UnitID) AS varchar(3)), 3)
FROM
dbo.Units u
JOIN
CTE c ON c.Id = u.UnitParentID
WHERE
u.UnitParentID IS NOT NULL
), Units AS (
SELECT
u.Id, u.ParentId, u.cLevel, u.Title, u.ord,
SUM(CASE WHEN e.EventTypeId = 1 THEN 1 ELSE 0 END) AS EventA,
SUM(CASE WHEN e.EventTypeId = 2 THEN 1 ELSE 0 END) AS EventB,
SUM(CASE WHEN e.EventTypeId = 3 THEN 1 ELSE 0 END) AS EventC,
SUM(CASE WHEN e.EventTypeId = 4 THEN 1 ELSE 0 END) AS EventD
FROM
CTE u
LEFT JOIN
dbo.Students s ON u.Id = s.UnitId
LEFT JOIN
dbo.[Events] e ON s.StudentId = e.StudentId
GROUP BY
u.Id, u.ParentId, u.cLevel, u.Title, u.ord
), addStudents AS (
SELECT *
FROM Units
UNION ALL
SELECT
s.StudentId, u.Id, u.cLevel + 1,
'Student ' + CAST(s.StudentId AS varchar(3)),
u.ord + RIGHT('000' + CAST(s.StudentId AS varchar(3)), 0),
SUM(CASE WHEN e.EventTypeId = 1 THEN 1 ELSE 0 END),
SUM(CASE WHEN e.EventTypeId = 2 THEN 1 ELSE 0 END),
SUM(CASE WHEN e.EventTypeId = 3 THEN 1 ELSE 0 END),
SUM(CASE WHEN e.EventTypeId = 4 THEN 1 ELSE 0 END)
FROM Units u
JOIN
dbo.Students s ON u.Id = s.UnitId
LEFT JOIN
dbo.[Events] e ON s.StudentId = e.StudentId
GROUP BY
s.StudentID, u.ID, u.cLevel, u.ord
)
SELECT --TOP(10)
REPLICATE(' ', cLevel) + Title As Title,
EventA, EventB, EventC, EventD
FROM
addStudents
ORDER BY
ord
For this:
Title | EventA | EventB | EventC | EventD
-----------------+--------+---------+--------+--------
Unit 1 | 0 | 1 | 0 | 0
Student 6 | 0 | 1 | 0 | 0
Unit 1.1 | 0 | 0 | 0 | 1
Student 21 | 0 | 0 | 0 | 1
Student 33 | 0 | 0 | 0 | 0
Unit 1.1.1 | 0 | 0 | 0 | 0
Student 23 | 0 | 0 | 0 | 0
Unit 1.1.1.1 | 3 | 2 | 3 | 0
Student 10 | 0 | 0 | 0 | 0
Student 17 | 1 | 0 | 0 | 0
...
SQL Fiddle Demo
Do you need also the hierarchy to be sorted / visualized? At least this will calculate the sums, but the order of the data is pretty random :)
;with CTE as (
select S.StudentId as UnitID, S.UnitId as UnitParentID,
S.StudentID, 'Student' as Type
from Students S
union all
select U.UnitId, U.UnitParentId,
CTE.StudentId as StudentID, 'Unit ' as Type
from
Units U
join CTE
on U.UnitId = CTE.UnitParentId
)
select C.Type + ' ' + convert(varchar, C.UnitId),
sum(case when EventTypeId = 1 then 1 else 0 end) as E1,
sum(case when EventTypeId = 2 then 1 else 0 end) as E2,
sum(case when EventTypeId = 3 then 1 else 0 end) as E3,
sum(case when EventTypeId = 4 then 1 else 0 end) as E4
from
CTE C
left outer join events E on C.StudentId = E.StudentId
group by
C.Type, C.UnitId
SQL Fiddle
If you need also the hierarchy to be in order, you'll probably have add few extra CTEs to get the numbering from top down with something like #shA.t did. This gathers the hierarchy separately for each student, so it's not really possible to add the level numbers in a simple way.

Aggregation based on another column values

Assume I have the following table:
+------------+-------------+
| Product_id | customer_id |
+------------+-------------+
| a | c1 |
| a | c2 |
| a | c3 |
| a | c4 |
| b | c1 |
| c | c1 |
| b | c2 |
| d | c2 |
+------------+-------------+
I want to find the number of (a, b, c) products purchases per customer and the number of (a, b, d) products purchases per customer. I tried to use COUNT with GROUP BY but I only managed to the find the number purchases of each customers FIDDLE. Do I need to use CASE WHEN or DECODE? How can I achieve that?
The expected output is something like:
+-------------+-------------+-------------+
| CUSTOMER_ID | ABC_PRODUCT | ABD_PRODUCT |
+-------------+-------------+-------------+
| c1 | 1 | 0 |
| c2 | 0 | 1 |
| c3 | 0 | 0 |
| c4 | 0 | 0 |
+-------------+-------------+-------------+
You can do this with a single aggregation and no subqueries. The key is using a nested case statement with aggregation to count each product for each customer. The following determines whether a customer has each "bundle":
SELECT CUSTOMER_ID,
(case when max(case when product_id = 'a' then 1 else 0 end) +
max(case when product_id = 'b' then 1 else 0 end) +
max(case when product_id = 'c' then 1 else 0 end) = 3
then 1
else 0
end) as ABC,
(case when max(case when product_id = 'a' then 1 else 0 end) +
max(case when product_id = 'b' then 1 else 0 end) +
max(case when product_id = 'd' then 1 else 0 end) = 3
then 1
else 0
end) as ABD
FROM CUSTOMERS_SALES
GROUP BY CUSTOMER_ID;
Now, your question is actually about the number of such purchases. So, I suppose a customer could purchase each item twice, and you would want them counted twice. If so, then the number is the least value of any counts. You can get this as well:
SELECT CUSTOMER_ID,
least(sum(case when product_id = 'a' then 1 else 0 end),
sum(case when product_id = 'b' then 1 else 0 end),
sum(case when product_id = 'c' then 1 else 0 end)
) as ABC,
least(sum(case when product_id = 'a' then 1 else 0 end),
sum(case when product_id = 'b' then 1 else 0 end),
sum(case when product_id = 'd' then 1 else 0 end)
) as ABD
FROM CUSTOMERS_SALES
GROUP BY CUSTOMER_ID;
Please try below query to find customer having the products a, b and c:
SELECT CUSTOMER_ID
FROM CUSTOMERS_SALES
WHERE PRODUCT_ID IN ('a', 'b', 'c')
GROUP BY CUSTOMER_ID
HAVING COUNT(DISTINCT PRODUCT_ID)=3
To get the count try:
SELECT COUNT(*) FROM(
SELECT CUSTOMER_ID
FROM CUSTOMERS_SALES
WHERE PRODUCT_ID IN ('a', 'b', 'd')
GROUP BY CUSTOMER_ID
HAVING COUNT(DISTINCT PRODUCT_ID)=3
)x
Based entirely off #TechDo's example:
SELECT DISTINCT CUSTOMER_ID,
DECODE((SELECT CUSTOMER_ID
FROM CUSTOMERS_SALES CS2
WHERE PRODUCT_ID IN ('A', 'B', 'C')
AND CS2.CUSTOMER_ID = CS.CUSTOMER_ID
GROUP BY CUSTOMER_ID
HAVING COUNT(DISTINCT PRODUCT_ID)=3), NULL, 0, 1) AS ABC_PRODUCT,
DECODE((SELECT CUSTOMER_ID
FROM CUSTOMERS_SALES CS2
WHERE PRODUCT_ID IN ('A', 'B', 'D')
AND CS2.CUSTOMER_ID = CS.CUSTOMER_ID
GROUP BY CUSTOMER_ID
HAVING COUNT(DISTINCT PRODUCT_ID)=3), NULL, 0, 1) AS ABD_PRODUCT
FROM CUSTOMERS_SALES CS
ORDER BY CUSTOMER_ID
SELECT CUSTOMERS_SALES.CUSTOMER_ID,NVL(MAX(abc.CUSTOMER_ID),0) as ABC_PRODUCT ,NVL(MAX(abd.CUSTOMER_ID),0) as ABD_PRODUCT FROM CUSTOMERS_SALES
LEFT JOIN
(SELECT CUSTOMER_ID
FROM CUSTOMERS_SALES
WHERE PRODUCT_ID IN ('a', 'b', 'd')
GROUP BY CUSTOMER_ID
HAVING COUNT(DISTINCT PRODUCT_ID)=3) abd
ON abd.CUSTOMER_ID=CUSTOMERS_SALES.CUSTOMER_ID
LEFT JOIN
(SELECT CUSTOMER_ID
FROM CUSTOMERS_SALES
WHERE PRODUCT_ID IN ('a', 'b', 'c')
GROUP BY CUSTOMER_ID
HAVING COUNT(DISTINCT PRODUCT_ID)=3) abc
ON abc.CUSTOMER_ID=CUSTOMERS_SALES.CUSTOMER_ID
GROUP BY CUSTOMERS_SALES.CUSTOMER_ID
ORDER BY CUSTOMERS_SALES.CUSTOMER_ID;
FIDDLE

Group by does not show all the rows

I have a table tblPersonaldata and tblStudentsadmitted
tblPersonalData
UID Name Gender
------------------------
E1 xyz M
E2 pqr M
E3 mno M
tblStudentsadmitted
UID Status Stage
----------------------
E1 Y 1
E2 Y 2
E3 Y 1
Now I want the data like this:
Gender Stage1 Stage2
M 2 1
But in this case I dont get the data for female gender. I want the data for female gender even if it is null
I have tried this:
select
case
when gender='M' then 'Male'
when gender='F' then 'Female'
end as Gender,
sum(case when Stage=1 then 1 else 0) end as Stage1,
sum(case when Stage=2 then 1 else 0) end as Stage2
from tblPersonaldata A inner join
tblStudentsadmitted B on A.UID=B.UID
where B.Status='Y'
group by Gender
SELECT CASE WHEN a.Gender = 'M' THEN 'Male' ELSE 'FEMALE' END Gender,
SUM(CASE WHEN Stage = 1 THEN 1 ELSE 0 END) Stage1,
SUM(CASE WHEN Stage = 2 THEN 1 ELSE 0 END) Stage2
FROM personal a
LEFT JOIN studentadmitted b
ON a.UID = b.UID AND b.Status = 'Y'
GROUP BY a.Gender
SQLFiddle Demo
SELECT CASE WHEN c.Gender = 'M' THEN 'Male' ELSE 'Female' END Gender,
SUM(CASE WHEN Stage = 1 THEN 1 ELSE 0 END) Stage1,
SUM(CASE WHEN Stage = 2 THEN 1 ELSE 0 END) Stage2
FROM (SELECT 'F' Gender UNION SELECT 'M' Gender) c
LEFT JOIN personal a
ON a.Gender = c.Gender
LEFT JOIN studentadmitted b
ON a.UID = b.UID AND b.Status = 'Y'
GROUP BY c.Gender
SQLFiddle Demo
OUTPUT
╔════════╦════════╦════════╗
║ GENDER ║ STAGE1 ║ STAGE2 ║
╠════════╬════════╬════════╣
║ Female ║ 0 ║ 0 ║
║ Male ║ 2 ║ 1 ║
╚════════╩════════╩════════╝
In SQL Server, you can use the PIVOT function to generate the result:
select gender,
Stage1,
Stage2
from
(
select
c.gender,
'Stage'+cast(stage as varchar(10)) Stage
from (values ('F'),('M')) c (gender)
left join tblpersonaldata p
on c.gender = p.gender
left join tblStudentsadmitted s
on p.uid = s.uid
and s.Status='Y'
)src
pivot
(
count(stage)
for stage in (Stage1, Stage2)
) piv
See SQL Fiddle with Demo.
Since you are using SQL Server 2008 this query uses the VALUES to generate the list of the genders that you want in the final result set
from (values ('F'),('M')) c (gender)
Then by using a LEFT JOIN on the other tables the final result will return a row for both the M and F values.
This can also be written using a UNION ALL to generate the list of genders:
select gender,
Stage1,
Stage2
from
(
select
c.gender,
'Stage'+cast(stage as varchar(10)) Stage
from
(
select 'F' gender union all
select 'M' gender
) c
left join tblpersonaldata p
on c.gender = p.gender
left join tblStudentsadmitted s
on p.uid = s.uid
and s.Status='Y'
)src
pivot
(
count(stage)
for stage in (Stage1, Stage2)
) piv
See SQL Fiddle with Demo
The result of both is:
| GENDER | STAGE1 | STAGE2 |
----------------------------
| F | 0 | 0 |
| M | 2 | 1 |
This is also working. Using Left joins with a new table (a table with two records for genders M & F).
Fiddle demo
select t.g Gender,
isnull(sum(case when Stage = 1 then 1 end),0) Stage1,
isnull(sum(case when Stage = 2 then 1 end),0) Stage2
from (values ('M'),('F')) t(g)
left join personal a on t.g = a.gender
left join studentadmitted b on a.uid = b.uid and b.Status = 'Y'
group by t.g
order by t.g
| GENDER | STAGE1 | STAGE2 |
----------------------------
| F | 0 | 0 |
| M | 2 | 1 |
SELECT GENDER, 0 AS 'STAGE 0', 1 AS 'STAGE 1', 2 AS 'STAGE 2'
FROM
(
SELECT P.ID, GENDER,CASE WHEN STAGE IS NULL THEN 0 ELSE STAGE END STAGE
FROM tblPersonaldata P
LEFT JOIN tblStudentsadmitted S ON P.UID = S.UID
) AS A
PIVOT
(
COUNT (ID) FOR STAGE IN ([0],[1],[2])
)P