2017-02-24 91 views
3

假設我們在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 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:0016: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返回此結果的查詢?

+0

您是否需要這樣的SQL?在顯示應用程序之前操作數據會不會更容易? –

+0

所以在這裏我應該假設你給兩個輸入變量'@ FromDate'和'@ ToDate'使用我必須生成「日期」列右? –

+0

@ jason.kaisersmith我想在SQL中希望它生成的數據將與另一個表連接的原因,因此它在代碼中效率不高,因爲SQL –

回答

2

我會用你的自/至輸入參數,生成在遞歸CTE飛日曆,然後根據加入,爲您的輪班表平日價值。

DECLARE @Shift TABLE (ShiftID INT, [Day] VARCHAR(3), DoctorId INT, FromTime TIME, ToTime TIME) 
INSERT INTO @Shift 
VALUES (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') 

DECLARE @D1 DATE, @D2 DATE 
SET @D1 = '2017-02-19' 
SET @D2 = '2017-02-28' 

;WITH Calendar AS 
(
    SELECT @D1 AS [DateVal], LEFT(DATENAME(WEEKDAY,@D1),3) AS [DWName] 
    UNION ALL 
    SELECT DATEADD(DAY,1,DateVal), LEFT(DATENAME(WEEKDAY,DATEADD(DAY,1,DateVal)),3) 
    FROM Calendar 
    WHERE DateVal<@D2 
) 


SELECT S.DoctorId, C.DateVal, S.[Day], S.FromTime, S.ToTime 
FROM @Shift S 
JOIN Calendar C ON S.[Day]=C.DWName 
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%' 
+0

實際上我們不能在代碼中明確地忽略'FRI'和'SAT',因爲我們不能期望這個數據,這個數據可能稍後會改變 –

0

我認爲使用SQL來處理這類任務是一個壞主意,因爲使用了大量的邏輯操作。使用C#函數應該更有效率。

使用SQL或C#將是同一個邏輯的解決方案:

1 - 創建臨時表,將讓你的結果。

2 - 從開始日期到結束日期循環播放日期。爲每個日期獲取DAY部分。從DAY部分,獲取您的字段FromTime和ToTime。將結果插入臨時表。

3 - 返回臨時表(或選擇並銷燬它)。

+0

你是對的,但我想要的問題是創建SQL查詢,我想要使用生成的數據與另一個表連接 –

+0

然後只保留臨時表並加入它。你不關心C#是否完成臨時表。使用C#的問題將是臨時表名稱的通信(無論是放入一個靜態表名還是在連接查詢中使用動態SQL)。 – Lostblue

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表中,獲取匹配記錄(如果有)和適當的時間。

請注意,此版本將適用於多位醫生。

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 
相關問題