SQL Query to fetch employee Attendence - sql

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

Related

Get users that have at least one product code and also more than 10 of the other product code

The table that needs to be queried looks like this:
ID
UserID
ProductCodes
1
33
9999
2
456
3051
3
456
9999
4
456
3051
4
33
9999
How would I write a SQL query to find out which users have at least one productCodes = '9999' and also have more than 10 productCodes <> '9999'?
You can use GROUP BY and HAVING:
SELECT
UserID
FROM dbo.YourTable
GROUP BY
UserId
HAVING SUM(CASE WHEN ProductCodes = '9999' THEN 1 ELSE 0 END) >= 1
AND COUNT(DISTINCT ProductCodes) >= 11
;
Use Case or Intersect (case is more performant)
SELECT UserID, SUM (case when ProductCodes='9999' then 1 else 0 end) PC9999
, SUM (case when ProductCodes<>'9999' then 1 else 0 end) PCNot9999
FROM dbo.Users
WHERE ProductCodes='9999'
GROUP BY UserID
HAVING SUM (case when ProductCodes='9999' then 1 else 0 end)>0
AND SUM (case when ProductCodes<>'9999' then 1 else 0 end) >10
I ended up going with this. It allows us to get specific with how many times a '9999' product code has been used in comparison with other codes.
SELECT
UserID
FROM Session_Hst
GROUP BY
UserID
HAVING SUM(CASE WHEN ProductCodes = '9999' THEN 1 ELSE 0 END) >= 1
AND COUNT(CASE WHEN ProductCodes <> '9999' THEN 1 ELSE null END ) >= 10
;

How to find number of nulls in a table SQL

Let's say that I have an employee table. And it has columns like name, salary, and age. If I want to check if there any nulls in the name. I gotta write
SELECT name FROM EMPLOYEE
WHERE name IS NULL;
But what should I do to see the number of nulls each column has?
Probably the simplest method is:
select count(*) - count(name) as num_name_nulls,
count(*) - count(col1) as num_col1_nulls,
. . .
from employee;
However, what I do in this situation is just select the counts:
select count(*), count(name), count(col1), . . .
from employee;
Then I eyeball the result to see if the counts are not equal.
I assume you want to see nulls for a column, you can apply conditional aggregation.
SELECT COUNT(CASE WHEN name is null then 1 end) AS Name_NullCount,
COUNT(CASE WHEN salary is null then 1 end) as salary_nullCount,
COUNT(CASE WHEN age is null then 1 end) as age_nullcount
FROM EMPLOYEE;
You can use below query but it depends on number of columns. It will give number of nulls each row has.
select
((case when column1 is null then 1 else 0 end)
+ (case when column2 is null then 1 else 0 end)
----------------------------------------
----------------------------------------
+(case when columnN is null then 1 else 0 end))
from TableName
For your case
select
((case when name is null then 1 else 0 end)
+(case when salary is null then 1 else 0 end)
+(case when age is null then 1 else 0 end))
from employee
you can find Null values per row from following query
SELECT
(
(CASE WHEN name IS NULL THEN 1 ELSE 0 END)+
...
...
+(CASE WHEN colName IS NULL THEN 1 ELSE 0 END)
) AS sum_of_nulls
FROM EMPLOYEE
WHERE EmpId = 49
where colName is your Db Column Name
select
sum(case
when name is null then 1
when name is not null tehn 0
end) cname,
sum(case
when salary is null then 1
when salary is not null then 0
end) csalary,
...
from employee
limit 1;

case expression with count and condition of count is greater then

I have the below table
Table A
PK status_cd id grp grp_rnk_asc grp_rnk_desc action_dt
154 new 10 1 1 4 11/6/2019
154 pending 10 1 2 3 11/7/2019
154 pending 10 1 3 2 11/8/2019
154 approved 10 1 4 1 11/9/2019
I want to...
Count partition with condition and when that count is > then 1 then 'pass'
Then be able to add additional when to the case expression
For example:
Sample of criteria
select
Count when status_cd not in ('new','approved')
over (partition by id,grp order by action_dt) if that count > 1 then 'pass'
--also be able to add new conditions here...
from A
--no where clause
I think you want:
select (case when sum(case when tatus_cd not in ('new',' approved') then 1 else 0 end) over (partition by id, grp) > 1
then 'pass'
end)
from A

Multiple conditions in 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

Use of AVG function to determine percentages in a SQL query

I want to know what percentage of records have a given value, where percentage is defined as the number of records that match the value divided by the total number of records. i.e. if there are 100 records, of which 10 have a null value for student_id and 20 have a value of 999999, then the percentage_999999 should be 20%. Can I use the AVG function to determine this?
Option 1:
SELECT year, college_name,
sum(case when student_id IN ('999999999') then 1 else 0 end) as count_id_999999999,
count_id_999999999/total_id as percent_id_999999999,
sum(case when student_id IS NULL then 1 else 0 end) as count_id_NULL,
count_id_NULL/total_id as percent_id_NULL
count(*) as total_id
FROM enrolment_data ed
GROUP BY year, college_name
ORDER BY year, college_name;
Option 2:
SELECT year, college_name,
sum(case when student_id IN ('999999999') then 1 else 0 end) as count_id_999999999,
avg(case when student_id IN ('999999999') then 1.0 else 0 end) as percent_id_999999999,
sum(case when student_id IS NULL then 1 else 0 end) as count_id_NULL,
avg(case when student_id IS NULL then 1.0 else 0 end) as percent_id_NULL
count(*) as total_id
FROM enrolment_data ed
GROUP BY year, college_name
ORDER BY year, college_name;
I created a similar table with 100 records, 20 999999999s, 10 nulls, and 70 1s. This worked for me on SQL Server:
select count(*), StudentID
from ScratchTbl
group by StudentID;
(No column name) StudentID
10 NULL
70 1
20 999999999
select avg(case when StudentID = '999999999' then 1.0 else 0.0 end) as 'pct_9s',
sum(case when StudentID = '999999999' then 1 else 0 end) as 'count_9s',
avg(case when StudentID is null then 1.0 else 0.0 end) as 'pct_null',
sum(case when StudentID is null then 1 else 0 end) as 'count_null'
from ScratchTbl
pct_9s count_9s pct_null count_null
0.200000 20 0.100000 10
I have a feeling that your use of the group by clause could be creating problems for you, perhaps select a specific year/college using the where clause (and get rid of the group by line) and see if you get the results you expect.