SQL - 连接中的条件列选择

时间:2017-03-24 17:33:59

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

我不确定是否可以使用TSQL实现此方案。我有一个名为WorkingDays的表,它有这个信息

ID  |  EmployeeId |  Monday | Tuesday | Wednesday | Thursday | Friday
----------------------------------------------------------------------
1   | 1           | 2       | 2       | 3         | 6        | 5
2   | 2           | 1       | 7       | 5         | 2        | 3

days列存储了WorkingSchedule表的ID,其中包含以下列:

ID          int    Primary Key
StartTime   time
EndTime     time

所以我需要id根据当前日期获取员工的StartTime和EndTime。

我需要从查询中获得的是开始和结束时间,具体取决于当天。我想要过滤的日期是当前日期(使用getdate()函数)

因此需要选择正确的日期列名来进行连接。

我如何实现这种情况?

2 个答案:

答案 0 :(得分:1)

动态sql版本:

declare @sql nvarchar(max) ='
select 
    t.EmployeeId
  , StarTime = max(case when t.rn=1 then '+quotename(datename(weekday,getdate()))+' end)
  , EndTime  = max(case when t.rn=2 then '+quotename(datename(weekday,getdate()))+' end)
from (
  select *
    , rn = row_number() over (partition by t.EmployeeId order by t.Id)
    from t
    ) t
group by t.EmployeeId;'
exec sp_executesql @sql;

rextester演示:http://rextester.com/WNH34961

返回:

+------------+----------+---------+
| EmployeeId | StarTime | EndTime |
+------------+----------+---------+
|          1 |        5 |       3 |
+------------+----------+---------+

根据您的输出方式,以下是另外两种不使用动态sql的方法:

两者都使用cross apply()取消数据取消,WorkDay = datename(weekday,getdate())取得当前WorkDay列。

对于一行输出,我们添加一些条件聚合:

/* one row per employeeId */
select 
    t.EmployeeId
  , x.WorkDay
  , StarTime = max(case when t.rn=1 then x.Time end)
  , EndTime  = max(case when t.rn=2 then x.Time end)
from (
  select *
    , rn = row_number() over (partition by t.EmployeeId order by t.Id)
    from t
    ) t
  cross apply (values 
    ('Monday',Monday),('Tuesday',Tuesday),('Wednesday',Wednesday)
    ,('Thursday',Thursday),('Friday',Friday)
  ) x (WorkDay,Time)
where WorkDay = datename(weekday,getdate())
group by t.EmployeeId, x.WorkDay

返回:

+------------+---------+----------+---------+
| EmployeeId | WorkDay | StarTime | EndTime |
+------------+---------+----------+---------+
|          1 | Friday  |        5 |       3 |
+------------+---------+----------+---------+

如果您想要输出两行,例如您当前的输出:

/* two rows per employeeId */
select 
    t.Id
  , t.EmployeeId
  , x.WorkDay
  , t.StartEnd
  , x.Time
from (
  select *
    , StartEnd = case 
        when row_number() over (partition by t.EmployeeId order by t.Id) = 1 
          then 'StartTime' 
        else 'EndTime' 
        end 
    from t
    ) t
  cross apply (values 
    ('Monday',Monday),('Tuesday',Tuesday),('Wednesday',Wednesday)
    ,('Thursday',Thursday),('Friday',Friday)
  ) x (WorkDay,Time)
where WorkDay = datename(weekday,getdate());

返回:

+----+------------+---------+-----------+------+
| Id | EmployeeId | WorkDay | StartEnd  | Time |
+----+------------+---------+-----------+------+
|  1 |          1 | Friday  | StartTime |    5 |
|  2 |          1 | Friday  | EndTime   |    3 |
+----+------------+---------+-----------+------+

答案 1 :(得分:0)

select wd.Employee, ws.StartTime, ws.EndTime
  from WorkingDays wd
  join WorkingSchedule ws on ws.Id = case datename(weekday, getdate())
                                      when 'Monday'    then ws.Monday
                                      when 'Tuesday'   then ws.Tuesday
                                      when 'Wednesday' then ws.Wednesday
                                      when 'Thursday'  then ws.Thursday
                                      when 'Friday'    then ws.Friday
                                      else 0
                                     end

提示:datename(weekday, getdate())会返回当前区域设置中的工作日名称!这可能会更好:

select wd.Employee, ws.StartTime, ws.EndTime
  from WorkingDays wd
  join WorkingSchedule ws on ws.Id = case datepart(weekday, getdate())
                                      when 1 then wd.Monday
                                      when 2 then wd.Tuesday
                                      when 3 then wd.Wednesday
                                      when 4 then wd.Thursday
                                      when 5 then wd.Friday
                                      else        0
                                     end

但是你必须检查哪一天是第一周(0,1),具体取决于你的设置。