Query that filters out results if they exist in a second table - sql

I have two tables. First is a table Employees the second is TimeCard. I am trying to determine when employees are not here. Sample Tables:
So an employee name is returned if it meets the following criteria: Status = 1 and Date != '8/27/13'. However I only want an Employee returned once even if they have multiple entires in the TimeCard table as long as they are not on a specified date.

Try the following:
SELECT e.employee FROM employees e
WHERE status=1
AND NOT EXISTS ( SELECT 1 FROM timecard t
WHERE t.employee=e.employee
AND t.Date = '8/27/13')
where '8/27/13' will work only, if date is a varchar column. Otherwise you should use a more standard date format like '2013-8-27'.
Edit:
In MSSQL '8/27/13' will actually work, but it is still not a good idea to use this notation as it is not unambiguous when smaller numbers are used, like '5/6/7'. Depending on who entered it (and from which country they come), this could mean either May 6 2007, or 2005 May the 7th or 5 June 2007 ...
2. Edit:
Evidently not a good idea to prepare supper while you are putting together a SQLfiddle! The whole thing was buggy. I just fixed it and, of course corrected the typo with t.Date != '8/27/13' sorry for the confusion! See the corrected fiddle here: http://sqlfiddle.com/#!3/26454/1

Try this:
SELECT DISTINCT e.employee
FROM employees e
LEFT JOIN timecard t ON t.employee = e.employee
WHERE e.status = 1 AND (t.date != '8/27/13' OR t.date IS NULL)

Related

How to show all employees absent dates only in MS Access 2010 query?

I want to have a query which shows me records of only those employees that were absent on various dates.
I have two queries in MS Access 2010. One is qAllDatesAllEmp which has all monthly dates for all employees. Second is qDailyWorkEmp which shows date-wise the working of employees. Now, say Emp1 had only one missing date of 5-Jan-2019; emp2 had 15-Jan-2019 missing and so on, the result should show me only these missing dates with employee names. What i have tried so far is that I have joined the date field from qAllDatesAllEmp to the date field in qDailyWorkEmp with join arrow pointing from qAllDatesAllEmp to qDailyWorkEmp. I also added the date field from qDailyWorkEmp to the query grid below but removed the check mark. When I run this query, it gives blank result. I would really welcome the experts' help on how to get the desired output below.
My Sample Data:
Query1: qAllDatesAllEmp contains {WorkDate; empID; empName; CityBased}
Query2: qDailyWorkEmp contains {DailyDate; empID; empName; CityBased}
The SQL for this is as follows:
SELECT qDailyWorkEmp.empID, qDailyWorkEmp.empName, qDailyWorkEmp.CityBased
FROM qAllDatesAllEmp LEFT JOIN
qDailyWorkEmp
ON qAllDatesAllEmp.WorkDate = qDailyWorkEmp.DailyDate
WHERE (((qDailyWorkEmp.DailyDate) Is Null));
My desired output:
empID; EmpName; MissingDate
001; ABC; 5-Jan-2019
007; LMN; 15-Jan-2019
...and so on
From what I can gather from your question, it seems like you are on the right track with your left join query, however, since your qAllDatesAllEmp query contains the master data, you should output the data from this query for records for which the corresponding values are null in your qDailyWorkEmp query.
You also appear to have a typo in your query on this line:
qAllDatesAllEmp.WhatDate = qDailyWorkEmp.DailyDate
As you have stated in your question that the query qAllDatesAllEmp contains the fields:
Query1: qAllDatesAllEmp contains {WorkDate; empID; empName; CityBased}
WhatDate is not one of these fields.
You will also need to join the empID field in both queries, so that you are comparing the date field on a per-employee basis, as opposed to comparing each date with the dates for all employees - hence your join criteria should be:
qAllDatesAllEmp LEFT JOIN qDailyWorkEmp ON
qAllDatesAllEmp.WorkDate = qDailyWorkEmp.DailyDate AND
qAllDatesAllEmp.empID = qDailyWorkEmp.empID
With the information provided, I might suggest the following:
SELECT
qAllDatesAllEmp.empID,
qAllDatesAllEmp.empName,
qAllDatesAllEmp.CityBased
qAllDatesAllEmp.WorkDate as MissingDate
FROM
qAllDatesAllEmp LEFT JOIN qDailyWorkEmp ON
qAllDatesAllEmp.WorkDate = qDailyWorkEmp.DailyDate AND
qAllDatesAllEmp.empID = qDailyWorkEmp.empID
WHERE
qDailyWorkEmp.DailyDate IS NULL

SQL query , group by only one column

i want to group this query by project only because there are two records of same project but i only want one.
But when i add group by clause it asks me to add other columns as well by which grouping does not work.
*
DECLARE #Year varchar(75) = '2018'
DECLARE #von DateTime = '1.09.2018'
DECLARE #bis DateTime = '30.09.2018'
select new_projekt ,new_geschftsartname, new_mitarbeitername, new_stundensatz
from Filterednew_projektkondition ps
left join Filterednew_fakturierungsplan fp on ps.new_projekt = fp.new_hauptprojekt1
where ps.statecodename = 'Aktiv'
and fp.new_startdatum >= #von +'00:00:00'
and fp.new_enddatum <= #bis +'23:59:59'
--and new_projekt= Filterednew_projekt.new_
--group by new_projekt
*
look at the column new_projekt . row 2 and 3 has same project, but i want it to appear only once. Due to different other columns this is not possible.
if its of interested , there is another coluim projectcondition id which is unique for both
You can't ask a database to decide arbitrarily for you, which records should be thrown away when doing a group. You have to be precise and specific
Example, here is some data about a person:
Name, AddressZipCode
John Doe, 90210
John Doe, 12345
SELECT name, addresszipcode FROM person INNER JOIN address on address.personid = person.id
There are two addresses stored for this one guy, the person data is repeated in the output!
"I don't want that. I only want to see one line for this guy, together with his address"
Which address?
That's what you have to tell the database
"Well, obviously his current address"
And how do you denote that an address is current?
"It's the one with the null enddate"
SELECT name, addresszipcode FROM person INNER JOIN address on address.personid = person.id WHERE address.enddate = null
If you still get two addresses out, there are two address records that are null - you have data that is in violation of your business data modelling principles ("a person's address history shall have at most one adddress that is current, denoted by a null end date") - fix the data
"Why can't i just group by name?"
You can, but if you do, you still have to tell the database how to accumulate the non-name data that it shows you. You want an address data out of it, it has 2 it wants to show you, you have to tell it which to discard. You could do this:
SELECT name, MAX(addresszipcode) FROM person INNER JOIN address on address.personid = person.id GROUP BY name
"But I don't want the max zipcode? That doesn't make sense"
OK, use the MIN, the SUM, the AVG, anything that makes sense. If none of these make sense, then use something that does, like the address line that has the highest end date, or the lowest end date that is a future end date. If you only want one address on show you must decide how to boil that data down to just one record - you have to write the rule for the database to follow and no question about it you have to create a rule so make it a rule that describes what you actually want
Ok, so you created a rule - you want only the rows with the minimum new_stundenstatz
DECLARE #Year varchar(75) = '2018'
DECLARE #von DateTime = '1.09.2018'
DECLARE #bis DateTime = '30.09.2018'
select new_projekt ,new_geschftsartname, new_mitarbeitername, new_stundensatz
from
(SELECT *, ROW_NUMBER() OVER(PARTITON BY new_projekt ORDER BY new_stundensatz) rown FROM Filterednew_projektkondition) ps
left join
Filterednew_fakturierungsplan fp on ps.new_projekt = fp.new_hauptprojekt1
where ps.statecodename = 'Aktiv'
and fp.new_startdatum >= #von +'00:00:00'
and fp.new_enddatum <= #bis +'23:59:59'
and ps.rown = 1
Here I've used an analytic operation to number the rows in your PS table. They're numbered in order of ascending new_stundensatz, starting with 1. The numbering restarts when the new_projekt changes, so each new_projekt will have a number 1 row.. and then we make that a condition of the where
(Helpful side note for applying this technique in future.. Ff it were the FP table we were adding a row number to, we would need to put AND fp.rown= 1 in the ON clause, not the WHERE clause, because putting it in the where would make the LEFT join behave like an INNER, hiding rows that don't have any FP matching record)

SQL - Duplicate rows with left join

I am trying to pull through the number of days taken sick leave and employee info.
I have two tables
One is a table where sick leave is recorded (LVE) and the other is a employee table which is a view containing staff data (Staff) eg the employment status column(pos_statusa)
With my query below, I am getting duplicate results - The same employeenumber, leave type, leave start, leave end, and position status.
What am I doing wrong here?
SELECT RTRIM(DET_NUMBER) AS DET_NUMBERA,
RTRIM(LVE_TYPE_CD) AS LVE_TYPE_CD,
l.LVE_START,
l.LVE_END,
l.LVE_HOUR_TKN,
l.LVE_DAY_TAKE,
e.pos_statusa
FROM dbo.LVE as l
LEFT JOIN Staff as e
ON l.DET_NUMBER = e.DET_NUMBERA COLLATE SQL_Latin1_General_CP1_CI_AS
WHERE (LVE_START > = '2017-02-01'
AND LVE_END < '2018-02-01')
AND LVE_TYPE_CD IN ('SIC','USIC')
Cheers
Did you try adding 'Distinct' after SELECT?
If you need only the records having data in LVE table and staff table both, after fulfilling your conditions then use JOIN instead of left JOIN.
SELECT RTRIM(DET_NUMBER) AS DET_NUMBERA,
RTRIM(LVE_TYPE_CD) AS LVE_TYPE_CD,
l.LVE_START,
l.LVE_END,
l.LVE_HOUR_TKN,
l.LVE_DAY_TAKE,
e.pos_statusa
FROM dbo.LVE as l
JOIN Staff as e
ON l.DET_NUMBER = e.DET_NUMBERA COLLATE SQL_Latin1_General_CP1_CI_AS
WHERE (LVE_START > = '2017-02-01'
AND LVE_END < '2018-02-01')
AND LVE_TYPE_CD IN ('SIC','USIC')
Thanks for all your help.
It looks like a simple 'DISTINCT' has done the trick!

Only a single result allowed for a SELECT that is part of an expression

I have the following SQL statement. It's throws the following error: "Only a single result allowed for a SELECT that is part of an expression". The goal of my sql statement is to get the name of the employee who made the 'cheapest' bribe.
The part between the brackets return the employee_id and the money it costs a day (of the relative cheapest bribe). These are two results while I only want the employee_id. So I just want to use the MIN part to get the right employee_id. How can I do this?
SELECT Voornaam, Achternaam
FROM Medewerker m JOIN
(
SELECT Medewerker_id
FROM Steekpenning
ORDER BY -1*Bedrag/(julianday(Begindatum) - julianday(Einddatum))
limit 1
) s
on m.Medewerker_id = s.Medewerker_id;
EDITED the answer. How can I expand this query to only show the bribes started this month? I think I need to use something like this? (julianday(Begindatum) - julianday('now')) > 31 but where?
Regards.
Cas
I think the following will work in SQLite:
select Firstname, Surname
from Employee e join
(select employee_id
from bribe
order by -1*Amount/(julianday(Startdate) - julianday(Enddate))
limit 1
) b
on e.employee_id = b.employee_id;

Oracle SQL, Select and compare dates against null values

I need to select and compare the last advertised date in advert, to any null values in lease to get when an un-leased property and when it was last advertised. This is the code I have so far;
SELECT YR_LEASE.PROPERTYNUM,
MAX(YR_ADVERT.DATETO),
count(YR_LEASE.RENTERNUM)
FROM YR_LEASE
JOIN YR_ADVERT
ON YR_LEASE.PROPERTYNUM=YR_ADVERT.PROPERTYNUM
GROUP BY YR_LEASE.PROPERTYNUM
This returns a count this is far too high and I'm not sure what i'm doing wrong, here's my ERD to try and give this question some context;
http://www.gliffy.com/pubdoc/4239520/L.png
I think you need to first identify unleased properties. From there you can find the latest advert date. Assuming some properties have never been advertised you'll need to go via YR_PROPERTY and do a left join to include unadvertised properties.
SELECT NVL(TO_CHAR(MAX(YR_ADVERT.DATETO),'DD/MM/YYYY'),'NO LAST ADVERT DATE') LAST_ADVERT_DATE
,YR_PROPERTY.PROPERTYNUM
FROM YR_PROPERTY LEFT JOIN YR_ADVERT ON YR_PROPERTY.PROPERTYNUM = YR_ADVERT.PROPERTYNUM
WHERE NOT EXISTS (SELECT 1
FROM YR_LEASE
WHERE YR_LEASE.PROPERTYNUM = YR_PROPERTY.PROPERTYNUM
AND YR_LEASE.RENT_FINISH > SYSDATE)
GROUP BY YR_LEASE.PROPERTYNUM;