【问题标题】:Know Present Absent from working date range知道工作日期范围内目前缺勤
【发布时间】:2017-02-22 13:16:40
【问题描述】:

Here is my table

我想获取在给定日期范围内存在/不存在的所有用户。

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

【问题讨论】:

  • 您应该将日期存储为 date 数据类型。
  • 虽然这不能解决您的问题,但您应该注意规范化。您的数据库中有两次员工的姓名 (?),一次在 tUserInfo 表中,多次在 tt 表中。如果任何用户名发生更改,您将必须检查 tt 中的所有条目并进行更改。否则 - 如果您不将其存储在这里 - 您只需在 tUserInfo 表中更改一次。

标签: sql sql-server sql-server-2008 sql-server-2012 sql-server-2008-r2


【解决方案1】:

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  |
+--------+------------------------+------------+---------+

注意:这只检查表 tt 中存在的 workdates。


如果您还需要检查给定日期范围内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  |
+--------+------------------------+------------+---------+

【讨论】:

  • 恐怕列 [InTime] , [OutTime] 也在游戏中,因为通常你想检查员工是否在某一天,即从 9 点到 5 点。由于您只比较日期,因此您无法检查员工 Goutam Kumar 在 2 月 21 日上午 9 点到 10 点是否在办公室。
  • @cybersin 问题状态 date 范围。 “在给定日期范围内存在/不存在。”
  • @SqlZim 结果列中没有工作日期我如何知道员工缺席/在场的日期。谢谢。
  • @SqlZim 但我想得到这样的结果:Id UserId Name EmpCode WorkDate Status 1 1 106 Goutam Kumar E2E106 2017-02-13 Present 2 2 111 Mansi Manchanda E2E111 2017-02-14 Absent 3 3 112 Arvind Kumar E2E112 2017-02-14 缺席 4 4 116 Rahul Garg E2E116 2017-02-16 缺席
  • @GoutamSingh 更新了答案。
【解决方案2】:

使用枢轴概念并获取所有日期然后分别放置用户

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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    • 1970-01-01
    • 1970-01-01
    • 2013-05-02
    • 1970-01-01
    相关资源
    最近更新 更多