SQL Display record of non equal to - sql

We have a single table with 2 columns, name & check_in_date
Every employee will check-in daily for every working day.
But if I want to find out on a specific day, who did not check in, how do I go about it?
select name from table
where check_in_date <> '2021-06-17'
The above will not work for me as it will display records outside of 2021-06-17.
I wanted to see only the names that did not check in on that date.
Many thanks in advance.

You need a table of employees. Then you would use not exists:
select e.*
from employees e
where not exists (select 1
from checkins ci
where ci.name = e.name and ci.date = ?
);
The ? is a placeholder for your date.
If you don't have a separate table, you can use aggregation instead:
select name
from checkins
group by name
having sum(case when ci.date = ? then 1 else 0 end) = 0;

Related

SQL - Count new entries based on last date

I have a table with the follow structure
ID ReportDate Object_id
What I need to know, is the count of new and count of old (Object id's)
For example: If I have the data below:
I want the following output grouped by ReportDate:
I thought a way doing it using a Where clause based on date, however i need the data for all the dates I have in the table. To see the count of what already existed in the previous report and what is new at that report. Any Ideas?
Edit: New/Old definition- New would be the records that never appeared before that report run date and appeared on this one, whereas old is the number of records that had at least one match in previous dates. I'll edit the post to include this info.
managed to do it using a left join. Below is my solution in case it helps anyone in the future :)
SELECT table.ReportRunDate,
-1*sum(table.ReportRunDate = new_table.init_date) as count_new,
-1*sum(table.ReportRunDate <> new_table.init_date) as count_old,
count(*) as count_total
FROM table LEFT JOIN
((SELECT Object_ID, min(ReportRunDate) as init_date
FROM table
GROUP By OBJECT_ID) as new_table)
ON table.Object_ID = new_table.Object_ID
GROUP BY ReportRunDate
This would work in Oracle, not sure about ms-access:
SELECT ReportDate
,COUNT(CASE WHEN rnk = 1 THEN 1 ELSE NULL END) count_of_new
,COUNT(CASE WHEN rnk <> 1 THEN 1 ELSE NULL END)count_of_old
FROM (SELECT ID
,ReportDate
,Object_id
,RANK() OVER (PARTITION BY Object_id ORDER BY ReportDate) rnk
FROM table_name)
GROUP BY ReportDate
Inner query should rank each occurence of object_id based on the ReportDate so the 1st occurrence of certain object_id will have rank = 1, the next one rank = 2 etc.
Then the outer query counts how many records with rank equal/not equal 1 are the within each group.
I assumed that 1 object_id can appear only once within each reportDate.

Redshift - Finding number of times a flag appears for a particular ID

I have some sales data that shows if a bill has been generated for a customer. The column labelled bill_generated returns 'Y' if a bill has been generated else its blank. I am trying to find the list of customers for whom atleast one bill has been generated. There could be multiple rows for each cust_id as shown below:
cust_id, bill_generated
001,NULL
001,Y
002,NULL
002,NULL
003,Y
Could anyone advice on this. I am using Redshift DB. Thanks..
Try below using group by and having cluse
select cust_id from tablename
group by cust_id
having sum(case when bill_generated is null then 0 else 1 end)=1
you can use co-related sub-query
select * from t
where exists (select 1 from t t1
where t1.bill_generated='Y' and t1.cust_id=t.cust_id
)

How to add the occurrences of a value in a SQL table specific to another value in the table

I have searched and think I have found part of my answer, but I still can't quite figure it out. I have a database with 4 tables and I'm trying to return for each employee their name, the number of total vacation days they have which is based on their job title and the number of vacation days they have taken wich is found by adding up all of instances where the ReasonID column of the Leave table equals 2 for that employee.
This is what I have, and if I take out the line where I'm trying to get VacationDaysTaken, I can return the correct EmployeeName and TotalVactionDays. If I just try to return VacationDaysTaken, then I get the number of vacation days used by all employees. If I try to run it as I have it listed below, I get "Column 'Employee.Last' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause."
SELECT
Employee.Last + ', ' + Employee.First AS EmployeeName,
Title.Vacation AS TotalVacationDays,
SUM(CASE WHEN Leave.ReasonID=2 THEN 1 ELSE 0 END) AS VacationDaysTaken
FROM Employee, Title, Leave, LeaveType
WHERE Employee.EmpID = Leave.EmpID
AND Leave.ReasonID = LeaveType.ReasonID
AND Employee.TitleID = Title.TitleID
ORDER BY EmployeeName
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
You need a GROUP BY:
SELECT e.Last + ', ' + e.First AS EmployeeName,
t.Vacation AS TotalVacationDays,
SUM(CASE WHEN l.ReasonID = 2 THEN 1 ELSE 0 END) AS VacationDaysTaken
FROM Employee e JOIN
Title t
ON e.TitleID = t.TitleID JOIN
Leave l
ON e.EmpID = l.EmpID
GROUP BY e.Last, e.First, t.Vacation
ORDER BY EmployeeName;
Note: Because you are using the ReasonId for the comparison, there is no need to join to the leave types table.

Select all unique names based on most recent value in different field

I have an access database with a table called SicknessLog. The fields are ID, StaffName, [Start/Return], DateStamp.
When a member of staff is off work for sickness then a record is added to the table and the value in the [Start/Return] field is 1. When they return to work a new record is added with the same details except the [Start/Return] field is 0.
I am trying to write a query that will return all distinct staff names where the most recent record for that person has a value of 1 (ie, all staff who are still off sick)
Does anyone know if this is possible? Thanks in advance
Here's one way, all staff that has been sick where it does not exist an event after that where that staff is "nonsick":
select distinct x.staffname
from sicknesslog x
where Start/Return = 1
and not exists (
select 1
from sicknesslog y
where x.StaffName = y.StaffName
and y.DateStamp > x.DateStamp
and y.Start/Return = 0
)
You can use group by to achieve this.
select staffname ,max(datestamp) from sicknesslog where start/return = 1 group by staffname
it will return all latest recored for all staff. If ID column is autogenerated PK then you can use it in max function.
select staffname,MAX(datestamp)
from sicknesslog
where [start/return]=1
group by staffname
order by max(datestamp) desc,staffname
This will retrieve latest records who is sick and off to work
This should be close:
select s.StaffName, s.DateStamp, s.[Start/Return]
from SicknessLog s
left join (
select StaffName, max(DateStamp) as MaxDate
from SicknessLog
group by StaffName
) sm on s.StaffName = sm.StaffName and s.DateStamp = sm.MaxDate and s.[Start/Return] = 1

How can I find records where a field appears once in a column or multiple times in the column but only once between a set of dates?

I am trying to write a query that brings up the details (invoiceNumber, name, phone & email) from a table but only where the entries match these specific requirements:
Return the rows where the email address appears only once in the whole table from any date
AND
Return the rows where the email address multiple times WHERE the email has only been entered ONCE within the last 3 months.
I am fairly sure that this requires nested statements but I have no idea how to go about setting it up.
Any help would be greatly appreciated!
Approach this by thinking about the email addresses. You can determine the frequency of appearance by doing a group by:
select emailaddress, count(*) as TotalCnt,
sum(case when invoicedate >= sysdate - 90 then 1 else 0 end) as LastThreeMonths
from t
group by emailaddress;
This gives you the information you need. The following query joins this back to the original table to get the rows you are looking for:
select t.*
from t join
(select emailaddress, count(*) as TotalCnt,
sum(case when invoicedate >= sysdate - 90 then 1 else 0 end) as LastThreeMonths
from t
group by emailaddress
) e
on t.emailaddress = e.emailaddress
where e.TotalCnt = 1 or e.LastThreeMonths = 1