I tried working with the results i found on here using the pivot answers but i'm not getting it to work. I am trying to join the columns in one table to the rows in another table by date.
I have the following table structure/results.
Holidays table
Date | SusanCalladine | ClaireWillis | FazailaPirbhai
2016-08-22 | 0 | 0 | 1
2016-08-23 | 0 | 1 | 1
2016-08-24 | 0 | 1 | 1
2016-08-25 | 0 | 1 | 1
2016-08-26 | 0 | 0 | 1
Which i am trying to join on date and row to the following (each date has 3 people in seperate rows)
Telephony Table
CallDate | AgentName | InboundCallsAnswered | InboundHandleTime
2016-08-22 | Claire Willis | 0 | 0
2016-08-22 | Fazaila Pirbhai | 36 | 17484
2016-08-22 | Susan Calladine | 0 | 0
2016-08-23 | Claire Willis | 12 | 4250
2016-08-23 | Fazaila Pirbhai | 16 | 23360
2016-08-23 | Susan Calladine | 0 | 0
any help would be much appreciated, thanks in advance
I hope this is what you want. if not do let me know
CREATE TABLE ##Holidaystable
([Date] DATE, SusanCalladine INT, ClaireWillis INT, FazailaPirbhai INT);
INSERT INTO ##Holidaystable VALUES
('2016-08-22', 0, 0, 1),
('2016-08-23', 0, 1, 1),
('2016-08-24', 0, 1, 1),
('2016-08-25', 0, 1, 1),
('2016-08-26', 0, 0, 1)
CREATE TABLE ##TelephonyTable
([CallDate] DATE, AgentName VARCHAR(50), InboundCallsAnswered INT, InboundHandleTime INT);
INSERT INTO ##TelephonyTable VALUES
('2016-08-22' , 'Claire Willis' , 0 , 0),
('2016-08-22' , 'Fazaila Pirbhai' , 36 , 17484),
('2016-08-22' , 'Susan Calladine' , 0 , 0),
('2016-08-23' , 'Claire Willis' , 12 , 4250),
('2016-08-23' , 'Fazaila Pirbhai' , 16 , 23360),
('2016-08-23' , 'Susan Calladine' , 0 , 0)
----Use a CTE for the query as below
;WITH Holiday AS
(SELECT
H.[Date],
T.CallDate
--,T.*
FROM ##Holidaystable H
INNER JOIN ##TelephonyTable T
ON H.[Date]=T.CallDate
)
SELECT * FROM Holiday
PIVOT
(
COUNT([Date]) FOR CallDate IN ([2016-08-22],[2016-08-23])
) AS PV1
You can use UNPIVOT to make rows from columns in Holiday table and join the result with Telephony by Date and AgentName columns.
-- CREATE Holiday Table
CREATE TABLE Holiday
(
Date DATE NOT NULL ,
[Susan Calladine] INT NULL ,
[Claire Willis] INT NULL ,
[Fazaila Pirbhai] INT NULL
);
-- CREATE Telephony Table
CREATE TABLE Telephony
(
CallDate DATE NOT NULL ,
AgentName NVARCHAR(100) NOT NULL ,
InboundCallsAnswered INT NULL ,
InboundHandleTime INT NULL
);
-- Insert rows in Holiday
INSERT INTO Holiday
VALUES ( '2016-08-22', 0, 0, 1 ),
( '2016-08-23', 0, 1, 1 ),
( '2016-08-24', 0, 1, 1 ),
( '2016-08-25', 0, 1, 1 ),
( '2016-08-26', 0, 0, 1 );
-- Insert rows in Telephony
INSERT INTO Telephony
VALUES ( '2016-08-22', 'Claire Willis', 0, 0 ),
( '2016-08-22', 'Fazaila Pirbhai', 36, 17484 ),
( '2016-08-22', 'Susan Calladine', 0, 0 ),
( '2016-08-23', 'Claire Willis', 12, 4250 ),
( '2016-08-23', 'Fazaila Pirbhai', 16, 23360 ),
( '2016-08-23', 'Susan Calladine', 0, 0 );
-- Use UNPIVOT
WITH Hol
AS ( SELECT Date ,
AgentName ,
Calls
FROM ( SELECT *
FROM Holiday
) p UNPIVOT ( Calls FOR AgentName IN ( [Susan Calladine],
[Claire Willis],
[Fazaila Pirbhai] ) ) AS unpvt
)
SELECT Date ,
Hol.AgentName ,
Calls ,
InboundCallsAnswered ,
InboundHandleTime
FROM Hol
LEFT JOIN Telephony t ON Hol.Date = t.CallDate
AND Hol.AgentName = t.AgentName
ORDER BY Date ,
AgentName;
The result will be :
Related
I have a table with three columns, which can contain duplicate rows
org - int NULL
id - int NULL
complete - bit NULL
So I might have data like so:
org | id | complete
-------------------
1 | 1 | 1
1 | 2 | NULL
1 | 2 | 1
1 | 3 | 1
2 | 3 | 1
2 | 4 | 1
2 | 4 | NULL
I want to get a count of all distinct id by org. That's easy enough to do with a COUNT(DISTINCT id) expression. Where I'm running into trouble now is I also want a count of all distinct id where any of the complete values isn't 1.
So from the above I'd want this output:
org | distinct id | distinct incomplete id
------------------------------------------
1 | 3 | 1
2 | 2 | 1
So for org 2, because id of 4 included a NULL value, then I can't count id 4 as fully complete, thus just id 3 is complete, thus resulting in a 1 in the distinct incomplete id column. So I don't know how to fill in the ???? part of the below query.
SELECT org, COUNT(DISTINCT id) TotalPeople, ???? IncompletePeople
FROM table
GROUP BY org
Try the following approach
DECLARE #T TABLE
(
Org INT,
Id INT,
Complete BIT
)
INSERT INTO #T
VALUES(1,1,1),(1,2,NULL),(1,2,1),(1,3,1),(2,3,1),(2,4,1),(2,4,NULL)
SELECT
Org,
DistinctId = COUNT(DISTINCT Id),
DistinctIncompleteId = SUM(CASE Complete WHEN 1 THEN 0 ELSE 1 END)
FROM #T
GROUP BY Org
You may try this way
create table #temptable ( org int, id int, comp int )
Go
insert into #temptable ( org, id, comp )
values ( 1,1,1)
,( 1, 2, null)
,( 1, 2, 1)
,( 1, 3, 1)
,( 2, 3, 1)
,( 2, 4, null)
,( 2, 4, 1)
select d.org, d.DistinctId, f.incompleteId from (
select COUNT (distinct id) as DistinctId , org from #temptable group by org) as d full outer join (
select COUNT (distinct id) as incompleteId , org from #temptable where comp is null group by org) as f on d.org=f.org
go
drop table #temptable
Group it by "org" and by "complete". Then put HAVING complete=1. Hope the code below helps you:
SELECT org, COUNT(id) TotalPeople, complete
FROM table
GROUP BY org,complete
HAVING complete=1 (complete IS NULL *for incomplete*)
I'm new to SQL Server pivot, and i'm trying to solve a problem where i need to output the following tables into one table that includes the values based on one table's columns
Here's my tables
ContactGroup
Title ID
---------- -----------
Group A 1
ContactsInGroups
ContactId GroupId
----------- -----------
1 1
2 1
3 1
ContactVariables
ID Name GroupId Order
----------- ---------- ----------- ------
1 Invoice 1 1
2 Due Date 1 1
ContactsVariablesValues
ContactVariableId ContactId Value
----------------- ----------- -----
1 1 600
Desired output
GroupId ContactId Invoice Due Date
----------- ----------- ----------- -----------
1 1 600 NULL
1 2 NULL NULL
1 3 NULL NULL
Ali, here is an example that will at least get you started. You can run the following in SSMS.
Create some table variables and insert your sample data.
DECLARE #ContactGroup TABLE ( id INT, title VARCHAR(50) );
INSERT INTO #ContactGroup ( id, title ) VALUES ( 1, 'Group A' );
DECLARE #ContactsInGroup TABLE ( ContactID INT, GroupID INT );
INSERT INTO #ContactsInGroup ( ContactID, GroupID ) VALUES ( 1, 1 ), ( 2, 1 ), ( 3, 1 );
DECLARE #ContactVariables TABLE ( id INT, [name] VARCHAR(50), GroupID INT, [Order] INT );
INSERT INTO #ContactVariables ( id, [name], GroupID, [Order] ) VALUES ( 1, 'Invoice', 1, 1 ), ( 2, 'Due Date', 1, 1 );
DECLARE #ContactsVariablesValues TABLE ( ContactVariableID INT, ContactID INT, [value] INT );
INSERT INTO #ContactsVariablesValues ( ContactVariableID, ContactID, [value] ) VALUES ( 1, 1, 600 );
Then query the data as follows:
SELECT
ContactGroup.id AS GroupID
, ContactsInGroup.ContactID
, ContactVars.Invoice
, ContactVars.[Due Date]
FROM #ContactGroup AS ContactGroup
INNER JOIN #ContactsInGroup AS ContactsInGroup
ON ContactGroup.id = ContactsInGroup.GroupID
OUTER APPLY (
SELECT
[Invoice], [Due Date]
FROM (
SELECT
Vars.[name]
, Vals.[value]
FROM #ContactVariables AS Vars
LEFT OUTER JOIN #ContactsVariablesValues Vals
ON Vars.id = Vals.ContactVariableID
WHERE
Vars.GroupID = 1
AND Vals.ContactID = ContactsInGroup.ContactID
) AS ContactData
PIVOT (
MIN( [value] )
FOR [name] IN (
[Invoice], [Due Date]
)
) AS pvt
) AS ContactVars
ORDER BY
ContactGroup.id, ContactsInGroup.ContactID;
Which returns:
+---------+-----------+---------+----------+
| GroupID | ContactID | Invoice | Due Date |
+---------+-----------+---------+----------+
| 1 | 1 | 600 | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
+---------+-----------+---------+----------+
Things to note
The "magic" here is in the OUTER APPLY. This allows us to query a subset of data based on the primary data returned, in this case the GroupID and ContactID. OUTER APPLY will also return rows with NULL values like you desire.
You're going to have some challenges here, namely that to use a PIVOT as shown in my example, you will need to know all the values ( Invoice, Due Date, etc... ) that will become column headers. Based on your setup, I'm thinking this may not be the case, so you will be forced to resort to an technique that creates and executes a dynamic PIVOT statement for you within the OUTER APPLY.
You also might consider using a TABLE VALUED FUNCTION that does the PIVOT work that can then be JOINed on vs. an OUTER APPLY.
You have several options, but hopefully this helps jumpstart your thinking.
Since FUNCCODE is shared between POSCODE and DEVCODE I can't call out both at the same time to eliminate the null values to insert the data into a separate table called JOINT. POSCODE and DEVCODE are FKs. I know there has to be a much easier way of doing this. I spent the last 2 weeks trying to craft a solution... It feels like I don't understand one thing to make this work. Any advice is appreciated.
Table setup
FUNCCODE | POSCODE | DEVCODE
11 1 NULL
12 NULL 1
13 2 NULL
14 NULL 2
The table needs to be rearranged and then inserted into a separate table called JOINT which is setup as:
POSCODE | POSFUNCCODE |DEVCODE | DEVFUNCCODE
1 11 1 12
2 13 2 14
Some of my attempts XD
Each join creates only 2 of the columns I need
SELECT
dbo.POSITION.POSCODE AS POSCODE,
dbo.FUNC.FUNCCODE AS POSFUNCCODE
FROM FUNC
INNER JOIN POSITION ON dbo.POSITION.POSCODE = dbo.FUNC.POSCODE
UNION ALL
SELECT
dbo.DEVICE.DEVCODE AS DEVCODE,
dbo.FUNC.FUNCCODE AS DEVFUNCCODE
FROM FUNC
INNER JOIN DEVICE ON dbo.DEVICE.DEVCODE = dbo.FUNC.DEVCODE
ORDER BY 1;
Only inserts the last row values
DECLARE #DATE DATETIME = GETDATE()
DECLARE #PC INT;
SELECT #PC = POSCODE
FROM func
WHERE poscode != 0
ORDER BY 1;
DECLARE #FCP INT;
SELECT #FCP = FUNCCODE
FROM FUNC
WHERE POSCODE != 0
ORDER BY 1;
DECLARE #DC INT;
SELECT #DC = devcode
FROM func
WHERE devcode != 0
ORDER BY 1;
DECLARE #FCD INT
SELECT #FCD = FUNCCODE
FROM FUNC
WHERE DEVCODE != 0
ORDER BY 1
INSERT INTO JOINT (POSCODE, POSFUNCCODE, DEVCODE, DEVFUNCCODE, JOINTTIME,
JOINTSTATUS)
VALUES (#PC, #FCP, #DC, #FCD, #DATE, 1)
If my understanding of your problem is correct, I think the below query would be a solution.
INSERT INTO JOINT (POSTCODE, DEVCODE, POSFUNCCODE, DEVFUNCCODE)
SELECT
POSTCODE,
DEVCODE,
MAX(CASE
WHEN POSCODE IS NOT NULL THEN FUNCCODE
ELSE NULL
END) POSFUNCCODE,
MAX(CASE
WHEN DEVCODE IS NOT NULL THEN FUNCCODE
ELSE NULL
END) DEVFUNCCODE
FROM FUNC
GROUP BY POSTCODE,DEVCODE
Second version after a better understanding
INSERT INTO JOINT (POSTCODE, DEVCODE, POSFUNCCODE, DEVFUNCCODE)
SELECT
t1.POSTCODE,
t2.DEVCODE,
t1.POSFUNCCODE,
t2.DEVFUNCCODE
(SELECT
POSTCODE,
MAX(CASE
WHEN POSCODE IS NOT NULL THEN FUNCCODE
ELSE NULL
END) POSFUNCCODE
FROM FUNC
GROUP BY POSTCODE) t1
INNER JOIN
(SELECT
DEVCODE,
MAX(CASE
WHEN DEVCODE IS NOT NULL THEN FUNCCODE
ELSE NULL
END) DEVFUNCCODE
FROM FUNC
GROUP BY DEVCODE) t2
ON t1.POSTCODE = t2.DEVCODE
Against my better judgment, I created a loop which inserted the proper values.... I know this is not the correct way to approach this, please excuse me since my experience in SQL is very little. But this corrects the interface issue in the client program. Shout out to #user4219031 for guidance!
DECLARE #DATE DATETIME = GETDATE()
DECLARE #PC INT = 0;
DECLARE #FCP INT = 12;
DECLARE #DC INT = 0;
DECLARE #FCD INT = 13
WHILE ( #PC < 739 )
BEGIN
INSERT INTO JOINT (POSCODE, POSFUNCCODE, DEVCODE, DEVFUNCCODE, JOINTTIME, JOINTSTATUS)
VALUES( #PC, #FCP, #DC, #FCD, #DATE, 1)
SET #PC = #PC + 1
SET #FCP = #FCP +2
SET #DC = #DC + 1
SET #FCD = #FCD + 2
END
EDIT: I changed my query to account for NULL POSCODE or DEVCODE.
SQL Fiddle
MS SQL Server 2017 Schema Setup:
CREATE TABLE t ( FUNCCODE int, POSCODE int, DEVCODE int ) ;
INSERT INTO t (FUNCCODE, POSCODE, DEVCODE)
VALUES
( 11, 1, NULL )
, ( 12, NULL, 1 )
, ( 13, 2, NULL )
, ( 14, NULL, 2 )
, ( 42, NULL, 1 )
, ( 77, NULL, 7 )
, ( 88, NULL, 8 )
, ( 99, 9, NULL )
;
Create New Table And Insert Records
CREATE TABLE ti ( POSCODE int, pos_FUNCCODE int, DEVCODE int, dev_FUNCCODE int ) ;
INSERT INTO ti ( POSCODE, pos_FUNCCODE, DEVCODE, dev_FUNCCODE)
SELECT t1.POSCODE
, t1.FUNCCODE AS pos_FUNCODE
, t2.DEVCODE
, t2.FUNCCODE AS dev_FUNCCODE
FROM t t1
FULL OUTER JOIN t t2 ON t1.POSCODE = t2.DEVCODE
WHERE t1.POSCODE IS NOT NULL OR t2.DEVCODE IS NOT NULL
;
What's In The New Table?:
SELECT * FROM ti
Results:
| POSCODE | pos_FUNCCODE | DEVCODE | dev_FUNCCODE |
|---------|--------------|---------|--------------|
| 1 | 11 | 1 | 12 |
| 1 | 11 | 1 | 42 |
| 2 | 13 | 2 | 14 |
| 9 | 99 | (null) | (null) |
| (null) | (null) | 7 | 77 |
| (null) | (null) | 8 | 88 |
==========ORIGINAL==========
SQL Fiddle
MS SQL Server 2017 Schema Setup:
CREATE TABLE t ( FUNCCODE int, POSCODE int, DEVCODE int ) ;
INSERT INTO t (FUNCCODE, POSCODE, DEVCODE)
VALUES
( 11, 1, NULL )
, ( 12, NULL, 1 )
, ( 13, 2, NULL )
, ( 14, NULL, 2 )
;
Create New Table And Insert Records
CREATE TABLE ti ( POSCODE int, pos_FUNCCODE int, DEVCODE int, dev_FUNCCODE int ) ;
INSERT INTO ti ( POSCODE, pos_FUNCCODE, DEVCODE, dev_FUNCCODE)
SELECT t1.POSCODE
, t1.FUNCCODE AS pos_FUNCODE
, t2.DEVCODE
, t2.FUNCCODE AS dev_FUNCCODE
FROM t t1
INNER JOIN t t2 ON t1.POSCODE = t2.DEVCODE
WHERE t1.POSCODE IS NOT NULL
;
What's In The New Table?:
SELECT * FROM ti
Results:
| POSCODE | pos_FUNCCODE | DEVCODE | dev_FUNCCODE |
|---------|--------------|---------|--------------|
| 1 | 11 | 1 | 12 |
| 2 | 13 | 2 | 14 |
I have a table that shows the entry and exit of items into the warehouse. The Camera 1 and Camera 2 document the entry time and exit time respectively of that item. The cameras then classify the item as it enters and leaves the checkpoint with the help of lasers. Eg: Big box: Class 5, Medium Box: Class 3, Small Box: Class 2.
Sometimes, the cameras classification doesn't match each other. Eg: Classification at entry can be Medium box and on exit can be Small box.
I need to find the number of transactions where the class didn't match for the same TransactionDetail and then a percentage of those class mismatches against all the transaction for a certain time range.
My table looks somewhat like this:
---------------------------------------------------------------------------
| AVDetailID | TransDetailID | AVClassID | CamID | CreatedDate |
---------------------------------------------------------------------------
| 20101522 | 54125478 | 5 | 1 | 2017-05-08 10:15:01:560|
| 20101523 | 54125478 | 5 | 2 | 2017-05-08 10:15:01:620|
| 20101524 | 54125479 | 3 | 1 | 2017-05-08 10:15:03:120|
| 20101525 | 54125479 | 2 | 2 | 2017-05-08 10:15:03:860|
| 20101526 | 54125480 | 4 | 1 | 2017-05-08 10:15:06:330|
| 20101527 | 54125480 | 4 | 2 | 2017-05-08 10:15:06:850|
---------------------------------------------------------------------------
So, in the above case the class changes from 3 to 2 in record 3 and 4. That is one transaction where the class changed. I need to get a percentage of all transactions that where the class changed between each cameras.
The code I've used so far is below. I just need to find a way to get a percentage of the total Transactions.
DECLARE #MinDate DATE = '20170406',
#MaxDate DATE = '20170407';
SELECT COUNT(tdBefore.TransDetailId) TD
--,SUM((COUNT(*) OVER() / allRecords.Count) * 100) AS DiffPercent
FROM AVTransDetail AS tdBefore
INNER JOIN AVTransDetail AS tdAfter
ON tdBefore.TransDetailID = tdAfter.TransDetailID
AND tdBefore.ACClassID = 1
AND tdAfter.ACClassID = 2
CROSS APPLY
(
SELECT COUNT(*) AS [Count]
FROM AVTransDetail
WHERE tdBefore.DateCreated >= #MinDate
AND tdAfter.DateCreated <= #MaxDate
) AS allRecords
WHERE tdBefore.AVCClassId <> tdAfter.AVCClassId
AND tdBefore.DateCreated >= #MinDate
AND tdAfter.DateCreated <= #MaxDate
How do I create a column for percentage of total transactions?
This worked with your sample data.
DECLARE #MinDate DATETIME = '5/8/2017 12:00AM';
DECLARE #MaxDate DATETIME = '5/8/2017 11:59PM';
WITH cam1 AS (
SELECT TransDetailID,AVClassID
FROM AVTransDetail
WHERE CreatedDate BETWEEN #MinDate AND #MaxDate
AND
CamID = 1),
cam2 AS (
SELECT TransDetailID,AVClassID
FROM AVTransDetail
WHERE CreatedDate BETWEEN #MinDate AND #MaxDate
AND
CamID = 2)
SELECT COUNT(*)'Total',SUM(CASE WHEN c1.AVClassID = c2.AVClassID THEN 0 ELSE 1 END)'NonMatch',
SUM(CASE WHEN c1.AVClassID = c2.AVClassID THEN 0 ELSE 1 END) * 100.00/COUNT(*)'Percentage'
FROM cam1 c1
JOIN cam2 c2 ON c1.TransDetailID=c2.TransDetailID
Try the below SQL script.
First we LAG to find the differences. Then, we get each transaction and whether there is a difference. And finally, we get the percentage.
DECLARE #MinDate DATE = '2017/04/06',
#MaxDate DATE = '2017/05/09';
SELECT count(*) AS TotalTransactions
,sum(Change) AS TransactionsWithChange
,(cast(sum(Change) AS FLOAT) / cast(count(*) AS FLOAT)) AS ChangePercent
FROM (
SELECT TransDetailID
,MAX(classChange) AS Change
FROM (
SELECT *
,LAG(AVClassID, 1, AVClassID) OVER (
PARTITION BY TransDetailID ORDER BY AVDetailID
) AS PrevClassId
,CASE
WHEN LAG(AVClassID, 1, AVClassID) OVER (
PARTITION BY TransDetailID ORDER BY AVDetailID
) != AVClassID
THEN 1
ELSE 0
END AS ClassChange
FROM AVTransDetail
where CreatedDate between #MinDate and #MaxDate
) AS CoreData
GROUP BY TransDetailID
) AS ChangeData
Hope this helps.
I added more sample rows to get better result
create table #trans (
AVDetailID int,
TransDetailID int,
AVClassID int,
CamID int,
CreatedDate datetime
)
insert into #trans values
( 20101522, 54125478, 5, 1, '2017-05-08 10:15:01:560'),
( 20101523, 54125478, 5, 2, '2017-05-08 10:15:01:620'),
( 20101524, 54125479, 3, 1, '2017-05-08 10:15:03:120'),
( 20101525, 54125479, 2, 2, '2017-05-08 10:15:03:860'),
( 20101526, 54125480, 4, 1, '2017-05-08 10:15:06:330'),
( 20101527, 54125480, 4, 2, '2017-05-08 10:15:06:850'),
( 20101528, 54125481, 4, 1, '2017-05-08 10:15:07:850'),
( 20101529, 54125481, 5, 2, '2017-05-08 10:15:09:850'),
( 20101530, 54125482, 4, 1, '2017-05-08 10:15:07:850'),
( 20101531, 54125482, 5, 3, '2017-05-08 10:15:09:850')
;with diff as (
-- select records that have different class
select CamID as Ent_CamID, count(*) diff_Count
from #trans ent
outer apply (
select top 1 AVClassID as x_AVClassID, CamID as x_CamID from #trans
where CreatedDate > ent.CreatedDate and TransDetailID = ent.TransDetailID
order by CamID, CreatedDate desc
) ext
where ent.AVClassID <> ext.x_AVClassID
group by ent.CamID, ext.x_CamID
union
select ext.x_CamID as Ext_CamID, count(*) diff_Count
from #trans ent
outer apply (
select top 1 AVClassID as x_AVClassID, CamID as x_CamID from #trans
where CreatedDate > ent.CreatedDate and TransDetailID = ent.TransDetailID
order by CamID, CreatedDate desc
) ext
where ent.AVClassID <> ext.x_AVClassID
group by ent.CamID, ext.x_CamID
)
, perc as (
select Ent_CamID as CamID, sum(diff_Count) Total_Error
, (select count(*)
from #trans where CamID = diff.Ent_CamID
group by CamID) AS Total_Capture
from diff
group by Ent_CamID
)
select CamID, Total_Error, Total_Capture, 100*(Total_Error)/Total_Capture Error_Percentage
from perc
Result:
CamID Total_Error Total_Capture Error_Percentage
1 3 5 60
2 2 4 50
3 1 1 100
I have a question about SQL Server.
Table: holidaylist
Date | weekendStatus | Holidaystatus
2015-12-01 | 0 | 0
2015-12-02 | 0 | 0
2015-12-03 | 0 | 0
2015-12-04 | 1 | 0
2015-12-05 | 1 | 0
2015-12-06 | 0 | 1
2015-12-07 | 0 | 0
2015-12-08 | 0 | 0
2015-12-09 | 0 | 1
2015-12-10 | 0 | 0
2015-12-11 | 0 | 0
2015-12-12 | 1 | 1
2015-12-13 | 1 | 0
Table: emp
empid | doj | dos
1 | 2015-12-01 | 2015-12-06
2 |2015-12-01 | 2015-12-13
3 |2015-12-03 |2015-12-13
I want get days difference from dos-doj withoutweekenstatusandholidaysstatus
and includeweekendandholidaystatus
I want output like this:
Empid | doj | dos |includeweekendandholidays | witoutincludeweekendandholidayslist
1 | 2015-12-01 |2015-12-06 | 5 | 3
2 | 2015-12-01 |2015-12-13 | 12 | 8
3 | 2015-12-03 |2015-12-13 | 10 | 6
I tried this query:
select
a.empid, a.doj, a.dos,
case
when b.weekendstatus = 1 and c.Holidaystatus = 1
then datediff(day, c.date, b.date)
end as includeweekenandholidays
case
when b.weekendstatus != 1 or c.Holidaystatus = 1
then datediff(day, c.date, b.date)
end as witoutincludeweekendandholidayslist
from
emp a
left join
holidaylist b on a.doj = b.date
left join
holidaylist c on a.dos = c.date
Above query not given expected result please tell me how to write query to achieve this task in SQL Server
Try this :
select a.empid,
a.doj,a.dos,
IncludeRest = (select count(h.date) from holidaylist h where e.doj<=h.date AND e.dos>=h.date),
ExcludeRest = (select count(h.date) from holidaylist h where e.doj<=h.date AND e.dos>=h.date AND h.weekendstatus = 0 AND h.holdaystatus = 0)
from emp e
you can use a CASE in your COUNT to determine whether or not to count that day..
SELECT
e.empid,
e.doj,
e.dos,
COUNT(*) includeweekendandholidays,
COUNT(CASE WHEN Holidaystatus = 0
AND [weekendStatus] = 0 THEN 1
END) withoutincludeweekendandholidayslist
FROM
emp e
JOIN holidaylist hl ON hl.Date >= e.doj
AND hl.Date < e.dos
GROUP BY
e.empid,
e.doj,
e.dos
This might perform better since it only joins to holidaylist table on records you need..
SELECT
e.empid,
e.doj,
e.dos,
DATEDIFF(DAY, e.doj, e.dos) includeweekendandholidays,
COUNT(*) withoutincludeweekendandholidayslist
FROM
emp e
JOIN holidaylist hl ON hl.Date BETWEEN e.doj AND e.dos
WHERE
weekendStatus = 0
AND Holidaystatus = 0
GROUP BY
e.empid,
e.doj,
e.dos,
DATEDIFF(DAY, e.doj, e.dos)
I don't get your output though since it only appears that you're excluding weekends and not holidays..
You can use OUTER APPLY:
SELECT a.empid, a.doj, a.dos,
DATEDIFF(d, a.doj, a.dos) + 1 AS include,
DATEDIFF(d, a.doj, a.dos) + 1 - b.wd - b.hd + b.common AS without
FROM emp AS a
OUTER APPLY (
SELECT SUM(weekendStatus) AS wd,
SUM(Holidaystatus) AS hd,
COUNT(CASE WHEN weekendStatus = 1 AND Holidaystatus = 1 THEN 1 END) AS common
FROM holidaylist
WHERE [Date] BETWEEN a.doj AND a.dos) AS b
For each row of table emp, OUTER APPLY calculates weekendStatus=1 and Holidaystatus=1 rows that correspond to the interval of this row.
Calculated fields selected:
include is the total number of days of the emp interval including weekend days and holidays.
without is the total number of days of the emp interval minus weekend days and holidays. common field makes sure common weekend days and holidays are not subtracted twice.
Note: The above query includes start and end days of the interval in the calculations, so the interval considered is [doj - dos]. You can change the predicate of the WHERE clause in the OUTER APPLY operation so as to exclude start, end, or both, days of the interval.
Demo here
try another way with cross join
select t.empid,t.doj,t.dos,datediff(day,t.doj,t.dos) includeweekendandholidays,
datediff(day,t.doj,t.dos)-isnull(t1.wes,0) as witoutincludeweekendandholidayslist
from #emp t left join (
select empid, sum(hd.Holidaystatus+hd.weekendStatus) wes from
#emp emp cross join #holidaylist hd where hd.[Date] between doj
and dateadd(day,-1,dos) group by empid) t1 on t.empid=t1.empid
sample data
declare #holidaylist table ([Date] date, weekendStatus int, Holidaystatus int)
insert into #holidaylist([Date], weekendStatus, Holidaystatus) values
('2015-12-01' , 0 , 0),
('2015-12-02' , 0 , 0),
('2015-12-03' , 0 , 0),
('2015-12-04' , 1 , 0),
('2015-12-05' , 1 , 0),
('2015-12-06' , 0 , 1),
('2015-12-07' , 0 , 0),
('2015-12-08' , 0 , 0),
('2015-12-09' , 0 , 1),
('2015-12-10' , 0 , 0),
('2015-12-11' , 0 , 0),
('2015-12-12' , 1 , 1),
('2015-12-13' , 1 , 0)
declare #emp table(empid int, doj date, dos date)
insert into #emp (empid,doj,dos) values
(1 , '2015-12-01' , '2015-12-06'),
(2 ,'2015-12-01' , '2015-12-13'),
(3 ,'2015-12-03' ,'2015-12-13')