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.
Related
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
How do i connect both these tables to have data connected based on department names and week number. So that if the weeknumber don't match up, it shows nulls for others.
http://sqlfiddle.com/#!6/3bbd3/1
A full outer join should do the trick:
SELECT d.id,
d.name,
f.id,
DATEPART(WEEK, setupdate) as WeekNumber
FROM departments d
FULL OUTER JOIN forecast f ON d.name = f.name AND
DATEPART(WEEK, setupdate) = DATEPART(WEEK, forecast)
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
I have the following relations:
and I want to to list all employees that joined the company before June of 2014 but did not receive a commission in June 2014 using some kind of outer join. I came up with this query but it is not working. Could someone tell me how to query this?
SELECT DISTINCT Employee.EmpId, Employee.EmpName
FROM Employee
LEFT OUTER JOIN Commission
ON Employee.EmpId = Commission.EmpId
WHERE Employee.JoinDate BETWEEN Employee.JoinDate AND '2014-06-31'
GROUP BY Employee.EmpId, Employee.EmpName
HAVING COUNT(Commission.Commdate BETWEEN '2014-06-01' AND '2014-06-31') = 0
ORDER BY Employee.EmpId
The LEFT JOIN is a good idea. But, you want the commission dates in the ON clause. Then find the employees that do not match. So, here is a version of the query (cleaned up to use table aliases):
SELECT e.EmpId, e.EmpName
FROM Employee e LEFT OUTER JOIN
Commission c
ON e.EmpId = c.EmpId AND
c.Commdate BETWEEN '2014-06-01' AND '2014-06-31'
WHERE e.JoinDate < '2014-06-01' AND c.EmpID IS NULL
GROUP BY e.EmpId, e.EmpName
ORDER BY e.EmpId;
Perhaps a more natural way to write the query, though, is:
SELECT e.*
FROM employee e
WHERE NOT EXISTS (SELECT 1
FROM Commission c
WHERE e.EmpId = c.EmpId AND
c.Commdate BETWEEN '2014-06-01' AND '2014-06-31'
) AND
e.JoinDate < '2014-06-01';
I have 4 tables, in that I want to fetch records from all 4 and aggregate the values
I have these tables
I am expecting this output
but getting this output as a Cartesian product
It is multiplying the expenses and allocation
Here is my query
select
a.NAME, b.P_NAME,
sum(a.DURATION) DURATION,
sum(b.[EXP]) EXPEN
from
(select
e.ID, a.P_ID, e.NAME, a.DURATION DURATION
from
EMPLOYEE e
inner join
ALLOCATION a ON e.ID = a.E_ID) a
inner join
(select
p.P_ID, e.E_ID, p.P_NAME, e.amt [EXP]
from
PROJECT p
inner join
EXPENSES e ON p.P_ID = e.P_ID) b ON a.ID = b.E_ID
and a.P_ID = b.P_ID
group by
a.NAME, b.P_NAME
Can anyone suggest something about this.
The following should work:
SELECT e.Name,p.Name,COALESCE(d.Duration,0),COALESCE(exp.Expen,0)
FROM
Employee e
CROSS JOIN
Project p
LEFT JOIN
(SELECT E_ID,P_ID,SUM(Duration) as Duration FROM Allocation
GROUP BY E_ID,P_ID) d
ON
e.E_ID = d.E_ID and
p.P_ID = d.P_ID
LEFT JOIN
(SELECT E_ID,P_ID,SUM(AMT) as Expen FROM Expenses
GROUP BY E_ID,P_ID) exp
ON
e.E_ID = exp.E_ID and
p.P_ID = exp.P_ID
WHERE
d.E_ID is not null or
exp.E_ID is not null
I've tried to write a query that will produce results where e.g. there are rows in Expenses but no rows in Allocations (or vice versa) for some particular E_ID,P_ID combination.
Use left join in select query by passing common id for all table
Hi I got the answer what I want from some modification in the query
The above query is also working like a charm and have done some modification to the original query and got the answer
Just have to group by the inner queries and then join the queries it will then not showing Cartesian product
Here is the updated one
select a.NAME,b.P_NAME,sum(a.DURATION) DURATION,sum(b.[EXP]) EXPEN from
(select e.ID,a.P_ID, e.NAME,sum(a.DURATION) DURATION from EMPLOYEE e inner join ALLOCATION a
ON e.ID=a.E_ID group by e.ID,e.NAME,a.P_ID) a
inner join
(select p.P_ID,e.E_ID, p.P_NAME,sum(e.amt) [EXP] from PROJECT p inner join EXPENSES e
ON p.P_ID=e.P_ID group by p.P_ID,p.P_NAME,e.E_ID) b
ON a.ID=b.e_ID and a.P_ID=b.P_ID group by a.NAME,b.P_NAME
Showing the correct output