SQL to show date for Null value based on query - sql

I have two tables, employee and employee time entry. I have run a query that is showing me all employees with the sum of time entered or 0 as null value. In the next column I have week number. If employee has not entered time during the week than it is giving me 0 but it is also giving me null value at the week number. how can I force query to show me week number, assuming no entry was made by employee.
Select
Concat(Empfname,Emplname) as EmployeeName,
department,
iif (sum(whours) is null, 0, sum(whours)) CurrentHours,
Datepart (ww,wdate) WeekNum
From
employee as e
left outer join
TimeEntry as w on e.id = w.eId
and wdate between '01/01/2017' and '01/31/2017'
group by
Concat(Empfname,Emplname), department, Datepart(ww, wdate)
Output
EmployeeName Department CurrentHours WeekNum
------------------------------------------------
John Smith Sales 8 1
Smith John Operations 0 Null
How can I tell it is also from WeekNum 1?
Thanks

The idea is to generate all rows using cross join and then use left join to bring in the rows you want something like this:
Select Concat(e.Empfname, e.Emplname) as EmployeeName, e.department,
coalesce(sum(whours), 0) as CurrentHours
datepart(week, wd.wdate) as WeekNum
from employee e cross join
(select distinct wdate from TimeEntry) wd left outer join
TimeEntry tw
on e.id = w.eId and tw.wdate = wd.wdate
where wd.wdate between '2017-01-01' and '2017-01-31'
group by Concat(e.Empfname, e.Emplname), e.department, Datepart(week, wd.wdate);

Try this:
Select Concat(Empfname,Emplname) as EmployeeName, department
iif (sum(whours) is null, 0, sum(whours)) CurrentHours
ISNULL(Datepart (ww,wdate),1) WeekNum
From employee as e left outer join TimeEntry as w on e.id=w.eId
and wdate between '01/01/2017' and '01/31/2017'
group by Concat(Empfname,Emplname), department, ISNULL(Datepart (ww,wdate),1)
which will force any NULL value to show 1 instead of NULL itself

Related

Calculate SUM from one table and display columns from another

I have 2 tables, Employee, and Transaction
Transaction
tID
cID
carID
eID
tDate
PickupDate
ReturnDate
Amount_Due
Employee
eID
fName
lName
Job
Manager
Hired
I need to calculate the commission (2.5%) and display that along with fName and lName.
I've calculated the commission, I think I've done the join correctly but can't quite figure out how to add in a SELECT to show the other two columns.
SELECT t.Amount_Due
, SUM(t.Amount_Due*0.025) AS Commission
FROM [Transaction] t
JOIN Employee e ON t.eID = e.eID
GROUP BY t.Amount_Due
You are grouping by the wrong columns, and you are trying to select Amount_Due and aggregate it at the same time:
SELECT e.fName
, e.lName,
, SUM(t.Amount_Due * 0.025) AS Commission
FROM [Transaction] t
JOIN Employee e
ON t.eID = e.eID
GROUP BY e.ID, e.fName, e.lName;
Probably just a typo - the JOIN should probably be ON t.eID = e.eId. You need to include both tables (table aliases) involved - you're currently just using the t.eID twice.
Try this :
SELECT
t.Amount_Due, SUM(t.Amount_Due*0.025) AS Commission
FROM
[Transaction] t
JOIN
Employee e ON t.eID = e.eID
GROUP BY
t.Amount_Due
As pointed out by #charlieface - it seems very odd that you're summing the Amount_due, and at the same time trying to group by that same column..... my best guess is that you probably want to group by the employee, based on their eID - so use something like this:
SELECT
e.eID, e.fName, e.lName, SUM(t.Amount_Due*0.025) AS Commission
FROM
[Transaction] t
JOIN
Employee e ON t.eID = e.eID
GROUP BY
e.eID, e.fName, e.lName
for that.

How can I get the absence days of all employee? SQL Server

How can I get the absence days and the present days of all employees , I would like an output like this:
employeeId DATE Status
1 2021/03/04 Absent
1 2021/03/05 Present
2 2021/03/04 Present
2 2021/03/05 Present
What I can get now only the present days :
select distinct DATEPART(dw,er.AddAt) as dayId,
DATENAME(dw,er.AddAt) as dayname,
DATEPART(DAY,er.AddAt) as monthday,
er.employeeId,firstName as Name
from records er,employee
where er.employeeId=employee.employeeId
Update:
After Testing the solution of #Gordon Linoff , that's what I got:
and I have two problems :
I have duplicate data ( 3 times duplicate )
When I select a other month than February , I got no data.
select Day, WeekdayName, e.employeeid,
(case when r.employeeid is not null then 'present' else 'absent' end)
from Get_Calendar_Date(DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0) ,DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1)) c cross join
employee e left join
records r
on c.Day = DATEPART(DAY,r.AddAt) and e.employeeid = r.employeeid
where Month=1
Let me assume that you have a calendar table and a table of all employees. The idea is then to do a cross join to generate the rows and a left join to bring in the existing data:
select c.dayid, c.dayname, e.employeeid,
(case when r.employeeid is not null then 'present' else 'absent' end)
from calendar c cross join
employees e left join
records r
on c.dayid = r.dayid and e.employeeid = r.employeeid;
I assume you have a calendar table because you have a column called dayid. If you don't have one, you can construct one using a numbers table, a recursive CTE, a subquery on records or some other method.
You can probably just use existing dates for the calendar:
from (select distinct dayid from records) d

SQL GROUP BY FirstName, Lastname and Year

I have made the query below=>
SELECT FirstName,
LastName,
COUNT(*) AantalBestellingen,
YEAR(Orders.OrderDate) as Jaar
from Employees
RIGHT JOIN Orders ON (Employees.EmployeeID=Orders.EmployeeID)
WHERE Employees.ReportsTo IS NOT NULL
GROUP BY Employees.FirstName, Employees.LastName, YEAR (Orders.OrderDate)
ORDER BY YEAR (Orders.OrderDate)
I need to select the first name, lastname from the employees and the total orders they have processed within the last year.
After adding the group by year to the query it's not showing the unique employees anymore but it shows the years. I need to get only the unique employees and the last order year they have processed an order in.
Any advice what i'm doing wrong?
One way to do this is with an inner select:
SELECT
FirstName,
LastName,
COUNT(*) as AantalBestellingen,
(select YEAR(max(Orders.OrderDate)) from Orders O
where Employees.EmployeeID=O.EmployeeID) as Jaar
from
Employees
RIGHT JOIN Orders
ON (Employees.EmployeeID=Orders.EmployeeID)
WHERE
Employees.ReportsTo IS NOT NULL
GROUP BY
Employees.FirstName,
Employees.LastName
ORDER BY Jaar
You can place the Last Year condition in WHERE clause as follows
SELECT FirstName,
LastName,
COUNT(*) AantalBestellingen,
from Employees
RIGHT JOIN Orders ON (Employees.EmployeeID=Orders.EmployeeID)
WHERE Employees.ReportsTo IS NOT NULL AND YEAR(Orders.OrderDate) = 2014
GROUP BY Employees.FirstName, Employees.LastName
Can you try this one... This will give all employee, his only last year order count and last year.
;with cteMaxYear as
(select max(YEAR(Orders.OrderDate)) MaxOrderYear, EmployeeID
from Orders
group by EmployeeID)
SELECT FirstName,
LastName,
COUNT(*) AantalBestellingen,
m.MaxOrderYear as Jaar
from Employees e
left outer join cteMaxYear m
inner join Orders o ON m.EmployeeID=o.EmployeeID and m.MaxOrderYear=o.YEAR(Orders.OrderDate)
on e.EmployeeID = m.EmployeeID
WHERE e.ReportsTo IS NOT NULL
GROUP BY e.FirstName, e.LastName, m.MaxOrderYear
ORDER BY m.MaxOrderYear

How to show the participation percentage in each department?

I have the following database design:
Employees Table: EmployeeID, Name, OrgCode
Departments Table: OrgCode, DepatName
CompleteSurvey Table: ID, ParticipantID
And I need to develop a table that shows the total number of employees in each department, and the total number of participants who completed the survey in each department, too. Then, I want to show the percentage of participation in each department which is mainly equal to the total number of participants / total number of employees.
I came up with the following two queries but I have to come up with one query that shows the above requirement, so how to do that?
Total number of employees in each department:
SELECT COUNT(DISTINCT dbo.Employees.EmployeeID) AS [Total Number of Employees],
dbo.Departments.DepartmentName
FROM dbo.Departments
INNER JOIN dbo.Employees ON dbo.Departments.OrgCode = dbo.Employees.OrgCode
GROUP BY dbo.Departments.DepartmentName
Total number of participants in each department:
SELECT COUNT(DISTINCT dbo.Employees.EmployeeID) AS [Total Number of Employees],
dbo.Departments.DepartmentName
FROM dbo.Departments
INNER JOIN dbo.Employees ON dbo.Departments.OrgCode = dbo.Employees.OrgCode
INNER JOIN dbo.CompleteSurvey ON dbo.Employees.EmployeeID = dbo.CompleteSurvey.RespondantID
GROUP BY dbo.Departments.DepartmentName
The problem with the second query that shows the participants, it doesn't show all the departments even if they have no participants, it should show zeros.
UPDATE:
Basically, what I want is to have one query that shows the total number of employees in each department and the total number of participants who completed the survey in each department, and show the percentage of participation.
If I understood correctly that CompleteSurvey is filled with EmployeeID when employe submits a survey, this query will retrieve the info you need. You can check live test # Sql Fiddle.
select Departments.DepatName,
count (Employees.EmployeeID) Employees,
count (CompleteSurvey.ID) Finished,
cast (count (CompleteSurvey.ID) as float) / count (Employees.EmployeeID)
PercentageFinished
from Departments
inner join Employees
on Departments.OrgCode = Employees.OrgCode
left join CompleteSurvey
on Employees.EmployeeID = CompleteSurvey.ParticipantID
group by Departments.DepatName
If you need all the departments, use this query:
select Departments.DepatName,
count (Employees.EmployeeID) Employees,
count (CompleteSurvey.ID) Finished,
case when count (Employees.EmployeeID) <> 0
then cast (count (CompleteSurvey.ID) as float)
/ count (Employees.EmployeeID)
else 0
end PercentageFinished
from Departments
left join Employees
on Departments.OrgCode = Employees.OrgCode
left join CompleteSurvey
on Employees.EmployeeID = CompleteSurvey.ParticipantID
group by Departments.DepatName
New test # Sql Fiddle.
Are you looking something like this (using tables variables)
DECLARE #Employees Table(EmployeeID INT, Name VARCHAR(50), OrgCode VARCHAR(50) )
DECLARE #Departments Table( OrgCode INT, DepartmentName VARCHAR(50) )
DECLARE #CompleteSurvey Table( ID INT, RespondantID INT)
INSERT INTO #Employees VALUES(12,'Emp 12', 1000),(13,'Emp 13', 1000),(112,'Emp 112', 2000), (113,'Emp 114', 2000)
INSERT INTO #Departments VALUES(1000, 'dept 1000'),(2000, 'dept 2000')
,(3000, 'no employee dept 3000')
INSERT INTO #CompleteSurvey VALUES (901,12), (901,112),(902,13), (902,112)
SELECT COUNT(DISTINCT EmployeeID) AS [Total Number of Employees], D.DepartmentName FROM #Departments D
LEFT OUTER JOIN #Employees E
ON D.OrgCode = E.OrgCode GROUP BY D.DepartmentName
SELECT D.DepartmentName,COUNT(DISTINCT E.EmployeeID) AS [Total Number of Employees],
COUNT(DISTINCT S.RespondantID )AS completed_survey ,
CASE WHEN COUNT(DISTINCT E.EmployeeID)>0 THEN COUNT(DISTINCT S.RespondantID )/
CAST(COUNT(DISTINCT E.EmployeeID)AS FLOAT)*100 ELSE 0 END AS particPerc
FROM #Departments D LEFT OUTER JOIN #Employees E ON D.OrgCode = E.OrgCode
LEFT OUTER JOIN #CompleteSurvey S ON E.EmployeeID =S.RespondantID GROUP BY D.DepartmentName
which outputs:
Total Number of Employees DepartmentName
2 dept 1000
2 dept 2000
0 no employee dept 3000
and finally what I think you're asking for
DepartmentName Total Number of Employees completed_survey particPerc
dept 1000 2 2 100
dept 2000 2 1 50
no employee dept 3000 0 0 0

Write a SQL Query to replace values and include all the Dates

Well I have this -
Table DimDate- Date
Table Employee- Id,Name,Points,Date
Now the Employee table has points for everyday unless they did not come...so the Date does not have all the Dates entries... I mean for e.g in a week he did not come for 2 days the Employee table has only 5 rows...so I have this dimdate table which has all the dates till 2050 which I want to join with and add Zeros for the dates he does not have points. So I have written this query but does not work -
Select E.EmployeeId,D.Date,isNull(E.Points,0) from DimDate D left join Employee E on D.Date between '01-01-2009'and '06-01-2009' where E.EmployeeId=1
The above query give multiple dates and I tried group by on Date but does not work.
You probably dont want to join the two tables on a date range but a date. Then filter the record set by the date range. example
Select
E.EmployeeId,
D.Date,
isNull(E.Points,0)
from DimDate D
left join Employee E on D.Date = E.Date
where E.EmployeeId=1
AND D.Date Between '01-01-2009'and '06-01-2009'
Edited:
Select
E.EmployeeId,
D.Date,
isNull(E.Points,0)
from DimDate D
left join Employee E on D.Date = E.Date And E.EmployeeId=1
where D.Date Between '01-01-2009'and '06-01-2009'
OR
Select
E.EmployeeId,
D.Date,
isNull(E.Points,0)
from DimDate D
left join Employee E on D.Date = E.Date
where (E.EmployeeId = 1 OR E.EmployeeId is NULL)
AND D.Date Between '01-01-2009'and '06-01-2009'
I think you need a cross join between the dimdates table and the table where your employees are defined. This will give you a list of records with all employee/date combinations. Then the result of that needs to be left outer joined to the table that has the employee points records.
Something like:
Select CJ.EmployeeId,CJ.Date,isNull(E.Points,0)
from (SELECT EmployeeID, D.Date
from DimDate D CROSS JOIN [EmployeeDefinitionTable] as edt) as CJ
left outer join Employee E on CJ.Date =E.Date AND CJ.EmployeeId = E.EmployeeId
where CJ.Date between '01-01-2009'and '06-01-2009'
and E.EmployeeId = 1
Where EmployeeDefinitionTable is a table that uniquely lists all employees (or at least their id's for this problem statement).
This also captures employees with no points entries.
The between statement and/or EmployeeId filtering could be moved up into the cross join if it fits your requirements. It would make the cross join more efficient.