Group by with case when - sql

I have Projects - Issues, one to many relationship.
I want Pending issues and Completed issues for each project.
So, what I have done
SELECT
a.id ,
a.Name,
SUM(CASE WHEN b.StatusId = 3 THEN 1 ELSE NULL END) AS CompletedIssues,
SUM(CASE WHEN b.StatusId != 3 THEN 1 ELSE NULL END) AS PendingIssues
FROM
Projects a
JOIN Issues b
ON a.ID = b.ProjectId
GROUP BY
a.name,
b.StatusId,
a.ID
But it's not giving proper output. see below snap.
There are two separate rows for Completed and pending issues and sometimes more then 2 rows based upon Issues Status ID (See BT5).
Is case when is wrong for this scenario?
what is the proper way to achieve this?

Fix your group by:
select p.id, p.Name,
sum(case when i.StatusId = 3 then 1 else null end) as CompletedIssues,
sum(case when i.StatusId <> 3 then 1 else null end) as PendingIssues
from Projects p join
Issues i
on p.ID = i.ProjectId
group by p.name, p.id;
Note: You may not want else NULL. Normally, you want counts to be zero rather than NULL:
select p.id, p.Name,
sum(case when i.StatusId = 3 then 1 else 0 end) as CompletedIssues,
sum(case when i.StatusId <> 3 then 1 else 0 end) as PendingIssues
from Projects p join
Issues i
on p.ID = i.ProjectId
group by p.name, p.id;
Also, I changed the table aliases to something more meaningful. Don't use meaningless letters such as a and b. Use table abbreviations.

Related

using Query one results to run Query two

SELECT distinct
Pd.Cpd as ' accountnumber'
FROM [RQL_ALK_PMT].[Cts_opps] pd
INNER JOIN [RQL_ALK_PMT].[Cts_opps].dpo.cnms_id metg on metg.cnms_id=me.cnms_id
This code would result with this
Result
accountnumber
1332132
3213123
5641202
6412221
1233242
What I would like to do is when the code above gets the results my bottom code reads them and runs them trough its code. The common denominator here would be the account number because its running through a different table
SELECT
pm.AcctNumb as 'accountnumber'
, SUM(CASE WHEN pm.cusidIN ('cr') THEN 1 ELSE 0 END) AS CA
, SUM(CASE WHEN pm.cusidIN ('gb') THEN 1 ELSE 0 END) AS GB
, SUM(CASE WHEN pm.cusidIN ('tev','offev','Lastev') THEN 1 ELSE 0 END) AS chr
, SUM(CASE WHEN pm.cusidIN
('pm','pr','che' )
THEN 1 ELSE 0 END) AS Act
, SUM(CASE WHEN pm.cusidIN ('supev','tev') THEN 1 ELSE 0 END) AS Fulfillment
FROM ops.medadata pm WITH (NOLOCK)
INNER JOIN mw.pim_acct Ma with (nolock) ON ma.AcctNumb= pm.AcctNumb
Where pm.AcctNumb in ()
GROUP BY
pm.AcctNumb
I have tried doing this the code below but it doesnt seem to work
With counta as (
SELECT distinct
Pd.Cpd as ' accountnumber'
FROM [RQL_ALK_PMT].[Cts_opps] pd
INNER JOIN [RQL_ALK_PMT].[Cts_opps].dpo.cnms_id metg on metg.cnms_id=me.cnms_id
)
SELECT
pm.AcctNumb as 'accountnumber'
, SUM(CASE WHEN pm.cusidIN ('cr') THEN 1 ELSE 0 END) AS CA
, SUM(CASE WHEN pm.cusidIN ('gb') THEN 1 ELSE 0 END) AS GB
, SUM(CASE WHEN pm.cusidIN ('tev','offev','Lastev') THEN 1 ELSE 0 END) AS chr
, SUM(CASE WHEN pm.cusidIN
('pm','pr','che' )
THEN 1 ELSE 0 END) AS Act
, SUM(CASE WHEN pm.cusidIN ('supev','tev') THEN 1 ELSE 0 END) AS Fulfillment
FROM ops.medadata pm WITH (NOLOCK)
INNER JOIN mw.pim_acct Ma with (nolock) ON ma.AcctNumb= pm.AcctNumb
left join counta on Pm.accountnumber = counta.accountnumber
Where pm.AcctNumb in (counta.accountnumber)
GROUP BY
pm.AcctNumb
**im having issue with joining the two tables together**
IN is not an equivalent to a join - but you are treating that way.
Instead think of "IN this LIST" and the list could be supplied by you, or by a subquery e.g.
a list given by the query itself
select * from atable
where acol IN ('a','b','c') -- i.e. the list is hardcoded
or, using a subquery
SELECT ...etc.
WHERE pm.AcctNumb IN (
SELECT Pd.Cpd
FROM [RQL_ALK_PMT].[Cts_opps] pd
INNER JOIN [RQL_ALK_PMT].[Cts_opps].dpo.cnms_id metg on metg.cnms_id=me.cnms_id
)
or, if using a CTE
With counta as (
SELECT Pd.Cpd
FROM [RQL_ALK_PMT].[Cts_opps] pd
INNER JOIN [RQL_ALK_PMT].[Cts_opps].dpo.cnms_id metg on metg.cnms_id=me.cnms_id
)
SELECT ... etc.
WHERE pm.AcctNumb IN (
SELECT Cpd
FROM counta
)
note, it usually is not more efficient to use select distinct when forming a subquery to be used with an IN list.

Retrieving multiple counts from a table per row returns incorrect count results

I am trying to show a list of customers and the number of ratings they've left by type. However the returns from counts are not accurate.
This is happening in SQL Server.
I have put together a representative schema and test data here: http://sqlfiddle.com/#!9/97908f3/5
select customer.custid, customer.name,
(
select count(eventid) from event
where type in ('x', 'y')
and rating = 'good'
and event.stayid = stay.stayid
) as 'Goods',
(
select count(eventid) from event
where type in ('x', 'y')
and rating = 'ok'
and event.stayid = stay.stayid
) as 'OKs',
(
select count(eventid) from event
where type in ('x', 'y')
and rating = 'bad'
and event.stayid = stay.stayid
) as 'Bads'
from customer, stay
where stay.custid = customer.custid
The results show:
custid name Goods OKs Bads
1 Jane 1 0 1
2 Alice 1 0 1
According to the data, Alice shouldn't have the 1 good review.
I have tried the same query as joins but get the same issue.
What am I doing wrong when I am trying to query the same table for multiple counts per row?
You should be using a single query with conditional aggregation here:
SELECT
c.custid,
c.name,
COUNT(CASE WHEN e.rating = 'good' THEN 1 END) AS Goods,
COUNT(CASE WHEN e.rating = 'ok' THEN 1 END) AS Oks,
COUNT(CASE WHEN e.rating = 'bad' THEN 1 END) AS Bads
FROM customer c
LEFT JOIN stay s
ON s.custid = c.custid
LEFT JOIN event e
ON e.stayid = s.stayid AND
e.type IN ('x', 'y')
GROUP BY
c.custid,
c.name;
#Beeblebrox, what Tim suggested is correct. Based on that I made a few below changes.
Select C.CustId, C.Name,
COUNT(CASE WHEN E.Rating = 'good' THEN 1 END) AS Goods,
COUNT(CASE WHEN E.Rating = 'ok' THEN 1 END) AS Oks,
COUNT(CASE WHEN E.Rating = 'bad' THEN 1 END) AS Bads
From Customer C LEFT JOIN Stay S ON S.CustId = C.CustId
LEFT Join Event E On E.CustId = S.CustId And E.Type In ('x', 'y')
Group By C.CustId, C.Name
See the result

compare count columns not recognized

I have some Columns whose values depend on sums for the row info. However, when I get to the where statement, it won't let me compare those values so I can just display the ones with issues. See comment *** in query for issue.
This is what my query looks like:
SELECT
DISTINCT
p.ID
,p.Last
,p.First
,SUM(distinct CASE WHEN pf.facility in ('S','H','E') then 1 ELSE 0 END) as facility_count
,SUM(distinct CASE WHEN (fs.ques_id = 59 AND pf.facility in ('S','H','E') ) THEN 1 ELSE 0 END) AS sum_qst_59
FROM person p
inner JOIN person_facilities pf ON p.ID = pf.ID
LEFT JOIN dbo.ADD_ANSW fs ON p.id = fs.id
WHERE
pf.Facility in ('s', 'h', 'e')
AND
pf.status in ('Active')
AND
facility_count != sum_qst_59 ***--this doesn't work. Says no such columns***
group by p.id, Last, First
order by Last
I saw compare counts, but I can't figure out how to get that to work for my query and output. Any help would be appreciated.
In other words, there are people that belong in multiple facilities (which I'm counting their facilities for each person). Plus I'm counting how many times they have answer 59 for those same facilities. Then I'm comparing the counts because they should be the same if they answered it for all facilities. Then I'm finding where the counts don't match so we can fix it.
*Update -
I'm trying what was suggested but it has the error
Incorrect syntax near keyword 'having'
SELECT
DISTINCT
p.ID
,p.Last
,p.First
--change in having and sum line below
,having SUM(distinct CASE WHEN pf.facility in ('S','H','E') then 1 ELSE 0 END) as facility_count
<>
SUM(distinct CASE WHEN (fs.ques_id = 59 AND pf.facility in ('S','H','E') ) THEN 1 ELSE 0 END) AS sum_qst_59
FROM person p
inner JOIN person_facilities pf ON p.ID = pf.ID
LEFT JOIN dbo.ADD_ANSW fs ON p.id = fs.id
WHERE
pf.Facility in ('s', 'h', 'e')
AND
pf.status in ('Active')
group by p.id, Last, First
order by Last
Update 2: Also tried the following but still incorrect syntax near having -
SELECT
DISTINCT
p.ID
,p.Last
,p.First
,SUM(distinct CASE WHEN pf.facility in ('S','H','E') then 1 ELSE 0 END) as facility_count
,SUM(distinct CASE WHEN (fs.ques_id = 59 AND pf.facility in ('S','H','E') ) THEN 1 ELSE 0 END) AS sum_qst_59
FROM person p
inner JOIN person_facilities pf ON p.ID = pf.ID
LEFT JOIN dbo.ADD_ANSW fs ON p.id = fs.id
WHERE
pf.Facility in ('s', 'h', 'e')
AND
pf.status in ('Active')
--change in having and sum line below
AND --this has incorrect syntax near having
having SUM(distinct CASE WHEN pf.facility in ('S','H','E') then 1 ELSE 0 END)
<>
SUM(distinct CASE WHEN (fs.ques_id = 59 AND pf.facility in ('S','H','E') ) THEN 1 ELSE 0 END)
group by p.id, Last, First
order by Last
Column aliases cannot be used to reference expressions in a WHERE clause. But even if they could you'd be wrong as filters that should take place after aggregation have to be put in a HAVING clause.
Try:
...
HAVING sum(CASE
WHEN pf.facility IN ('S','H','E') THEN
1
ELSE
0
END)
<>
sum(CASE
WHEN fs.ques_id = 59
AND pf.facility IN ('S','H','E') THEN
1
ELSE
0
END)
...
sum(DISTINCT ...) also doesn't seem to make sense. And the DISTINCT in the outer SELECT also could be useless.

Aggregate case when inside non aggregate query

I have a pretty massive query that in its simplest form looks like this:
select r.rep_id, u.user_id, u.signup_date, pi.application_date, pi.management_date, aum
from table1 r
left join table2 u on r.user_id=u.user_id
left join table3 pi on u.user_id=pi.user_id
I need to add one more condition that gives me count of users with non null application date per rep (like: rep 1 has 3 users with filled application dates), and assign it into categories (since 3 users, rep is a certain status category). This looks something like this:
case when sum(case when application_date is not null then 1 else 0 end) >=10 then 'status1'
when sum(case when application_date is not null then 1 else 0 end) >=5 then 'status2'
when sum(case when application_date is not null then 1 else 0 end) >=1 then 'status3'
else 'no_status' end as category
However, if I was to simply add it to the select statement, all reps will becomes of status1 because the sum() is done over all advisors with application dates filled:
select r.rep_id, u.user_id, u.signup_date, pi.application_date, pi.management_date, aum,
(
select case when sum(case when application_date is not null then 1 else 0 end) >=10 then 'status1'
when sum(case when application_date is not null then 1 else 0 end) >=5 then 'status2'
when sum(case when application_date is not null then 1 else 0 end) >=1 then 'status3'
else 'no_status' end as category
from table3
) as category
from table1 r
left join table2 u on r.user_id=u.user_id
left join table3 pi on u.user_id=pi.user_id
Can you assist with having the addition to my query to be across reps and not overall? Much appreciated!
Based on your description, I think you need a window function:
select r.rep_id, u.user_id, u.signup_date, pi.application_date, pi.management_date, aum,
count(pi.application_date) over (partition by r.rep_id) as newcol
from table1 r left join
table2 u
on r.user_id = u.user_id left join
table3 pi
on u.user_id = pi.user_id;
You can use the count() in a case to get ranges, if that is what you prefer.

How to get multiple counts in one sql query across multiple tables

I have 2 tables
Company & products
I need to get 2 counts. One is the total count of products and the secondly count of products for sale_flg=1
This SQL does not seem to work..Tried several other ways..not able to get the expected results
SELECT A.COMPANY_NAME, COUNT(B.PRODUCT_ID) AS TOTAL_COUNT_OF_PRODUCTS,
(CASE WHEN B.SALEFLG =1 THEN 1 END) AS COUNT_OF_SALES
FROM COMPANY A LEFT JOIN
PRODUCT B
ON B.COMPANY_ID = A.COMPANY_ID
GROUP BY A.COMPANY_NAME
I think you just need a sum for the case:
SELECT C.COMPANY_NAME, COUNT(P.PRODUCT_ID) AS TOTAL_COUNT_OF_PRODUCTS,
SUM(CASE WHEN P.SALEFLG = 1 THEN 1 ELSE 0 END) AS COUNT_OF_SALES
FROM COMPANY C LEFT JOIN
PRODUCT P
ON P.COMPANY_ID = C.COMPANY_ID
GROUP BY C.COMPANY_NAME ;
If you have B.SALEFLG = 1 or 0 for you may try
Sum(B.SALEFLG) AS COUNT_OF_SALES
Or use UNION
If you use count then in else you should consider null because null is not consider in count aggregation and if you have B.SALEFLG =1 or 0 then use sum aggregation.
You can try below code:
SELECT A.COMPANY_NAME, COUNT(B.PRODUCT_ID) AS TOTAL_COUNT_OF_PRODUCTS,
count(CASE WHEN B.SALEFLG =1 THEN 1 else null END) AS COUNT_OF_SALES
FROM COMPANY A LEFT JOIN
PRODUCT B
ON B.COMPANY_ID = A.COMPANY_ID
GROUP BY A.COMPANY_NAME
OR try this:
SELECT A.COMPANY_NAME, COUNT(B.PRODUCT_ID) AS TOTAL_COUNT_OF_PRODUCTS,
sum(B.SALEFLG) AS COUNT_OF_SALES
FROM COMPANY A LEFT JOIN
PRODUCT B
ON B.COMPANY_ID = A.COMPANY_ID
GROUP BY A.COMPANY_NAME
This SQL server query is working.
Company Table and Product Table
Company Table CompanyID is join with Product table and sales_flg add in product table .
sales_flg = 1 record display in CntSalesflg
select Comp.CompID as CompID, COUNT(Pro.ProductID) as CntProdustID,
SUM(CASE WHEN Pro.SalesflagID = 1 THEN 1 ELSE 0 END) as CntSalesflg
from Product as Pro
inner join Company as Comp on Pro.CompID = Comp.CompID
GROUP by Comp.CompID