4

我有以下架构,我已经稍微简化了:

CREATE TABLE [dbo].[Header] (
    [HeaderId] [int] IDENTITY(1,1) NOT NULL,
    [StaffId] [int] NOT NULL,
    [WeekEnding] [smalldatetime] NOT NULL,
    ...
)

CREATE TABLE [dbo].[Staff] (
    [StaffId] [int] NOT NULL,
    [FirstWeekEnding] [smalldatetime] NULL,
    ...
)

Header 表上的 StaffId 是一个外键。

标题表跟踪与员工相关的数据(在未显示的子表中),如果子表中的数据存在,则对于给定的一周,将有一个“周末”条目。在这种情况下,“周末”始终是星期日。因此,样本数据可能如下所示:

HeaderId    StaffId    WeekEnding
---------------------------------
1           1          13/02/2011
2           1          20/02/2011
etc...

staff 表上的“FirstWeekEnding”值是他们开始跟踪 Header 表中信息的第一个日期。

我的问题

给定每个工作人员的第一周结束日期,我如何构建一个查询来提供从 Header 表到当前日期的所有 MISSING 记录?

例如,给定以下数据:

StaffId     FirstWeekEnding
---------------------------
1           02/01/2011

HeaderId    StaffId    WeekEnding
---------------------------------
1           1          02/01/2011
2           1          09/01/2011
3           1          16/01/2011
4           1          13/02/2011
5           1          20/02/2011

结果将是:

StaffId    WeekEnding
---------------------
1          23/01/2011
1          30/01/2011
1          06/02/2011

理想情况下,查询应处理按 StaffId 分组的多个员工。

4

3 回答 3

3

您将需要一种方法来生成日期系列。参见例如http://syntaxhelp.com/SQLServer/Recursive_CTE。然后搜索日期系列中没有匹配记录的条目。

DECLARE @startDate DATETIME, @endDate DATETIME
SELECT @startDate = '2011-01-02', @endDate = GETDATE()

;WITH DateSeries AS (
    SELECT @startDate AS dt
    UNION ALL
    SELECT dt + 7 FROM DateSeries      -- using 7 for weekly interval
    WHERE dt + 7 <= @endDate
)
SELECT
    *
FROM
    DateSeries ds
LEFT JOIN
    (your data here) t
ON
    ds.dt = t.WeekEnding
WHERE
    t.WeekEnding IS NULL
于 2011-02-23T00:23:44.977 回答
2

假设您使用的是 SQL 2005+,您可以为每个员工生成所有周数,并尝试加入 CTE 中的 Header 表(类似,但可能不完全是这样):

;WITH cte AS 
( SELECT StaffId, FirstWeekEnding AS WeekEnding
  FROM STAFF
  UNION ALL
  SELECT StaffId, DATEADD(D, 7, WeekEnding) FROM cte
  WHERE DATEADD(D, 7, WeekEnding) <= GETDATE()
)
SELECT StaffId, WeekEnding
FROM cte LEFT JOIN Header ON cte.StaffId = Header.StaffId AND cte.WeekEnding = Header.WeekEnding
WHERE Header.WeekEnding IS NULL
OPTION (MAXRECURSION 32767)
于 2011-02-23T00:22:38.767 回答
1

好的,所以我建议创建一个日历表并加入该表。

这是最终的查询:

select StaffID, BaseDate
From (
select 
 StaffID, 
 BaseDate, 
 (
  Select count(*) 
  from Header h 
  where h.WeekEnding = c.BaseDate And h2.StaffID = h.StaffID
 ) as Count
From Header h, Calendar c ) as Subquery
Where Count = 0

和日历:

create table Calendar (
BaseDate datetime primary key,
DayOfWeek varchar(10) not null,
WeekOfYear int not null,
MonthOfYear varchar(10) not null,
Quarter int not null
/* Add any other useful columns */
)
go

declare @d datetime
set @d = '20090101'
while @d < '20250101'
begin
insert into dbo.Calendar values (
@d,
datename(dw, @d),
datepart(ww, @d),
datename(mm, @d),
datepart(qq, @d))
set @d = dateadd(dd, 1, @d)
end
go

select *
from dbo.Calendar
where DayOfWeek = 'Sunday' and
BaseDate between '20090101' and '20250101'
go
于 2011-02-23T00:38:10.777 回答