2011-09-02 17 views
4

我正在開發一個系統(ASP.NET/MSSQL/C#)來調度餐館員工。
我遇到的問題是我需要每週「自動旋轉」輪班「InTimes」。我怎樣才能在SQL中「自動旋轉」附加記錄(1變爲2,2變3,3變4,4變回1)?

用戶需要能夠將一天的時間表複製到下週的同一天,並將所有員工輪班時間輪換一個時間段。
例如,在下表中,莫妮卡本週一有10點半的班次,所以她將在下週的11:00上班,亞當將從12:00 pm上班到上午10:30。
輪班之間的時間不是固定的,每個班次的員工人數也不是固定的。
任何想法如何做到這一點(理想的SQL語句)將不勝感激。

請記住我是一個相對的新手。

RecordID EmpType Date  Day Meal ShiftOrder InTime  EmployeeID 
1  Server 29-Aug-11 Monday Lunch 1  10:30:00 AM Monica 
2  Server 29-Aug-11 Monday Lunch 2  11:00:00 AM Sofia 
3  Server 29-Aug-11 Monday Lunch 3  11:30:00 AM Jenny 
4  Server 29-Aug-11 Monday Lunch 4  12:00:00 PM Adam 
5  Server 29-Aug-11 Monday Dinner 1  4:30:00 PM Adam 
6  Server 29-Aug-11 Monday Dinner 2  4:45:00 PM Jenny 
7  Server 29-Aug-11 Monday Dinner 3  5:00:00 PM Shauna 
8  Server 29-Aug-11 Monday Dinner 4  5:15:00 PM Sofia 
10  Server 29-Aug-11 Monday Dinner 5  5:30:00 PM Monica 
+0

什麼是代碼示例的相關性?這看起來像是第一部分的長篇重複,與手頭的問題毫無關係。請用ascii藝術替換它。 – Johan

+0

我重新格式化了「表格」,希望更清楚。 – Nick

+0

如果用戶需要能夠做到這一點,那麼你爲什麼要在SQL?在我的前端做到這一點更有意義。如果用戶需要覆蓋它(例如,員工下週正在休假),那麼您將需要在前端而不是通過SQL。 –

回答

1

不知怎的,員工需要得到他最後的(少數)轉移

SELECT TOP 3 * FROM shift WHERE EmployeeID LIKE 'monica' ORDER BY [date] DESC 

接着,他/她將需要輸入日期和時間偏移他想之前下週,相關工作計劃表。

INSERT INTO shift SELECT 
    recordID 
    ,[date] 
    ,CASE [Intime] 
    WHEN [Intime] BETWEEN 00:00 AND 10:00 THEN 'Breakfast' 
    WHEN [Intime] BETWEEN 10:01 AND 04:29 THEN 'Lunch' 
    WHEN [Intime] BETWEEN 04:30 AND 23:59 THEN 'Dinner' 
    END as Meal 
    ,No_idea_how_to_generate_this AS ShiftOrder 
    ,[Intime] 
    ,EmployeeID 
FROM (SELECT 
    NULL as recordID 
    ,DATEADD(DAY, [email protected], ls.[date]) as [date] 
    ,CAST(DATEADD(MINUTE, @timeoffset, ls.[time] AS TIME) as [Intime] 
    ,EmployeeId 
FROM Shift WHERE recordID = @recordID) AS subselect 

這裏: - @recordID是員工選擇爲出發點,爲新任命的紀錄。
- @dateoffset是增加天數的起點記錄 - @timeoffset的分鐘數添加到起始記錄

其餘全部是由該行作爲起點,用戶確定。

1

這就是我想出了:

CREATE TABLE #tmp 
(
    [RecordID] INT , 
    [EmpType] VARCHAR(20) , 
    [Date] DATE , 
    [Day] VARCHAR(10) , 
    [Meal] VARCHAR(10) , 
    [ShiftOrder] INT , 
    [InTime] TIME , 
    [EmployeeID] VARCHAR(50) 
) 

INSERT INTO [#tmp] 
     ([RecordID] , 
      [EmpType] , 
      [Date] , 
      [Day] , 
      [Meal] , 
      [ShiftOrder] , 
      [InTime] , 
      [EmployeeID] 
     ) 
VALUES (1,'Server','29-Aug-11','Monday','Lunch',1,'10:30:00 AM','Monica'), 
(2,'Server','29-Aug-11','Monday','Lunch',2,'11:00:00 AM','Sofia'), 
(3,'Server','29-Aug-11','Monday','Lunch',3,'11:30:00 AM','Jenny'), 
(4,'Server','29-Aug-11','Monday','Lunch',4,'12:00:00 PM','Adam'), 
(5,'Server','29-Aug-11','Monday','Dinner',1,'4:30:00 PM','Adam'), 
(6,'Server','29-Aug-11','Monday','Dinner',2,'4:45:00 PM','Jenny'), 
(7,'Server','29-Aug-11','Monday','Dinner',3,'5:00:00 PM','Shauna'), 
(8,'Server','29-Aug-11','Monday','Dinner',4,'5:15:00 PM','Sofia'), 
(10,'Server','29-Aug-11','Monday','Dinner',5,'5:30:00 PM','Monica'); 

WITH CountByShift AS (SELECT *, COUNT(1) OVER (PARTITION BY EmpType, [Day], [Meal]) AS [CountByShiftByDayByEmpType] 
FROM [#tmp] 
), 
NewShiftOrder AS (
    SELECT *, ([ShiftOrder] + 1) % [CountByShiftByDayByEmpType] AS [NewShiftOrder] 
    FROM [CountByShift] 
) 
SELECT [RecordID] , 
     [EmpType] , 
     [Date] , 
     [Day] , 
     [Meal] , 
     [ShiftOrder] , 
     CASE WHEN [NewShiftOrder] = 0 THEN [CountByShiftByDayByEmpType] ELSE [NewShiftOrder] END AS [NewShiftOrder], 
     [InTime] , 
     [EmployeeID] 
FROM NewShiftOrder 
ORDER BY [RecordID] 
1

你需要的所有班次的表吧:

create table dbo.Shifts (
    [Day]  varchar(9) not null, 
    Meal  varchar(6) not null, 
    ShiftOrder integer not null, 
    InTime  time not null, 
    constraint PK__dbo_Shifts primary key ([Day], Meal, ShiftOrder) 
); 

如果表正確填充你就可以運行這個以獲得當天,膳食,ShiftOrder n元組的當前地圖,膳食對:

with numbers_per_shift as (
    select [Day], Meal, max(ShiftOrder) as ShiftOrderCount 
    from dbo.Shifts s 
    group by [Day], Meal 
) 

select s.[Day], s.Meal, s.ShiftOrder, 
     s.ShiftOrder % n.ShiftOrderCount + 1 as NextShiftOrder 
    from dbo.Shifts as s 
inner join numbers_per_shift as n 
    on s.[Day] = n.[Day] 
    and s.Meal = n.Meal; 

對於表爲正確填充每個班次順序都必須以1開頭,並且在一天,一對膳食中不加跳或重複地加1。

1

借用@Ben Thul大部分#tmp表格定義,假設您有一個標識字段,而不是假設您將日期和時間存儲爲日期和時間......這應該遍地運行良好,複製的最後日期爲下一週:

CREATE TABLE #tmp 
(
    [RecordID] INT , 
    [EmpType] VARCHAR(20) , 
    [Date] VARCHAR(9) , 
    [Day] VARCHAR(10) , 
    [Meal] VARCHAR(10) , 
    [ShiftOrder] INT , 
    [InTime] VARCHAR(11) , 
    [EmployeeID] VARCHAR(50) 
) 

INSERT INTO [#tmp] 
     ([RecordID] , 
      [EmpType] , 
      [Date] , 
      [Day] , 
      [Meal] , 
      [ShiftOrder] , 
      [InTime] , 
      [EmployeeID] 
     ) 
VALUES (1,'Server','29-Aug-11','Monday','Lunch',1,'10:30:00 AM','Monica'), 
(2,'Server','29-Aug-11','Monday','Lunch',2,'11:00:00 AM','Sofia'), 
(3,'Server','29-Aug-11','Monday','Lunch',3,'11:30:00 AM','Jenny'), 
(4,'Server','29-Aug-11','Monday','Lunch',4,'12:00:00 PM','Adam'), 
(5,'Server','29-Aug-11','Monday','Dinner',1,' 4:30:00 PM','Adam'), 
(6,'Server','29-Aug-11','Monday','Dinner',2,' 4:45:00 PM','Jenny'), 
(7,'Server','29-Aug-11','Monday','Dinner',3,' 5:00:00 PM','Shauna'), 
(8,'Server','29-Aug-11','Monday','Dinner',4,' 5:15:00 PM','Sofia'), 
(10,'Server','29-Aug-11','Monday','Dinner',5,' 5:30:00 PM','Monica'); 


with 
    Shifts as (
     select EmpType, [Day], Meal, ShiftOrder, InTime 
     from #tmp 
     where [Date] = (select max(cast([Date] as datetime)) from #tmp) 
    ), 
    MaxShifts as (
     select EmpType, [Day], Meal, max(ShiftOrder) as MaxShiftOrder 
     from #tmp 
     where [Date] = (select max(cast([Date] as datetime)) from #tmp) 
     group by EmpType, [Day], Meal 
    ) 
insert into #tmp (EmpType, [Date], [Day], Meal, ShiftOrder, InTime, EmployeeID) 
    select s.EmpType 
     , replace(convert(varchar(11), dateadd(dd, 7, cast(a.[Date] as datetime)), 6), ' ', '-') as [Date] 
     , s.Day 
     , s.Meal 
     , s.ShiftOrder 
     , s.InTime 
     , a.EmployeeID 
    from #tmp as a 
     join MaxShifts as m on a.EmpType = m.EmpType 
      and a.[Day] = m.[Day] 
      and a.Meal = m.Meal 
     join Shifts as s on a.EmpType = s.EmpType 
      and a.[Day] = s.[Day] 
      and a.Meal = s.Meal 
      and 1 + a.ShiftOrder % m.MaxShiftOrder = s.ShiftOrder 
    where a.[Date] = (select max(cast([Date] as datetime)) from #tmp) 
0

我是一個SQL程序員,DBA 20歲了。據說,這個複雜的業務邏輯應該在系統的C#部分。然後TDD構建的應用程序可以處理不可避免的變化,並且仍然是可重構和正確的。

我的建議是'推回'。您的迴應應該是「這不僅僅是查找/填充空白邏輯,這種複雜的業務邏輯屬於應用程序」。它屬於可以進行單元測試的東西,並且每次更改時都會進行單元測試。

正確的答案有時是'不',這是其中之一。

1

我假設這個時間表真的和一頓飯和一個工作日在一個下面的答案中相關聯。

另外我想指出ShiftOrder和Day列不應該是列。日期顯然是由Date決定的,所以它是浪費空間的總數(計算列OR或在UI端確定它),ShiftOrder由Date和InTime列確定(可能很容易在具有RANK()函數的查詢中計算或UI方面)。這表示它會使這個查詢更容易一些:)

declare @dt date = cast('29-Aug-11' as date) 
/* note: the date above may be passed from UI or it maybe calculated based on getdate() and dateadd function or s.t. like that */ 

INSERT INTO [table] (EmpType,Date,Day,Meal,ShiftOrder,InTime,EmployeeID) 
SELECT t1.EmpType, dateadd(day, 7, t1.date), t1.day, t1.meal, t2.ShiftOrder, t2.InTime, t1.EmployeeID 
FROM [table] t1 
INNER JOIN [table] t2 
ON (t1.Date = t2.Date 
    and t1.Meal = t2.Meal 
    and (
     t1.ShiftOrder = t2.ShiftOrder + 1 
     or 
     (
      t1.ShiftOrder = (select max(shiftOrder) from [table] where meal = t1.meal and date =t1.date) 
      and 
      t2.ShiftOrder = (select min(shiftOrder) from [table] where meal = t1.meal and date =t1.date) 
     ) 
    ) 
) 
WHERE t1.Date = @dt 
1

這是一個非常直接的集面向問題。聚合(count(*)和max())和查找表是不必要的。你可以用一條SQL語句來完成。

第一步(設置)是爲了識別那些簡單地在日程表中滑下來的員工。

下一步(設置)是爲了識別需要「環繞」到計劃頭部的那些員工。

這就是我想出了:

/* Set up the temp table for demo purposes */ 
DROP TABLE #tmp 

CREATE TABLE #tmp 
(
    [RecordID] INT , 
    [EmpType] VARCHAR(20) , 
    [Date] DATE , 
    [Day] VARCHAR(10) , 
    [Meal] VARCHAR(10) , 
    [ShiftOrder] INT , 
    [InTime] TIME, 
    [EmployeeID] VARCHAR(50) 
) 

INSERT INTO [#tmp] 
     ([RecordID] , 
      [EmpType] , 
      [Date] , 
      [Day] , 
      [Meal] , 
      [ShiftOrder] , 
      [InTime] , 
      [EmployeeID] 
     ) 
VALUES (1,'Server','29-Aug-11','Monday','Lunch',1,'10:30:00 AM','Monica'), 
(2,'Server','29-Aug-11','Monday','Lunch',2,'11:00:00 AM','Sofia'), 
(3,'Server','29-Aug-11','Monday','Lunch',3,'11:30:00 AM','Jenny'), 
(4,'Server','29-Aug-11','Monday','Lunch',4,'12:00:00 PM','Adam'), 
(5,'Server','29-Aug-11','Monday','Dinner',1,' 4:30:00 PM','Adam'), 
(6,'Server','29-Aug-11','Monday','Dinner',2,' 4:45:00 PM','Jenny'), 
(7,'Server','29-Aug-11','Monday','Dinner',3,' 5:00:00 PM','Shauna'), 
(8,'Server','29-Aug-11','Monday','Dinner',4,' 5:15:00 PM','Sofia'), 
(10,'Server','29-Aug-11','Monday','Dinner',5,' 5:30:00 PM','Monica'); 

/* the "fills" CTE will find those employees who "wrap around" */ 
;WITH fills AS (
    SELECT 
     [d2].[EmpType], 
     [d2].[Date], 
     [d2].[Day], 
     [d2].[Meal], 
     1 AS [ShiftOrder], 
     [d2].[InTime], 
     [d2].[EmployeeID] 
    FROM 
     [#tmp] d1 
    RIGHT OUTER JOIN 
     [#tmp] d2 ON 
      ([d1].[Meal] = [d2].[Meal]) 
      AND ([d1].[ShiftOrder] = [d2].[ShiftOrder] + 1) 
    WHERE 
     [d1].[EmployeeID] IS NULL 
) 
INSERT INTO [table] (EmpType,Date,Day,Meal,ShiftOrder,InTime,EmployeeID) 
SELECT 
    [d1].[EmpType], 
    DATEADD(DAY, 7, [d1].[Date]) AS [Date], 
    DATENAME(dw,(DATEADD(DAY, 7, [d1].[Date]))) AS [Day], 
    [d1].[Meal], 
    [d1].[ShiftOrder], 
    [d1].[InTime], 
    ISNULL([d2].[EmployeeID], [f].[EmployeeID]) AS [EmployeeID] 
FROM 
    [#tmp] d1 
LEFT OUTER JOIN 
    [#tmp] d2 ON 
     ([d1].[Meal] = [d2].[Meal]) AND ([d1].[ShiftOrder] = [d2].[ShiftOrder] + 1) 
LEFT OUTER JOIN 
    [fills] f ON 
     ([d1].[Meal] = [f].[Meal]) AND ([d1].[ShiftOrder] = [f].[ShiftOrder]) 
0

如何使用數據透視表中的所有員工,然後將移位的時序爲行?在初始日期基於Shift排序名稱。

事情是這樣的..

Date_time Shift_Order Monica Sofia Jenny Adam  Shauna 
08/29/11 1  10:30AM 11:00AM 11:30AM 12:00PM NULL 
08/29/11 2  5:30PM 5:15PM 4:45PM 4:30PM 5:00PM 
相關問題