SQL - Duplicate rows with left join - sql

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!

Related

sql join and minus

I seem to be having problem getting a certain query to work. I know I'm so close. Here's a copy of my er diagram
I think I am so close to achieving what I want to do with this code, only I get invalid identifier when trying to run it. I think its because the practice is being changed somehow after joining, as I am only getting invalid identifier on row 5?
SELECT staffid, staff_firstname, staff_surname, practice.practice_name, practice.practice_city
from staff
join practice on staff.practiceid = practice.practiceid
MINUS
SELECT staffid, staff_firstname, staff_surname, practice.practice_name, practice.practice_city
from staff
where role = 'GP';
Basically I'm trying to use the minus construct to find practices which do not employ a GP and include some information such as the CITY and practice_address.
I can use the minus construct to find out how many staff do not have the role of GP like so:
SELECT staffid, staff_firstname, staff_surname
from staff
MINUS
SELECT staffid, staff_firstname, staff_surname
from staff
where role = 'GP';
where I get the results:
STAFFID STAFF_FIRS STAFF_SURN
__________ __________ __________
8 NYSSA THORNTON
9 MONA BRADSHAW
10 GLORIA PENA
I'm struggling to use the join with the minus construct to get information about the GP's practice address and city etc.
Any help would be greatly appreciated!
The second select, after the minus, is referring to columns from the practice table - but it doesn't join to it:
SELECT staffid, staff_firstname, staff_surname,
practice.practice_name, practice.practice_city
from staff
join practice on staff.practiceid = practice.practiceid
MINUS
SELECT staffid, staff_firstname, staff_surname,
practice.practice_name, practice.practice_city
from staff
join practice on staff.practiceid = practice.practiceid
where role = 'GP';
That isn't going to give you what you want though, it will just remove the rows for staff that are GPs, not all trace of practices that have any GPs - non-GP staff at all practices will still be shown.
if you don't want the remaining staff details you only need to include the columns from the practice table in the select lists, and the minus would then give you what you want (and Gordon Linoff has shown two alternatives to minus in that case). If you do want the remaining staff details then you can use a not-exists clause rather than a minus - something like:
select s.staffid, s.staff_firstname, s.staff_surname,
p.practice_name, p.practice_city
from staff s
join practice p on s.practiceid = p.practiceid
where not exists (
select 1
from staff s2
where s2.practice_id = p.practice_id
and s2.role = 'GP
);
This is similar to Gordon's second query but has an extra join to staff for the details. Again, if you don't want those, use Gordon's simpler query.
You could also use an aggregate check, or could probably do something with an analytic function if you've learned abput those, to save having to hit the tables twice.
Your original query only operates on the level of "staff", not "practice". I would be inclined to solve this using aggregation:
select p.practice_name, p.practice_city
from staff s join
practice p
on s.practiceid = p.practiceid
group by p.practice_name, p.practice_city
having sum(case when s.role = 'GP' then 1 else 0 end) = 0;
Or, even better:
select p.*
from practice p
where not exists (select 1
from staff s
where s.practiceid = p.practiceid and s.role = 'GP'
);
I think this is the simplest and most direct interpretation of your question.

SQL using inner join

So this is the situation I have. I have 3 tables (tblEmployeesinfo , sqlSumrepMTC, sqlSumrepMTC15th) I display this info using inner join:
SELECT
SQLSummRepMTC."RepCompany", SQLSummRepMTC."WHTax",
SQLSummRepMTC."Company", SQLSummRepMTC."MonthName",
SQLSummRepMTC."YearVal", SQLSummRepMTC."Basis",
tblEmployeesInfo."LastName", tblEmployeesInfo."FirstName",
tblEmployeesInfo."Company", tblEmployeesInfo."MInitial",
tblEmployeesInfo."Division", sqlSumrepMTC15th."WHTax",
sqlSumrepMTC15th."Basis"
FROM
{
oj ("BIOMETRICS"."dbo"."SQLSummRepMTC" SQLSummRepMTC INNER JOIN
"BIOMETRICS"."dbo"."tblEmployeesInfo" tblEmployeesInfo
ON SQLSummRepMTC."EmployeeNo" = tblEmployeesInfo."EmployeeNo")
INNER JOIN "BIOMETRICS"."dbo"."sqlSumrepMTC15th" sqlSumrepMTC15th
ON tblEmployeesInfo."EmployeeNo" = sqlSumrepMTC15th."EmployeeNo"
}
ORDER BY
SQLSummRepMTC."Basis" ASC,
tblEmployeesInfo."Company" ASC,
tblEmployeesInfo."LastName" ASC
Let's say one employee has his record on sqlSumrepMTC with its field Taxvalue of 50 but he does not exist on sqlSumrepMTC15th my problem is that this record will not be displayed in the inner join since it does not have value on both tables. What i want to achieve is just display a 0 value when it does not exist in the other table. This is my report looks like.
Employeeno employeename 15th 30th
01 james 10 20
02 Chris NULL 50
first record will appear in the report since it has both record existing in the two tables, the second will not since its null in the first table. I just need it to appear in the report if one value is null or is missing from the other. Thanks in advance
You have two joins! Thus, if there is no record in sqlSumrepMTC15th you need to replace the second join with LEFT JOIN. If it is possible, that there is no join record in sqlSumrepMTC15th AND tblEmployeesInfo, you need to replace both joins with LEFT JOIN.
Furthermore, you can replace NULL by
SELECT CASE
WHEN attribute IS NULL
THEN 0
ELSE attribute
END AS resultColumName,
nextAttribute
FROM ...

Query From Multiple tables with sum and case function

I have two tables: TaskUser and PaperMaterial
TaskUser - Contains all users One column titled: User1) that could be a user in the PaperMaterial Table
PaperMaterial - Multi-column table where data could be written multiple times for the same user on multiple dates.
What I am trying to accomplish is a query that will show all users for a given date range and their total page count regardless if they have data in the papermaterial table.
IE:
Select Assigned_To,
Case
When PaperMaterial.Assigned_To = TaskUser.User1 then sum(Page_Count)
When PaperMaterial.Assigned_To <> TaskUser.User1 then '0'
End as Count1
From PaperMaterial
Inner Join TaskUser
on TaskUser.User1 = PaperMaterial.Assigned_To
Where Date_Assigned between ('06/09/2014') and ('06/13/2014')
Order By Assigned_To
Now, obviously this code does not work, because I am new to SQL and I am not very good yet. However, you should be able to see the goal here. which is:
Mike 0
Bob 200
Jen 0
Betty 125
so on, so forth
Thank you
I think this will do the trick
SELECT a.User1, ifnull(sum(Page_Count),0) AS Count1
From TaskUser AS a
LEFT JOIN PaperMaterial AS b
ON b.Assigned_To = a.User1
Where Date_Assigned between DATE('2014-06-09') AND DATE('2014-06-13')
GROUP BY a.User1
Order By a.User1
You might need to tweak the Date_Assigned logic, depending on your date formats... but the current clause you're using doesn't really make a lot of sense. I think the one above should do the job, assuming your Date_Assigned variable is formatted as a date or datetime

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

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)

SQL: return 0 count in case no record is found

A very simple issue as it appears but somehow not working for me on Oracle 10gXE.
Based on my SQLFiddle, I have to show all staff names and count if present or 0 if no record found having status = 2
How can I achieve it in a single query without calling Loop in my application side.
SELECT S.NAME,ISTATUS.STATUS,COUNT(ISTATUS.Q_ID) as TOTAL
FROM STAFF S
LEFT OUTER JOIN QUESTION_STATUS ISTATUS
ON S.ID = ISTATUS.DONE_BY
AND ISTATUS.STATUS = 2 <--- instead of WHERE
GROUP BY S.NAME,ISTATUS.STATUS
By filtering in the WHERE clause, you filter too late, and you remove STAFF rows that you do want to see. Moving the filter into the join condition means only QUESTION_STATUS rows get filtered out.
Note that STATUS is not really a useful column here, since you won't ever get any result other than 2 or NULL, so you could omit it:
SELECT S.NAME,COUNT(ISTATUS.Q_ID) as TOTAL
FROM STAFF S
LEFT OUTER JOIN QUESTION_STATUS ISTATUS
ON S.ID = ISTATUS.DONE_BY
AND ISTATUS.STATUS = 2
GROUP BY S.NAME
I corrected your sqlfiddle: http://sqlfiddle.com/#!4/90ba0/12
The rule of thumb is that the filters must appear in the ON condition of the table they depend on.
Move filter into the LEFT JOIN , also use COALESCE to have your results display 0 instead of null as you requested in your question
select S.NAME,COALESCE(ISTATUS.STATUS,0),COUNT(ISTATUS.Q_ID) as TOTAL
from STAFF S
LEFT OUTER JOIN QUESTION_STATUS ISTATUS
ON S.ID = ISTATUS.DONE_BY
AND ISTATUS.STATUS =2
GROUP BY S.NAME,ISTATUS.STATUS