SQL Server使用表中的一些数据生成数据

时间:2017-02-24 16:13:53

标签: c# sql sql-server

假设我们在SQL Server中有一个存储医生班次的表,因此我们使用工作日而不是存储明确的日期,表格如下所示

ShiftId  Day    DoctorId    FromTime      ToTime
--------------------------------------------------
1        SUN    1           08:00:00      16:00:00
2        MON    1           09:00:00.00   14:00:00
3        TUE    1           09:00:00.00   15:00:00
4        WED    1           10:00:00.00   17:00:00
5        THU    1           13:00:00.00   18:00:00

我想创建一个select语句,通过使用此表中存储的数据生成显式日期

示例

假设我想生成Sunday 19th February 2017Tuesday 28th February 2017之间的日期,输出应该是这样的

DoctorId    Date                Day     FromTime    ToTime
------------------------------------------------------------
1           '02-19-2017'        SUN     08:00:00    16:00:00
1           '02-20-2017'        MON     09:00:00    14:00:00
1           '02-21-2017'        TUE     09:00:00    15:00:00
1           '02-22-2017'        WED     10:00:00    17:00:00
1           '02-23-2017'        THU     13:00:00    18:00:00
1           '02-26-2017'        SUN     08:00:00    16:00:00
1           '02-27-2017'        MON     09:00:00    14:00:00
1           '02-28-2017'        TUE     09:00:00    15:00:00

解释

为这些日期生成的时间对应于我们表格中存储的天数,例如,第一行'02-19-2017'生成的时间为08:00:00 16:00:00,因为'02-19-2017'是星期日,并且第二行'02-20-2017'生成的时间为09:00:00 14:00:00,因为'02-20-2017'是星期一,依此类推。

您可能会注意到24th February FRI25th February SAT没有生成日期,因为我们未在表格中存储FridaySaturday

我们可以在T-SQL中编写一个返回此结果的查询吗?

5 个答案:

答案 0 :(得分:2)

我会使用From / To输入参数在递归CTE中动态生成日历,然后根据工作日值将其连接到班次表。

.icon-advanced {
    background: url('icon/icon-advanced.svg');
    background-repeat: no-repeat;
    background-size: cover; /* stretch the background to cover the whole element */

    /* 
       still inline, but has block features
       meaning height and width can be set
    */
    display: inline-block;
    height: 20px;
    width: 20px;
}

答案 1 :(得分:0)

使用日历CTE,加入

with DateCTE as
(
select @DateFrom as Date1
union
select dateadd('DD',1,Date1)
from DateCTE
where Date1 < @DateTo
)
select D1.*,
       datename('DW',Date1) as Day
       FromTime,
       ToTime
from DateCTE D1
left join MyTable M2
  on datename('DW',Date1) like M2.Day
where datename('DW',Date1) not like 'Fri%' 
and datename('DW',Date1) not like 'Sat%'

答案 2 :(得分:0)

我认为使用SQL进行此类任务是一个坏主意,因为使用了大量逻辑操作。使用C#函数应该更有效。

使用SQL或C#将是相同的逻辑解决方案:

1 - 创建一个保存结果的临时表。

2 - 从开始日期到结束日期循环您的日期。对于每个日期,请获取DAY部分。从DAY部分,获取你的字段FromTime和ToTime。将结果插入临时表。

3 - 返回临时表(或选择并销毁它)。

答案 3 :(得分:0)

您的数据库中可能应该有一个日历表。为此,您可以使用递归CTE或数字表来实现几乎相同的效果:

with n as (
      select row_number() over (order by (select null)) - 1 as n
      from master.spt_values
     )
select dd.doctorid, d.dte, s.day, s.fromtime, s.totime
from (select dateadd(day, n.n, @startdate) as dte
      from n
      where dateadd(day, n.n, @startdate) <= @enddate
     ) d cross join
     (select distinct doctorid from shifts
     ) dd join
     shifts s
     on upper(left(datename(wd, d.dte), 3)) = s.day and
        ss.doctorid = d.doctorid;

这有点棘手。我们的想法是生成日期(使用数字表非常容易)。然后和医生一起做cross join,所以所有的医生都有约会。最后,返回shifts表,获取匹配的记录(如果有的话)和适当的时间。

请注意,此版本适用于多位医生。

答案 4 :(得分:0)

你可以试试这个

DECLARE @STARTDate date = '02-19-2017', @ToDate date = '02-27-2017'

;WITH myCTE AS
(
    SELECT @STARTDate AS MyDate, 1 AS iID
    UNION ALL 
    SELECT DATEADD(DAY,1,MyDate), iID + 1
              FROM   myCTE 
              WHERE  MyDate < @ToDate
)
SELECT * FROM YourTable
JOIN myCTE on myCTE.iID = YourTable.ID