【问题标题】:SQL - Conditional column selection in joinSQL - 连接中的条件列选择
【发布时间】:2017-03-24 17:33:58
【问题描述】:

我不确定这个场景是否可以使用 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 表的 Ids,该表有以下列:

ID          int    Primary Key
StartTime   time
EndTime     time

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

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

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

我怎样才能实现这个场景?

【问题讨论】:

  • 如果您能根据上述数据提供一个示例输出,那将非常有帮助
  • 工作日表中的 id 是什么。如果是那个表id,那么同一个员工怎么能包含两个不同的工作计划id,我的意思是同一个emp id的两行
  • 每行只有一名员工!并且每个员工都为每个工作日分配了小时数。所以问题很明确。我们也不需要示例输出,因为问题是关于加入的方式,对,而不是确切的结果。据我所知。 :)

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


【解决方案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
【解决方案2】:
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),具体取决于您的设置。

【讨论】:

    猜你喜欢
    • 2013-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-21
    • 1970-01-01
    • 2021-09-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多