I have a query that I am running to pull hours from a database. I'm using 2 tables Employee_TB and Payroll_Hours_TB. The query is working, however it's not displaying active employees with "0" hours. I would like the query to show those employees who are active Employee_Tb.Active_Flag = 1 with hours, and 0 hours for the date range.
SELECT
REPLACE(REPLACE(Employee_Tb.First_Name, '.', ''), ' ', '') AS FirstName,
REPLACE(REPLACE(Employee_Tb.Last_Name, '.', ''), ' ', '') AS LastName,
Employee_Tb.Home_Store_Id, Employee_Tb.Payroll_Id,
SUM(Payroll_Hours_Tb.Hours_Worked) AS RegHours
FROM Employee_Tb
LEFT OUTER JOIN Payroll_Hours_Tb ON Employee_Tb.Employee_Id = Payroll_Hours_Tb.Employee_Id
WHERE (Payroll_Hours_Tb.Work_Date BETWEEN #startdate AND #enddate)
AND (Employee_Tb.Active_Flag = 1)
GROUP BY Employee_Tb.Payroll_Id, Employee_Tb.First_Name, Employee_Tb.Last_Name, Employee_Tb.Home_Store_Id
Move the following condition from the where clause to the on clause:
(Payroll_Hours_Tb.Work_Date BETWEEN #startdate AND #enddate)
...like so:
-- simplified column list for demonstration
select
e.Employee_Id
,coalesce(sum(h.Hours_Worked), 0) as RegHours
from Employee_Tb as e
left join Payroll_Hours_Tb as h
on e.Employee_Id = h.Employee_Id
and h.Work_Date between #startdate and #enddate
where e.Active_Flag = 1
group by e.Employee_Id
Otherwise you're filtering the entire set after the join.
Is it showing null instead of 0?
Maybe you can try something like
ISNULL(SUM(Payroll_Hours_Tb.Hours_Worked), 0) AS RegHours
Related
I have 2 SQL queries. I have looked at some of the examples on the site and still confused about how to combine them. I would like both queries in one table.
Thank you for your help
Jeremy
SELECT DISTINCT
"exStudent"."Student_StudentID" AS StudentID,
"exPerson"."Person_FirstName" + ' ' + "exPerson"."Person_LastName" AS FirstLast,
"exPerson"."Person_LastName" AS LastName,
"exPerson"."Person_FirstName" AS FirstName,
"exPerson"."Person_Gender" AS Gender,
ISNULL("exStudentEnrollment"."StudentEnrollment_Building",'') AS Building,
"exStudentEnrollment"."StudentEnrollment_Grade" AS Grade,
ISNULL("exStudentEnrollment"."StudentEnrollment_Homeroom",'') AS Homeroom,
ISNULL("exStudentEnrollment"."StudentEnrollment_HomeroomTeacher",'') AS HRTeacher
FROM
"exStudent" "exStudent"
INNER JOIN
"exPerson" "exPerson" ON "exStudent"."ForeignKey" = "exPerson"."ForeignKey"
INNER JOIN
"exPersonMailing" "exPersonMailing" ON "exPerson"."ForeignKey" = "exPersonMailing"."ForeignKey"
INNER JOIN
"exStudentEnrollment" "exStudentEnrollment" ON "exStudent"."ForeignKey" = "exStudentEnrollment"."ForeignKey"
WHERE
"exStudentEnrollment"."StudentEnrollment_Current" = 1
AND "exStudentEnrollment"."StudentEnrollment_Homeroom" <> ''
AND "exStudentEnrollment"."StudentEnrollment_SchoolYear"= (DATENAME(YEAR, '07-01-' + CONVERT(VARCHAR, YEAR(DATEADD(MONTH, -6, GETDATE())))) + '-' + DATENAME(YEAR, '06-30-' + CONVERT(VARCHAR, YEAR(DATEADD(MONTH, +6, GETDATE())))))
ORDER BY
Homeroom, Gender, LastName, FirstName
This is the second query:
select *
from UserDefinedScreen --ID for "Lunch IDs" is 2
select *
from UserDefinedField
where UserDefinedScreen_ID = 2 --ID for "Lunch ID" field is 3
select s.StudentID, pudf.Value
from PersonUserDefinedField pudf
join PersonUserDefinedScreen puds on pudf.PersonUserDefinedScreen_ID = puds.ID
join Person p on puds.Person_ID = p.ID
join Student s on s.Person_ID = p.ID
where pudf.UserDefinedField_ID = 3
I want to create a where clause that will take into account the termination date and say if they hire date is between these values and the term date isn't on or before the hiredate - IE the employee never started - how would I go about that? So far I have this:
SELECT A.AdpID AS EmployeeID,
ISNULL(A.Lname, '') AS [Last Name],
ISNULL(A.Fname, '') AS [First Name],
ISNULL(A.PrimaryEmail, '') AS [Email],
ISNULL(M.Fname + ' ' + M.Lname, '') AS Manager,
ISNULL(CONVERT(VARCHAR(100), A.HireDate, 101), '') AS HireDate,
ISNULL(CONVERT(VARCHAR(100), A.TerminationDate, 101), '') AS TermDate,
ISNULL(DIV.DivisionName, '') AS Division,
ISNULL(FUN.FunctionName, '') AS [Function],
ISNULL(DEP.DepartmentName, '') AS Department,
ISNULL(WGP.WorkgroupName, '') AS Workgroup,
ISNULL(LOB.CcaLOBName, '') AS LOB,
ISNULL(MAES.EmpStatusDesc, '') AS [Employee Type]
FROM dbo.Associates AS A
LEFT OUTER JOIN dbo.Associates AS M -- Look up for associate information
ON A.SuperPrincipal = M.AssocId
LEFT OUTER JOIN dbo.MasterCCALob AS LOB -- Look up line of business
ON A.LobID = LOB.CcaLOBID
LEFT OUTER JOIN dbo.MasterAssocEmpStatus AS MAES -- Look up for employee type
ON A.EmpStatusID = MAES.EmpStatusID
LEFT OUTER JOIN dbo.AssociatesDepartment AS DEP WITH(NOLOCK) -- Look up for Department
ON A.AssociatesDepartmentID = DEP.AssociatesDepartmentID
LEFT OUTER JOIN dbo.AssociatesDivision AS DIV WITH(NOLOCK) -- Look up for Division
ON A.AssociatesDivisionID = DIV.AssociatesDivisionID
LEFT OUTER JOIN dbo.AssociatesWorkGroup AS WGP WITH(NOLOCK) -- Look up for WorkGroup
ON A.AssociatesWorkgroupID = WGP.AssociatesWorkgroupID
LEFT OUTER JOIN dbo.AssociatesFunction AS FUN WITH(NOLOCK) -- Look up for Function
ON A.AssociatesFunctionID = FUN.AssociatesFunctionID
WHERE ( LEN(A.TerminationDate) = 0
AND ISNULL(A.HireDate, '1900-01-01') BETWEEN '2015-10-01' AND GETDATE() )
OR ( LEN(A.TerminationDate) > 0
AND ISNULL(A.TerminationDate, '1900-01-01') > ISNULL(A.HireDate, '1900-01-01')
AND ISNULL(A.HireDate, '1900-01-01') BETWEEN '2015-10-01' AND GETDATE() )
ORDER BY A.HireDate DESC
There where clause is as bad as can be because I get the craziest results back from this
I was working on this query for awhile and I'm trying to figure out how to get this query to show all the initials in the where clause in the output table regardless as to whether that person has a p.Id or not. This is because I will be putting this information into a pre-formatted Excel table. Thanks in advance! EDITED:
SELECT
e.Initials, COUNT(p.Id) As "NT > 7"
FROM
Employees AS e
LEFT JOIN
Projects AS p
ON
e.Id = p.NTEmployeeId AND
cast(p.NTDate as Datetime) < cast(dateadd(day, -7, (getdate())) as Datetime)
JOIN
Statuses AS s
ON
s.Id = p.StatusId AND
s.Code in ('WIPR', 'RISK', 'PEND')
WHERE
e.Initials IN('af', 'cm' , 'jy','br','dfv','rxc','tm','axk','hd','sa','rw')
GROUP BY (e.Initials);
You need an additional left join and to move the conditions on all but the first table into on clauses. Remember, the where clause will turn the outer joins to inner joins, because NULL values don't (generally) match conditions.
SELECT e.Initials, COUNT(p.Id) As "NT > 7"
FROM Employees e LEFT JOIN
Projects p
ON e.Id = p.NTEmployeeId AND
cast(p.NTDate as Date) < cast(getdate() as date) -- do date comparisons as dates, not strings
LEFT JOIN -- NEED LEFT JOIN HERE, or `ON` clause turns it into inner join
Statuses s
ON s.Id = p.StatusId AND
s.Code in ('WIPR', 'RISK', 'PEND') -- `LIKE`/`OR` isn't wrong but `IN` is easier
WHERE e.Initials IN ('af', 'cm' , 'jy', 'br','dfv', 'rxc', 'tm', 'axk', 'hd', 'sa', 'rw')
GROUP BY e.Initials;
I made a couple other changes:
Use dates for comparing dates, not strings. I think I have the logic right.
Use IN instead of chains of ORs if you can.
And for what you are doing, you might want to be counting the matching statuses rather than the matching people.
I figured out what I needed to do to get the correct answer to display. Please see below:
SELECT
e.Initials, COUNT(CASE WHEN s.Code in ('WIPR', 'RISK', 'PEND')
and cast(p.NTDate as Datetime) < cast(dateadd(day, -7, (getdate())) as Datetime) THEN p.Id END) As "NT > 7"
FROM
Employees AS e
LEFT JOIN
Projects AS p
ON
e.Id = p.NTEmployeeId
JOIN
Statuses AS s
ON
s.Id = p.StatusId
WHERE
e.Initials IN('af', 'cm' , 'jy','br','dfv','rxc','tm','axk','hxd','rw')
GROUP BY (e.Initials);
When i execute the following query, i get the message like
"Ora-01427 single-row subquery returns more than one row"
SELECT E.I_EmpID AS EMPID,
E.I_EMPCODE AS EMPCODE,
E.I_EmpName AS EMPNAME,
REPLACE(TO_CHAR(A.I_REQDATE, 'DD-Mon-YYYY'), ' ', '') AS FROMDATE,
REPLACE(TO_CHAR(A.I_ENDDATE, 'DD-Mon-YYYY'), ' ', '') AS TODATE,
TO_CHAR(NOD) AS NOD,
DECODE(A.I_DURATION,
'FD',
'FullDay',
'FN',
'ForeNoon',
'AN',
'AfterNoon') AS DURATION,
L.I_LeaveType AS LEAVETYPE,
REPLACE(TO_CHAR((SELECT C.I_WORKDATE
FROM T_COMPENSATION C
WHERE C.I_COMPENSATEDDATE = A.I_REQDATE
AND C.I_EMPID = A.I_EMPID),
'DD-Mon-YYYY'),
' ',
'') AS WORKDATE,
A.I_REASON AS REASON,
AP.I_REJECTREASON AS REJECTREASON
FROM T_LEAVEAPPLY A
INNER JOIN T_EMPLOYEE_MS E
ON A.I_EMPID = E.I_EmpID
AND UPPER(E.I_IsActive) = 'YES'
AND A.I_STATUS = '1'
INNER JOIN T_LeaveType_MS L
ON A.I_LEAVETYPEID = L.I_LEAVETYPEID
LEFT OUTER JOIN T_APPROVAL AP
ON A.I_REQDATE = AP.I_REQDATE
AND A.I_EMPID = AP.I_EMPID
AND AP.I_APPROVALSTATUS = '1'
WHERE E.I_EMPID <> '22'
ORDER BY A.I_REQDATE DESC
when i execute this without ORDER BY A.I_REQDATE DESC it returns 100 rows...
Use the following query:
SELECT E.I_EmpID AS EMPID,
E.I_EMPCODE AS EMPCODE,
E.I_EmpName AS EMPNAME,
REPLACE(TO_CHAR(A.I_REQDATE, 'DD-Mon-YYYY'), ' ', '') AS FROMDATE,
REPLACE(TO_CHAR(A.I_ENDDATE, 'DD-Mon-YYYY'), ' ', '') AS TODATE,
TO_CHAR(NOD) AS NOD,
DECODE(A.I_DURATION,
'FD',
'FullDay',
'FN',
'ForeNoon',
'AN',
'AfterNoon') AS DURATION,
L.I_LeaveType AS LEAVETYPE,
REPLACE(TO_CHAR((SELECT max(C.I_WORKDATE)
FROM T_COMPENSATION C
WHERE C.I_COMPENSATEDDATE = A.I_REQDATE
AND C.I_EMPID = A.I_EMPID),
'DD-Mon-YYYY'),
' ',
'') AS WORKDATE,
A.I_REASON AS REASON,
AP.I_REJECTREASON AS REJECTREASON
FROM T_LEAVEAPPLY A
INNER JOIN T_EMPLOYEE_MS E
ON A.I_EMPID = E.I_EmpID
AND UPPER(E.I_IsActive) = 'YES'
AND A.I_STATUS = '1'
INNER JOIN T_LeaveType_MS L
ON A.I_LEAVETYPEID = L.I_LEAVETYPEID
LEFT OUTER JOIN T_APPROVAL AP
ON A.I_REQDATE = AP.I_REQDATE
AND A.I_EMPID = AP.I_EMPID
AND AP.I_APPROVALSTATUS = '1'
WHERE E.I_EMPID <> '22'
ORDER BY A.I_REQDATE DESC
The trick is to force the inner query return only one record by adding an aggregate function (I have used max() here). This will work perfectly as far as the query is concerned, but, honestly, OP should investigate why the inner query is returning multiple records by examining the data. Are these multiple records really relevant business wise?
The only subquery appears to be this - try adding a ROWNUM limit to the where to be sure:
(SELECT C.I_WORKDATE
FROM T_COMPENSATION C
WHERE C.I_COMPENSATEDDATE = A.I_REQDATE AND ROWNUM <= 1
AND C.I_EMPID = A.I_EMPID)
You do need to investigate why this isn't unique, however - e.g. the employee might have had more than one C.I_COMPENSATEDDATE on the matched date.
For performance reasons, you should also see if the lookup subquery can be rearranged into an inner / left join, i.e.
SELECT
...
REPLACE(TO_CHAR(C.I_WORKDATE, 'DD-Mon-YYYY'),
' ',
'') AS WORKDATE,
...
INNER JOIN T_EMPLOYEE_MS E
...
LEFT OUTER JOIN T_COMPENSATION C
ON C.I_COMPENSATEDDATE = A.I_REQDATE
AND C.I_EMPID = A.I_EMPID
...
(SELECT C.I_WORKDATE
FROM T_COMPENSATION C
WHERE C.I_COMPENSATEDDATE = A.I_REQDATE AND ROWNUM <= 1
AND C.I_EMPID = A.I_EMPID)
I'm getting an incorrect count when I use multiple 'Joins'. It should only show 3 as the total but it's returning 134 for the total. What's the proper way to use COUNT with multiple 'Joins'?
SELECT r.Field1
, Total = COUNT(r.Field1)
FROM Location1.dbo.Table1 r ( NOLOCK )
JOIN Location2.dbo.Table2 i ( NOLOCK ) ON r.Field1 = i.Field1
JOIN Location3.dbo.Table3 rt ( NOLOCK ) ON rt.Field1 = i.Field1
AND rt.Field2 = r.Field2
WHERE r.Field3 = '40'
AND r.Field4 = 'H'
AND r.Field1 = '516'
AND CONVERT(CHAR(10), r.TIMESTAMP, 101) = CONVERT(CHAR(10), GETDATE(), 101)
GROUP BY r.Field1
That's how joins work. You get the total number of results as a result of the joins. So even if the original table only has one row that matches your criteria, the COUNT from a JOIN could have hundreds of results due to one-to-many relationship. You can see why by changing your query:
SELECT *
FROM Location1.dbo.Table1 r ( NOLOCK )
JOIN Location2.dbo.Table2 i ( NOLOCK ) ON r.Field1 = i.Field1
JOIN Location3.dbo.Table3 rt ( NOLOCK ) ON rt.Field1 = i.Field1
AND rt.Field2 = r.Field2
WHERE r.Field3 = '40'
AND r.Field4 = 'H'
AND r.Field1 = '516'
AND CONVERT(CHAR(10), r.TIMESTAMP, 101) = CONVERT(CHAR(10), GETDATE(), 101)
This will return all rows from all tables and you'll see the 134 rows. If you aren't interested in the total, then don't do the join -- since you say that the query without the joins gives you the expected result of 3.