Multiple conditions in SQL - sql

I have following table:
Employee ID Employee Status Date of Termination
1 A NULL
2 A NULL
3 I 1/1/2016
4 I 12/15/2016
5 I 1/1/2016
I would like to report on the following:
Number of current active employees - 2
Number of inactive employees - 3
Number of employees terminated in last one month - 2
This is the piece of code I used:
select
case when employee_status='A' then count(employee_id) else '' end,
case when employee_status='I' then count(employee_id) else '' end,
case when employee_status='I'
then
(select count(employee_id)
from employee
where date_of_termination between '1/1/2016' and '2/1/2016')
else '' end
from employee
My result set is:
Active | Inactive | Inactive_last_month
2 | 0 | 0
0 | 3 | 2
I would like to achieve the following:
Active | Inactive | Inactive_last_month
2 | 3 | 2
Any recommendations will be appreciated.

You need to SUM up the number of rows that match each criteria:
SELECT
SUM(CASE WHEN date_of_termination IS NULL THEN 1 ELSE 0 END) AS active,
SUM(CASE WHEN date_of_termination IS NOT NULL THEN 1 ELSE 0 END) AS inactive,
SUM(CASE WHEN date_of_termination BETWEEN '20160101' AND '20160201' THEN 1 ELSE 0 END) AS inactive_last_month
FROM
Employee
I've ignored the employee_status column with the assumption that the date is sufficient to determine whether or not the employee is active/inactive - in which case that column probably shouldn't even exist in the table since it's duplicating data.

This should be possible to simplify it using SUM :
select
sum(case when employee_status='A' then 1 else 0 end) as active,
sum(case when employee_status='I' then 1 else 0 end) as inactive,
sum(case when employee_status='I' and date_of_termination between '1/1/2016' and '2/1/2016' then 1 else 0 end) as inactive_last_month
from employee

I woudl wrap the case satements in sum() function and also modify the ELSE part of the CASE Statement to be 0.
so it will look like something like this:
select
SUM(case when employee_status='A' then count(employee_id) else 0 end) AS Active,
SUM(case when employee_status='I' then count(employee_id) else 0 end) AS Inactive,
SUM(case when employee_status='I'
then
(select count(employee_id)
from employee
where date_of_termination between '1/1/2016' and '2/1/2016')
else 0 end) AS Inactive_last_month
from employee

Related

Keep the number of data records but the sum of two other Variables should be calculated

I have a table with Course-Participants, Course_Id and Status.
I want the number of records from Course-Participants to stay the same. But from the combination of Course_Id and Status it should show a total.
It should look like this:
And this is my attempt:
SELECT
[Course_Id]
,Sum(case when Course_ID is not null and Status = 0 THEN 1 else 0 end) as Sum_Status_A
,Sum(case when Course_ID is not null and Status = 1 THEN 1 else 0 end) as Sum_Status_B
,Sum(case when Course_ID is not null and Status = 2 THEN 1 else 0 end) as Sum_Status_C
FROM CourseParticipant
group by course_id
because of the group by statement, I cannot include the course participant in the query. As a result, I cannot output the desired number of data records.
Also select participant_id and add it the the group by:
SELECT
Course_Id,
Participant_id,
Sum(case when Course_ID is not null and Status = 0 THEN 1 else 0 end) as Sum_Status_A,
Sum(case when Course_ID is not null and Status = 1 THEN 1 else 0 end) as Sum_Status_B,
Sum(case when Course_ID is not null and Status = 2 THEN 1 else 0 end) as Sum_Status_C
FROM CourseParticipant
group by course_id, participant_id

Is there a way to rewrite this statement without sub queries?

I am trying to combine 4 queries for a monthly report so that I don't have to run them seperately. Our internal accounting software appears doesn't support sub queries so this statement doesn't work.
select left(salesgroupcode,4) as "Sales Group",
count(Number_of_products),
count(Number_of_discontinued),
count(Number_not_uploaded),
count(Number_sitting)
from (select
case when quantityavailable > 1 then 1 end Number_of_products,
case when quantityavailable > 1 and discontinued = true then 1 end Number_of_discontinued,
case when quantityavailable > 1 and z_datefirstuploaded is null then 1 end Number_not_uploaded,
case when quantityavailable > 1 and z_datefirstuploaded is null and dateoflastsale <= '01/01/2019' then 1 end Number_sitting
from icprod
) icprod
I don't have any other info about the specific rules etc that the software allows so I'm happy to try anything.
Thanks in advance.
Any help is appreciated
Yes, it is possible:
select left(salesgroupcode,4) as "Sales Group",
count(*),
count(case when discontinued = true then 1 end ),
count(case when z_datefirstuploaded is null then 1 end),
count(case when z_datefirstuploaded is null and dateoflastsale <= '01/01/2019')
from icprod
where quantityavailable > 1
group by left(salesgroupcode,4)
Just use conditional aggregation:
select sum(case when quantityavailable > 1 then 1 else 0 end ) as Number_of_products,
sum(case when quantityavailable > 1 and discontinued = true then 1 else 0 end) as Number_of_discontinued,
sum(case when quantityavailable > 1 and z_datefirstuploaded is null then 1 else 0 end) as Number_not_uploaded,
sum(case when quantityavailable > 1 and z_datefirstuploaded is null and dateoflastsale <= '2019-01-01' then 1 else 0 end) as Number_sitting
from icprod;
Notes that I changed the date constant to be ISO 8601 standard format. In some databases, you may need to precede that with date.
This can in turn be simplified to:
select count(*) as Number_of_products,
sum(case when discontinued = true then 1 else 0 end) as Number_of_discontinued,
sum(case when z_datefirstuploaded is null then 1 else 0 end) as Number_not_uploaded,
sum(case when z_datefirstuploaded is null and dateoflastsale <= '2019-01-01' then 1 else 0 end) as Number_sitting
from icprod
where quantityavailable > 1

Counting Values based on certain criteria SQL

I am trying to Write a View for some reporting in our CRM program and I'm having trouble with the counts. We are trying to count the number of referrals based on certain criteria. I feel like the way I wrote the view is incorrect. I am trying to use a CASE statement to make sure it counts the values that I want, but I the numbers I am getting I am not able to validate with reverse engineering.
Did I structure the CASE statement correctly?
(Note: I do realize that client is misspelled, unfortunately whoever wrote the database before I got it had some spelling issues.)
This is what I have written so far:
SELECT Comp_Name, Count(Case WHEN comp_primaryreferralsource IS NOT NULL and Comp_type = 'Client' Then 1
ELSE NULL END) AS Client_Referrals,
Count(Case WHEN lead_companyprimaryreferralsource IS NOT NULL Then 1 Else Null End) AS Target_Referrals,
Count(Case WHEN comp_primaryreferralsource IS NOT NULL and Comp_type = 'Prospect' Then 1 Else Null End) As Prospective_Client_Referral,
Count(Case WHEN comp_primaryreferralsource IS NOT NULL and Comp_type = 'Lost_Clent' Then 1 Else Null End) AS Lost_Client_Referral,
Count(Case WHEN mcgr_companyid IS NOT NULL Then 1 Else NULL END) AS Intro_By_MCG
FROM Company
RIGHT JOIN Lead on Lead_PrimaryCompanyID = Comp_CompanyId
RIGHT JOIN MCGRelationships on mcgr_companyid = Comp_CompanyId
WHERE COMP_Name IS NOT NULL
Group By Comp_Name
Here is a Sample of What i'm getting:
Client1 0 0 0 0 1
Client2 0 0 0 0 2
Client3 0 0 0 0 1
Client4 0 0 0 0 1
Client5 0 0 0 0 2
Client6 0 0 0 0 2
Client7 0 0 4 0 4
Client8 0 0 0 0 2
Client9 0 2 2 0 2
Client10 12 6 0 0 12
Client11 0 0 0 0 2
When I just run a query on the table where Client 10 is the Primary Referral source, I get nothing. So I can't account for those 12 instances.
I think your problem may be in the join to MCGRelationships, if each company record can have more than one relationship record. If I'm following you correctly, you want Intro_By_MCG to be 1 if that record exists in MCGRelationships, regardless of the number of times it appears there. By joining the table, your query would be counting a lead once for each MCGRelationship associated with the company the lead comes from. Try this and let us know if the result is different:
SELECT Comp_Name, Count(Case WHEN comp_primaryreferralsource IS NOT NULL and Comp_type = 'Client' Then 1
ELSE NULL END) AS Client_Referrals,
Count(Case WHEN lead_companyprimaryreferralsource IS NOT NULL Then 1 Else Null End) AS Target_Referrals,
Count(Case WHEN comp_primaryreferralsource IS NOT NULL and Comp_type = 'Prospect' Then 1 Else Null End) As Prospective_Client_Referral,
Count(Case WHEN comp_primaryreferralsource IS NOT NULL and Comp_type = 'Lost_Clent' Then 1 Else Null End) AS Lost_Client_Referral,
Count(Case WHEN EXISTS (Select Comp_CompanyId FROM MCGRelationships WHERE mcgr_companyid = Comp_CompanyId) Then 1 Else NULL END) AS Intro_By_MCG
FROM Company
RIGHT JOIN Lead on Lead_PrimaryCompanyID = Comp_CompanyId
WHERE COMP_Name IS NOT NULL
Group By Comp_Name

SQL Query to fetch employee Attendence

I need to write query on employee table to fetch the employee with employee ID & how many days he is present absent & half-day for given date range.
Employee
AID EmpID Status Date
1 10 Present 17-03-2015
2 10 Absent 18-03-2015
3 10 HalfDay 19-03-2015
4 10 Present 20-03-2015
5 11 Present 21-03-2015
6 11 Absent 22-03-2015
7 11 HalfDay 23-03-2015
Expected Output will be :
EmpID Present Absent HalfDay
10 2 1 1
11 1 1 1
Can you please help me with the Sql query ?
Here Is the query I tried
SELECT EMP.EMPID,
(CASE WHEN EMP.STATUS = 'Present' THEN COUNT(STATUS) ELSE 0 END) Pres,
(CASE WHEN EMP.STATUS = 'Absent' THEN COUNT(STATUS) ELSE 0 END) ABSENT,
(CASE WHEN emp.status = 'HalfDay' THEN Count(status) ELSE 0 END) HalfDay
FROM EMPLOYEE EMP GROUP BY emp.empid
The COUNT() function tests if the value is NOT NULL. Therefore it will always increment for both sides of a CASE statement like this:
COUNT(CASE Status WHEN 'Present' THEN 1 ELSE 0) AS Present
So we need to use SUM() ...
select empid,
sum(case when status='Present' then 1 else 0 end) present_tot,
sum(case when status='Absent' then 1 else 0 end) absent_tot,
sum(case when status='HalfDay' then 1 else 0 end) halfday_tot
from employee
group by empid
order by empid
/
... or use COUNT() with a NULL else clause. Both produce the same output, perhaps this one is clearer:
SQL> select empid,
2 count(case when status='Present' then 1 end) present_tot,
3 count(case when status='Absent' then 1 end) absent_tot,
4 count(case when status='HalfDay' then 1 end) halfday_tot
5 from employee
6 group by empid
7 order by empid
8 /
EMPID PRESENT_TOT ABSENT_TOT HALFDAY_TOT
---------- ----------- ---------- -----------
10 2 1 1
11 1 1 1
SQL>
Note that we need to use ORDER BY to guarantee the order of the result set. Oracle introduced a hashing optimization for aggregations in 10g which meant GROUP BY rarely returns a predictable sort order.
Replace 0 with null because it would be also come in count and added the where clause for date range, check the example below:
select empID,
count(case when status='Present' then 1 else null end) Present_Days,
count(case when status='Absent' then 1 else null end) Absent_Days,
count(case when status='HalfDay' then 1 else null end) HalfDays
from Employee
where date >= to_date('17mar2015') and date <= to_date('23mar2015')
group by empID

sql subquery that collects from 3 rows

I have a huge database with over 4 million rows that look like that:
Customer ID Shop
1 Asda
1 Sainsbury
1 Tesco
2 TEsco
2 Tesco
I need to count customers that within last 4 weeks had shopped in all 3 shops Tesco Sainsbury and Asda. Can you please advice if its possible to do it with subqueries?
This is an example of a "set-within-sets" subquery. You can solve it with aggregation:
select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) > 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0;
This structure is quite flexible. So if you wanted Asda and Tesco but not Sainsbury, then you would do:
select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) = 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0;
EDIT:
If you want a count, then use this as a subquery and count the results:
select count(*)
from (select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) > 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0
) t