1

Here is my tableKnow Присутствует Отсутствует от работы Диапазон дат

Я хочу, чтобы все пользователи, которые присутствуют/отсутствуют между заданном диапазоне дат.

CREATE TABLE [tt](
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [UserId] [varchar](20) NULL, 
    [EmpCode] [varchar](50) NULL, 
    [Name] [varchar](200) NULL, 
    [WorkDate] [varchar](20) NULL, 
    [InTime] [varchar](20) NULL, 
    [OutTime] [varchar](20) NULL, 
    [TotalTime] [varchar](50) NULL, 
) 
insert into [tt] values 
    ('106','E2E106','Goutam Kumar','2017-02-21','12:54:54 PM','10:06:42 PM','08:55:00') 
,('106','E2E106','Goutam Kumar','2017-02-20','12:49:21 PM','09:26:27 PM','07:53:00') 
,('106','E2E106','Goutam Kumar','2017-02-15','12:31:51 PM','09:21:14 PM','08:30:00') 
,('106','E2E106','Goutam Kumar','2017-02-13','05:46:06 PM','09:32:17 PM','03:46:00') 
,('106','E2E106','Goutam Kumar','2017-02-14','01:02:28 PM','09:32:50 PM','07:39:00') 
,('111','E2E111','Mansi Manchanda','2017-02-21','12:42:42 PM','09:09:42 PM','08:07:00') 
,('111','E2E111','Mansi Manchanda','2017-02-17','12:09:11 PM','09:40:46 PM','06:36:00') 
,('111','E2E111','Mansi Manchanda','2017-02-16','11:56:21 AM','09:20:08 PM','08:07:00') 
,('111','E2E111','Mansi Manchanda','2017-02-15','01:07:19 PM','09:57:40 PM','08:30:00') 

CREATE TABLE tUserInfo(
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [UserId] [nvarchar](20) NULL, 
    [Name] [nvarchar](200) NULL, 
    [EmpCode] [varchar](200) NULL, 
) 
INSERT into tUserInfo VALUES 
('106','Goutam Kumar','E2E106')  
,('111','Mansi Manchanda','E2E111') 
,('112','Arvind Kumar Prajapati','E2E112') 
,('116','Rahul Garg','E2E116') 

Я могу получить настоящее или отсутствующее состояние пользователя для данной даты. Но мой вопрос здесь в том, что я хочу, чтобы все пользователи присутствовали/отсутствовали между заданным диапазоном дат.

Я хочу данных выглядеть следующим образом:

Id UserId Name   EmpCode InTime OutTime WorkDate Status 
1 106 Goutam Kumar E2E106     2017-02-13 Present 
2 111 Mansi Manchanda E2E111     2017-02-14 Absent 
3 112 Arvind Kumar E2E112     2017-02-14 Absent 
4 116 Rahul Garg  E2E116     2017-02-17 Absent 
+0

Вы должны хранить ваши даты как 'date' типов данных. – SqlZim

+0

Хотя это не касается вашей проблемы, вам следует позаботиться о нормализации. У вас есть имя сотрудника (?) Дважды в вашей базе данных, один раз в таблице 'tUserInfo' и много раз в вашей таблице' tt'. Если какие-либо имена пользователей будут изменены, вам придется пройти через все записи в 'tt' и изменить его. В противном случае - если вы не храните его здесь - вам просто нужно изменить его один раз в таблице 'tUserInfo'. –

ответ

3

rextester: http://rextester.com/LCUT68753

Показать все пользователи, и либо отсутствует, все время, или присутствует по крайней мере один раз, используя outer apply() и case выражение:

declare @fromdate date = '20170201' 
declare @thrudate date = '20170214' 

select u.* 
    , Status=case when x.WorkDate is null then 'Absent' else 'Present' end 
from tUserInfo as u 
outer apply (
    select top 1 tt.WorkDate 
    from tt 
    where tt.UserId = u.UserId 
    and tt.WorkDate >= @fromdate 
    and tt.WorkDate <= @thrudate 
    ) as x 

возвращение:

+----+--------+------------------------+---------+---------+ 
| Id | UserId |   Name   | EmpCode | Status | 
+----+--------+------------------------+---------+---------+ 
| 1 | 106 | Goutam Kumar   | E2E106 | Present | 
| 2 | 111 | Mansi Manchanda  | E2E111 | Absent | 
| 3 | 112 | Arvind Kumar Prajapati | E2E112 | Absent | 
| 4 | 116 | Rahul Garg    | E2E116 | Absent | 
+----+--------+------------------------+---------+---------+ 

Пользователи отсутствуют на весь срок, используя not exists():

select * 
from tUserInfo as u 
where not exists (
    select 1 
    from tt 
    where tt.UserId = u.UserId 
    and tt.WorkDate >= @fromdate 
    and tt.WorkDate <= @thrudate 
    ) 

возвращается:

+----+--------+------------------------+---------+ 
| Id | UserId |   Name   | EmpCode | 
+----+--------+------------------------+---------+ 
| 2 | 111 | Mansi Manchanda  | E2E111 | 
| 3 | 112 | Arvind Kumar Prajapati | E2E112 | 
| 4 | 116 | Rahul Garg    | E2E116 | 
+----+--------+------------------------+---------+ 

Все пользователи присутствуют по крайней мере один раз, используя exists():

select * 
from tUserInfo as u 
where exists (
    select 1 
    from tt 
    where tt.UserId = u.UserId 
    and tt.WorkDate >= @fromdate 
    and tt.WorkDate <= @thrudate 
    ) 

возвращается:

+----+--------+--------------+---------+ 
| Id | UserId |  Name  | EmpCode | 
+----+--------+--------------+---------+ 
| 1 | 106 | Goutam Kumar | E2E106 | 
+----+--------+--------------+---------+ 

знать, кто отсутствовал, и кто присутствовал на каждой workdate в течение диапазона дат:

select 
    u.UserId 
    , u.Name 
    , d.WorkDate 
    , [Status] = case when x.WorkDate is null then 'Absent' else 'Present' end 
from (select distinct UserId, Name from tUserInfo) as u 
    cross join (
    select distinct 
     WorkDate 
    from tt 
    where tt.WorkDate >= @fromdate 
     and tt.WorkDate <= @thrudate 
    ) as d 
outer apply (
    select top 1 tt.WorkDate 
    from tt 
    where tt.UserId = u.UserId 
    and tt.WorkDate = d.WorkDate 
    ) as x 

возвращается:

+--------+------------------------+------------+---------+ 
| UserId |   Name   | WorkDate | Status | 
+--------+------------------------+------------+---------+ 
| 106 | Goutam Kumar   | 2017-02-13 | Present | 
| 111 | Mansi Manchanda  | 2017-02-13 | Absent | 
| 112 | Arvind Kumar Prajapati | 2017-02-13 | Absent | 
| 116 | Rahul Garg    | 2017-02-13 | Absent | 
| 106 | Goutam Kumar   | 2017-02-14 | Present | 
| 111 | Mansi Manchanda  | 2017-02-14 | Absent | 
| 112 | Arvind Kumar Prajapati | 2017-02-14 | Absent | 
| 116 | Rahul Garg    | 2017-02-14 | Absent | 
+--------+------------------------+------------+---------+ 

Примечание: Это только проверки workdate st шляпа существует в таблице tt.


Если вам необходимо также проверить даты, которые не существуют в tt в пределах вашего заданного диапазона дат, вы можете использовать common table expression для создания даты для диапазона дат:

set @fromdate = '20170212' 
set @thrudate = '20170214' 

;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n)) 
, dates as (
    select top (datediff(day, @fromdate, @thrudate)+1) 
     [Date]=convert(date,dateadd(day 
     , row_number() over (order by (select 1)) -1, @fromdate)) 
    from   n as deka 
     cross join n as hecto  /* 100 days */ 
     --cross join n as kilo  /* 2.73 years */ 
     --cross join n as [tenK] /* 27.3 years */ 
    order by [Date] 
) 
select 
    u.UserId 
    , u.Name 
    , WorkDate = convert(varchar(10),d.Date,120) 
    , [Status] = case when x.WorkDate is null then 'Absent' else 'Present' end 
from (select distinct UserId, Name from tUserInfo) as u 
    cross join dates as d 
outer apply (
    select top 1 tt.WorkDate 
    from tt 
    where tt.UserId = u.UserId 
    and tt.WorkDate = d.Date 
    ) as x  

возвращается:

+--------+------------------------+------------+---------+ 
| UserId |   Name   | WorkDate | Status | 
+--------+------------------------+------------+---------+ 
| 106 | Goutam Kumar   | 2017-02-12 | Absent | 
| 111 | Mansi Manchanda  | 2017-02-12 | Absent | 
| 112 | Arvind Kumar Prajapati | 2017-02-12 | Absent | 
| 116 | Rahul Garg    | 2017-02-12 | Absent | 
| 106 | Goutam Kumar   | 2017-02-13 | Present | 
| 111 | Mansi Manchanda  | 2017-02-13 | Absent | 
| 112 | Arvind Kumar Prajapati | 2017-02-13 | Absent | 
| 116 | Rahul Garg    | 2017-02-13 | Absent | 
| 106 | Goutam Kumar   | 2017-02-14 | Present | 
| 111 | Mansi Manchanda  | 2017-02-14 | Absent | 
| 112 | Arvind Kumar Prajapati | 2017-02-14 | Absent | 
| 116 | Rahul Garg    | 2017-02-14 | Absent | 
+--------+------------------------+------------+---------+ 
+0

Я боюсь, что колонки '[InTime]', '[OutTime]' также находятся в игре, так как обычно вы хотите проверить, был ли Employee там один конкретный день, т. Е. От 9-5. Поскольку вы сравниваете только даты, вы не можете проверить, был ли сотрудник Goutam Kumar в офисе 21 февраля с 9:00 до 10:00. – sqlady

+0

@cybersin question указывает диапазон 'date'. «которые присутствуют/отсутствуют между заданным диапазоном дат». – SqlZim

+0

@SqlZim Спасибо за помощь, которая сработала для меня :) –

0

Использование концепции поворота и извлечения всех дат, а затем помещая пользователь соответственно

DECLARE @cols AS NVARCHAR(MAX) 
DECLARE @query AS NVARCHAR(MAX) 

SET @cols=STUFF((SELECT distinct ',' + QUOTENAME(c.WorkDate) 
      FROM tt c 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 


set @query = 'SELECT Id,UserId,EmpCode, ' + @cols + ' from 
      (
       select Id 
        , UserId 
        , EmpCode 
        ,Name 
        ,WorkDate 

       from tt 
      ) x 
      pivot 
      (
       max(Name) 
       for WorkDate in (' + @cols + ') 
      ) p ' 


execute(@query) 

enter image description here