I have 2 queries which return counts of different information in a table:
SELECT Date, COUNT(*) AS Total
FROM Table
WHERE Type = 7 AND Date >= '2010-01-01'
GROUP BY Date
HAVING COUNT(*) > 5000
ORDER BY Date
which returns the totals for all of the 'busy' dates:
Date Total
---------- -----------
2010-01-05 9466
2010-02-02 8747
2010-03-02 9010
2010-04-06 7916
2010-05-05 9342
2010-06-02 8723
2010-07-02 7829
2010-08-03 8411
2010-09-02 7687
2010-10-04 7706
2010-11-02 8567
2010-12-02 7645
and
SELECT Date, COUNT(*) AS Failures
FROM Table
WHERE Type = 7 AND ErrorCode = -2 AND Date >= '2010-01-01'
GROUP BY Date
ORDER BY Date
which returns the total failures (all of which happened on busy dates):
Date Failures
---------- -----------
2010-09-02 29
2010-10-04 16
2010-11-02 8
Is it possible to combine these into a single query to return one result?
E.g.:
Date Total Failures
---------- ----------- -----------
2010-01-05 9466
2010-02-02 8747
2010-03-02 9010
2010-04-06 7916
2010-05-05 9342
2010-06-02 8723
2010-07-02 7829
2010-08-03 8411
2010-09-02 7687 29
2010-10-04 7706 16
2010-11-02 8567 8
2010-12-02 7645
;With baseData As
(
SELECT
Date,
COUNT(*) AS Total,
COUNT(CASE WHEN ErrorCode = -2 THEN 1 END) AS Failures
FROM Table
WHERE Type = 7 AND Date >= '2010-01-01'
GROUP BY Date
)
SELECT
Date,
Total,
Failures,
CAST(Failures AS float)/Total AS Ratio
FROM baseData
WHERE Total > 5000 OR Failures > 0
ORDER BY Date
If you can refactor to the same where clause, this should be possible.
I haven't taken your HAVING(Count()) into consideration
SELECT [Date], COUNT(*) AS Total, SUM(CASE WHEN ErrorCode = -2 THEN 1 ELSE 0 END) AS Failures
FROM [Table]
WHERE [Type] = 7 AND [Date] >= '2010-01-01'
GROUP BY [Date]
ORDER BY [Date]
Edit : Here is some test data
create table [Table]
(
[ErrorCode] int,
[Type] int,
[Date] datetime
)
insert into [table]([Date], [Type], [ErrorCode] )values ('1 Jan 2010', 7, 0)
insert into [table]([Date], [Type], [ErrorCode] )values ('1 Jan 2010', 7, -2)
insert into [table]([Date], [Type], [ErrorCode] )values ('2 Jan 2010', 7, -2)
insert into [table]([Date], [Type], [ErrorCode] )values ('2 Jan 2010', 8, -2)
insert into [table]([Date], [Type], [ErrorCode] )values ('2 Jan 2010', 7, 1)
yes you should be able to do a UNION ALL between the 2 tables
Related
I am searching for a way to sum columns by week.
This is the initial table data.
Date WeekNo Col1 Col2 Col3
2020/07/01 27 1 4 3
2020/07/04 27 3 3 1
2020/07/06 28 1 1 1
2020/07/11 28 1 3 8
and I want to add a row total to every end of the week like this:
Date WeekNo Col1 Col2 Col3
2020/07/01 27 1 4 3
2020/07/04 27 3 3 1
TOTAL 27 4 7 4
2020/07/06 28 1 1 1
2020/07/11 28 1 3 8
TOTAL 28 2 4 9
I tried something similar the the code below but I have multiple columns to sum.
Do you have other ideas, suggestions?
Also, grouping sets does not create a new row if there is no data for that week to sum (like 0 or NULL).
SELECT
YEAR(Date) AS OrderYear,
MONTH(Date) AS OrderMonth,
SUM(Col1) AS SumCol1
FROM tb
GROUP BY
GROUPING SETS
(
YEAR(Date), --1st grouping set
(YEAR(Date),MONTH(Date)) --2nd grouping set
)
Is this what you are after?
My solution uses the built in with rollup addition to the group by clause.
-- create sample data
declare #data table
(
[Date] Date,
WeekNo int,
Col1 int,
Col2 int,
Col3 int
);
insert into #data ([Date], WeekNo, Col1, Col2, Col3) values
('2020-07-01', 27, 1, 4, 3),
('2020-07-04', 27, 3, 3, 1),
('2020-07-06', 28, 1, 1, 1),
('2020-07-11', 28, 1, 3, 8);
-- solution
select case when grouping(d.Date) = 0
then convert(nvarchar(10), d.Date) -- type conversion so all column values have the same type
else 'TOTAL'
end as 'Date',
d.WeekNo,
sum(d.Col1) as 'Col1',
sum(d.Col2) as 'Col2',
sum(d.Col3) as 'Col3'
from #data d
group by d.WeekNo, d.Date with rollup -- "roll up" the aggregations
having grouping(d.WeekNo) = 0; -- filter out aggregation across weeks
Gives me:
Date WeekNo Col1 Col2 Col3
---------- ----------- ----------- ----------- -----------
2020-07-01 27 1 4 3
2020-07-04 27 3 3 1
TOTAL 27 4 7 4
2020-07-06 28 1 1 1
2020-07-11 28 1 3 8
TOTAL 28 2 4 9
You only need to add (DATEPART(wk, Date)) as aggregation rule after listing the other non-aggregated columns Date,Col1, Col2, Col3. Btw, you do not need a WeekNo column, since it could already be computer by use of (DATEPART(wk, Date)).
So far so good, but ordering is such a daunting task as returning null values for WeekNo column for subtotal. I used two analytic functions ( ROW_NUMBER() and FISRT_VALUE() to overcome this problem ) :
SELECT COALESCE(Date,'TOTAL') As Date,
DATEPART(wk, Date) AS WeekNo,
SUM(Col1) AS Col1,
SUM(Col2) AS Col2,
SUM(Col3) AS Col3
FROM tb
GROUP BY GROUPING SETS ( ( Date,Col1, Col2, Col3 ),
(DATEPART(wk, Date))
)
ORDER BY CASE WHEN DATEPART(wk, Date) IS NULL
THEN
ROW_NUMBER() OVER (PARTITION BY DATEPART(wk, Date)
ORDER BY COALESCE(Date,'TOTAL') )
ELSE
DATEPART(wk, Date) -
FIRST_VALUE(DATEPART(wk, Date))
OVER ( ORDER BY COALESCE(Date,'TOTAL') ) + 1
END,
DATEPART(wk, Date)
Demo
Consider the following table structure and sample data -
EmpID InputDateTime StatusINOUT
-------------------------------------
1 2018-05-26 08:44 1
1 2018-05-26 08:44 2
2 2018-05-28 08:44 1
2 2018-05-28 12:44 2
1 2018-05-21 08:44 1
1 2018-05-21 10:44 2
2 2018-05-23 08:44 1
2 2018-05-23 08:44 2
Now I want to separate column InputDateTime into two columns i.e., INTIME(1) and OUTTIME(2). The logic behind this is the date for which StatusInOut is 1 will be InTime and for StatusInOut is 2 that date value will be OUTTIME(2).
The expected output format is as shown below:
Empid INTIME(1) OUTIME(2)
--------------------------------------------
1 2018-05-26 08:44 2018-05-26 08:44
2 2018-05-28 08:44 2018-05-28 12:44
1 2018-05-21 08:44 2018-05-21 10:44
2 2018-05-23 08:44 2018-05-23 08:44
use case when
select empid,max(case when statusINOut=1 then Datetime end) as INtime,
max(case when statusINOut=2 then Datetime end) as Outtime
from table_name t
group by empid,convert(date,Datetime)
Try the following query using join and update.
create table #tempStatus (EmpId int, intTime datetime, sStatus int)
insert into #tempStatus
values(1, '2018-05-26 08:44', 1),
(1, '2018-05-26 08:44', 2),
(2, '2018-05-28 08:44', 1),
(2, '2018-05-28 12:44', 2),
(1, '2018-05-21 08:44', 1),
(1, '2018-05-21 10:44', 2),
(2, '2018-05-23 08:44', 1),
(2, '2018-05-23 08:44', 2)
,(3, '2018-05-23 08:44', 1)
select EmpId, MIN(intTime) as intTime, MAX(intTime) as OutTime into #tempA from (
select EmpId, intTime, intTime as OutTime
from #tempStatus where sStatus = 1
)a
group by EmpId, intTime
update s
set s.OutTime = t.outTime
from #tempA s
left join
(
select EmpId, MAX(outTime) as outTime from(
select EmpId, intTime as outTime
from #tempStatus where sStatus = 2
)b
group by empId,outTime) t
on s.EmpId = t.EmpId and Convert(Varchar,s.OutTime,112) = Convert(Varchar,t.outTime,112)
select * from #tempA order by EmpId
drop table #tempA
DROP TABLE #tempStatus
OR you can also try the below one query
select empid,
max(case when sStatus = 1 then intTime end) as INTIME,
max(case when sStatus = 2 then intTime end) as OUTIME
from (select t.*,
row_number () over ( order by inttime) as seq1,
row_number () over (partition by empid order by inttime) as seq2
from #tempStatus t
) t
group by empid, (seq1-seq2);
Check for the similar answers - here
try:
select EmpID
, min(DateTime) INTIME(1)
, max(DateTime) OUTIME(2)
from TABLE
group by EmpID;
SQL Server 2012-2017. Can this be done with a CTE? Trying to avoid using a cursor.
I have a report request to return the inventory for the first of each month between dateFrom and dateTo, excluding the inventory on the dateFrom and dateTo.
Inventory is tracked by status history for each item. Each status history is coded as either in-inventory or out-of-inventory.
There could be many status history entries with an in-inventory status to track process steps. There will be another status history entry when the item is shipped, broken, lost, etc, and those are coded as out-of-inventory.
For reporting, an item is in inventory if the most recent status in status history before the reporting date is one that we code as in-inventory.
DECLARE #dateFrom dateTime, #dateTo dateTime
SET #dateFrom = '2-Nov-2017'
SET #dateTo = '20-Feb-2018 23:59:59.9'
--this proves out the dates are calculating correctly
;WITH cteDateTest AS
(
SELECT
1 roundCount,
DATEADD(M, DATEDIFF(M, 0, #dateFrom), 31) invDate --returns first of the month following dateFrom
UNION ALL
SELECT
roundCount + 1,
DATEADD(M, 1, invDate) --this one would go into the row_number join
FROM
cteDateTest
WHERE
DATEADD(M, 1, invDate) < #DateTo
)
SELECT * FROM cteDateTest
I've simplified the tables, using temp tables to be explicit that these are NOT the issue but created for ease in others understanding the problem.
CREATE TABLE #tempItems
(
id INT PRIMARY KEY,
itemDesc NVARCHAR (15) NULL,
isActive BIT
)
INSERT INTO #tempItems (id, itemDesc, isActive)
SELECT 1, 'widget 1',1 UNION ALL
SELECT 2, 'toy 2',1 UNION ALL
SELECT 3, 'something 3',1 UNION ALL
SELECT 4, 'prize 4',1
CREATE TABLE #tempStatusHistory
(
historyID INT PRIMARY KEY,
itemId INT,
itemStatus NVARCHAR (25) NULL,
statusDate DATETIME,
statusIsInInventory BIT,
)
INSERT INTO #tempStatusHistory (historyID, itemId, itemStatus, statusDate, statusIsInInventory)
SELECT 1, 1, 'in receiving', '2017-10-10',1 UNION ALL
SELECT 2, 1, 'in test', '2017-10-11',1 UNION ALL
SELECT 3, 1, 'on shelves', '2017-10-31',1 UNION ALL
SELECT 4, 2, 'in receiving', '2017-11-15',1 UNION ALL
SELECT 5, 2, 'in test', '2017-11-16',1 UNION ALL
SELECT 6, 2, 'on shelves', '2017-12-17',1 UNION ALL
SELECT 7, 2, 'sold', '2017-12-24',0 UNION ALL
SELECT 8, 3, 'in test', '2017-11-18',1 UNION ALL
SELECT 9, 3, 'in repair', '2017-12-19',1 UNION
SELECT 10, 3, 'returned to vendor', '2018-02-03',0 UNION ALL
SELECT 11, 4, 'in receiving', '2018-01-20',1 UNION ALL
SELECT 12, 4, 'on shelves', '2018-01-21',1 UNION ALL
SELECT 13, 4, 'sold', '2018-03-20',0
--select * from #tempStatusHistory
/* Per above data:
widget 1 in inventory all these months. Toy 2 in Dec 1 inventory. something 3 in Dec1, Jan 1, Feb 1 inventory, prize 4 in Feb 1 and Mar 1 inventory
Dec 1 inventory = 3 (widget 1, toy 2, something 3)
Jan 1 inventory = 2 (widget 1, something 3)
Feb 1 inventory = 3 (widget 1, something 3, prize 4)
Mar 1 inventory = 2 (widget 1, prize 4)
*/
--Our normal way of getting inventory for #dateFrom
SELECT
SH.historyId historyId, I.itemDesc
FROM
#tempItems I
JOIN
(SELECT
ROW_NUMBER () OVER (PARTITION BY itemId ORDER BY statusDate DESC) AS [Index],
itemId, historyId, statusDate, statusIsInInventory
FROM
#tempStatusHistory
WHERE
statusDate < #dateFrom) SH ON I.id = SH.itemId AND SH.[Index] = 1
WHERE
SH.statusIsInInventory = 1
--trying to pull inventory for each month between #dateFrom and #dateTo (exclusive of the end dates)
--anchor part of cte
;WITH cteInv AS
(
SELECT
1 roundCount,
DATEADD(M, DATEDIFF(M, 0, #dateFrom), 31) invDate,
DATEADD(M, 1, #dateFrom) staticDate,
1 linkField,
SH.historyId historyId,
I.itemDesc
FROM
#tempItems I
JOIN
(SELECT
ROW_NUMBER () OVER (PARTITION BY itemId ORDER BY statusDate DESC) AS [Index],
itemId, historyId, statusDate, statusIsInInventory
FROM
#tempStatusHistory
WHERE
statusDate < DATEADD(M, DATEDIFF(M, 0, #dateFrom), 31)) SH ON I.id = SH.itemId AND SH.[Index] = 1
WHERE
SH.statusIsInInventory = 1
--recursive part
UNION ALL
SELECT
roundCount + 1
, DATEADD(M,1,invDate)
, DATEADD(M,1,#dateFrom) staticDate
, 1
, SH.historyId
, I.itemDesc
FROM #tempItems I
--invDate not happy below
JOIN (SELECT ROW_NUMBER () OVER (PARTITION BY itemId ORDER BY statusDate DESC) AS [Index], itemId, historyId, statusDate, statusIsInInventory
FROM #tempStatusHistory WHERE statusDate < DATEADD(M,1,invDate)) SH ON I.id = SH.itemId AND SH.[Index] = 1
JOIN cteInv C ON I.isActive = C.linkField
WHERE DATEADD(M,1,invDate)< #dateTo AND SH.statusIsInInventory = 1
)
SELECT * from cteInv order by roundCount, invDate, itemDesc
drop table #tempItems
drop table #tempStatusHistory
the reference to invDate in the status history link shows as an error "invalid column name invDate". I can't figure a way around this. I also suspect an issue because if I replace invDate with #dateFrom in the same spot, I had expected the same inventory result for each month calculation, but it started multiplying itself.
Is cte a good solution for this? Is there a better way?
Thanks for anyone helping me on my first post here.
Addition: Expected output would be:
roundCount invDate linkField historyId itemDesc
-----------------------------------------------------------
1 2017-12-01 1 8 something 3
1 2017-12-01 1 5 toy 2
1 2017-12-01 1 3 widget 1
2 2018-01-01 1 9 something 3
2 2018-01-01 1 5 toy 2
3 2018-02-01 1 12 prize 4
3 2018-02-01 1 9 something 3
3 2018-02-01 1 3 widget 1
You are actually very very closed. Just need one OUTER APPLY
-- this is your cteDateTest query
;WITH
cteDateTest AS
(
SELECT
1 roundCount
,DATEADD(M,DATEDIFF(M,0,#dateFrom),31) invDate --returns first of the month following dateFrom
UNION ALL
SELECT
roundCount + 1
,DATEADD(M,1,invDate) --this one would go into the row_number join
FROM cteDateTest
WHERE DATEADD(M,1,invDate)< #DateTo
)
SELECT *
from cteDateTest d
OUTER APPLY
(
-- this is your normal query of getting inventory for #dateFrom
SELECT SH.historyID
, I.itemDesc
FROM #tempItems I
INNER JOIN
(
SELECT ROW_NUMBER () OVER (PARTITION BY itemId ORDER BY statusDate DESC) AS [Index],
itemId, historyID, statusDate, statusIsInInventory
FROM #tempStatusHistory
WHERE statusDate < d.invDate -- change to invDate from cteDateTest
) SH ON I.id = SH.itemId
AND SH.[Index] = 1
WHERE SH.statusIsInInventory = 1
) h
Using the table below (call it TableA), I need to create an SQL statement that selects two sets of data and combines them together. First, I need to select those rows where Status = 1 and the DateCreated is greater (meaning newer) than a specified date, that I'll call the StartDate. I also need to select all those rows where Status = 0 and the DateCreated is also greater than specified date BUT where the results are sorted by DateCreated descendingly AND the number of these records is limited to 2.
So if my table data looks like this:
ID Status DateCreated
1 1 2013-05-01 14:00
2 1 2013-05-01 15:00
3 1 2013-05-01 16:00
4 0 2013-05-01 17:00
5 0 2013-05-01 18:00
6 0 2013-05-01 19:00
7 0 2013-05-01 20:00
and I set the #startDate to 2013-05-01 14:30, I want the result set to look like this:
2 1 2013-05-01 15:00
3 1 2013-05-01 16:00
6 0 2013-05-01 19:00
7 0 2013-05-01 20:00
Is this best done with a Union that joins two results or is there a better more efficient way?
You should benchmark with your real data set for performance differences, but just to give you an alternative you can write it using ROW_NUMBER() instead;
SELECT id, status, datecreated FROM (
SELECT id, status, datecreated,
ROW_NUMBER() OVER (PARTITION BY status ORDER BY DateCreated DESC) rn
FROM Table1 WHERE DateCreated > '2013-05-01 14:30'
) a
WHERE status = 1 OR rn < 3
ORDER BY DateCreated;
An SQLfiddle to test with.
No need for UNION - just a WHERE clause translation of your requirements:
declare #t table (ID int not null,Status int not null,DateCreated datetime not null)
insert into #t(ID,Status,DateCreated) values
(1,1,'2013-05-01T14:00:00'),
(2,1,'2013-05-01T15:00:00'),
(3,1,'2013-05-01T16:00:00'),
(4,0,'2013-05-01T17:00:00'),
(5,0,'2013-05-01T18:00:00'),
(6,0,'2013-05-01T19:00:00'),
(7,0,'2013-05-01T20:00:00')
declare #startDate datetime
set #startDate ='2013-05-01T14:30:00'
;With Numbered as (
select *,ROW_NUMBER() OVER (PARTITION BY Status ORDER BY DateCreated desc) as rn
from #t
)
select * from Numbered
where
DateCreated > #startDate and
(
Status = 1 or
Status = 0 and rn <= 2
)
Admittedly, you only need the row numbers for Status 0, but there shouldn't be any harm in running it across all rows.
Try this one -
Query:
DECLARE #temp TABLE
(
ID INT
, [Status] INT
, DateCreated DATETIME
)
INSERT INTO #temp(ID, [Status], DateCreated)
VALUES
(1, 1, '20130501 14:00:00'),
(2, 1, '20130501 15:00:00'),
(3, 1, '20130501 16:00:00'),
(4, 0, '20130501 17:00:00'),
(5, 0, '20130501 18:00:00'),
(6, 0, '20130501 19:00:00'),
(7, 0, '20130501 20:00:00')
DECLARE #startDate DATETIME = '20130501 14:30:00'
SELECT
ID
, [Status]
, DateCreated
FROM (
SELECT
ID
, [Status]
, DateCreated
, ROW_NUMBER() OVER (PARTITION BY [Status] ORDER BY DateCreated DESC) AS rn
FROM #temp
) t
WHERE DateCreated > #startDate
AND (
[Status] % 1 = 1
OR
rn < 3
)
ORDER BY t.DateCreated
Output:
ID Status DateCreated
----------- ----------- -----------------------
2 1 2013-05-01 15:00:00.000
3 1 2013-05-01 16:00:00.000
6 0 2013-05-01 19:00:00.000
7 0 2013-05-01 20:00:00.000
I need some T-SQL that will show missing records.
Here is some sample data:
Emp 1
01/01/2010
02/01/2010
04/01/2010
06/01/2010
Emp 2
02/01/2010
04/01/2010
05/01/2010
etc...
I need to know
Emp 1 is missing
03/01/2010
05/01/2010
Emp 2 is missing
01/01/2010
03/01/2010
06/01/2010
The range to check will start with todays date and go back 6 months.
In this example, lets say today's date is 06/12/2010 so the range is going to be 01/01/2010 thru 06/01/2010.
The day is always going to be the 1st in the data.
Thanks a bunch. :)
Gerhard Weiss
Secretary of Great Lakes Area .NET Users Group
GANG Upcoming Meetings | GANG LinkedIn Group
Try This:
DECLARE #Employees table (DateOf datetime, EmployeeID int)
INSERT #Employees VALUES ('01/01/2010',1)
INSERT #Employees VALUES ('02/01/2010',1)
INSERT #Employees VALUES ('04/01/2010',1)
INSERT #Employees VALUES ('06/01/2010',1)
INSERT #Employees VALUES ('02/01/2010',2)
INSERT #Employees VALUES ('04/01/2010',2)
INSERT #Employees VALUES ('05/01/2010',2)
--I was unsure of the data in the question
--this gives first day of each month for last six months
DECLARE #StartDate datetime
,#EndDate datetime
SELECT #StartDate=DATEADD(month,-6,DATEADD(month,DATEDIFF(month,0,GETDATE()),0) )
,#EndDate=GETDATE()
;with AllDates AS
(
SELECT #StartDate AS DateOf
UNION ALL
SELECT DateAdd(month,1,DateOf)
FROM AllDates
WHERE DateOf<#EndDate
)
SELECT
dt.DateOf,dt.EmployeeID
FROM (SELECT DISTINCT
a.DateOf,e.EmployeeID
FROM AllDates a
CROSS JOIN (SELECT DISTINCT EmployeeID FROM #Employees) e
) dt
LEFT OUTER JOIN #Employees ee ON dt.EmployeeID=ee.EmployeeID AND dt.DateOf=ee.DateOf
WHERE ee.EmployeeID IS NULL
ORDER BY dt.EmployeeID,dt.DateOf
OUTPUT:
DateOf EmployeeID
----------------------- -----------
2009-10-01 00:00:00.000 1
2009-11-01 00:00:00.000 1
2009-12-01 00:00:00.000 1
2010-03-01 00:00:00.000 1
2010-05-01 00:00:00.000 1
2009-10-01 00:00:00.000 2
2009-11-01 00:00:00.000 2
2009-12-01 00:00:00.000 2
2010-01-01 00:00:00.000 2
2010-03-01 00:00:00.000 2
(10 row(s) affected)
this will do every day for last six months, just incorporate this in the above if that is what you want:
DECLARE #StartDate datetime
,#EndDate datetime
SELECT #StartDate=DATEADD(month,-6,GETDATE())
,#EndDate=GETDATE()
;with AllDates AS
(
SELECT #StartDate AS DateOf
UNION ALL
SELECT DateOf+1
FROM AllDates
WHERE DateOf<#EndDate
)
SELECT * FROM AllDates
--OPTION (MAXRECURSION 500) --uncomment and increase if the date range needs more rows
fill a temp table with the date ranges and outer join the temp table to your Emp* table and only return records from your temp table that have null in the corresponding row of the Emp* table
If you're only going back a fixed # of months, you can precalc those "first of month" dates and left join to your employee data:
SELECT d.DT, CASE WHEN e.DT IS NULL THEN 1 ELSE 0 END AS IsMissing
FROM (
SELECT DATEADD(m, DATEDIFF(m, 0, CURRENT_TIMESTAMP), 0) AS DT
UNION
SELECT DATEADD(m, DATEDIFF(m, 0, CURRENT_TIMESTAMP) - 1, 0)
UNION
SELECT DATEADD(m, DATEDIFF(m, 0, CURRENT_TIMESTAMP) - 2, 0)
UNION
SELECT DATEADD(m, DATEDIFF(m, 0, CURRENT_TIMESTAMP) - 3, 0)
UNION
SELECT DATEADD(m, DATEDIFF(m, 0, CURRENT_TIMESTAMP) - 4, 0)
UNION
SELECT DATEADD(m, DATEDIFF(m, 0, CURRENT_TIMESTAMP) - 5, 0)
) AS d
LEFT JOIN EmployeeDates e ON d.DT = e.DT AND e.EmpID = 1