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,
    ...
)

ヘッダーテーブルのStaffIdは外部キーです。

ヘッダーテーブルは、スタッフに関連するデータを追跡し(サブテーブルには表示されていません)、サブテーブルにデータが存在する場合、特定の週に「週末」のエントリがあります。この場合、「週末」は常に日曜日です。したがって、サンプルデータは次のようになります。

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

スタッフテーブルの「FirstWeekEnding」値は、ヘッダーテーブルの情報の追跡を開始した最初の日付です。

私の質問

各スタッフの最初の週の終了日を前提として、ヘッダーテーブルから現在の日付までのすべての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のヘッダーテーブルに対して結合を試みることができます(これに似ていますが、正確にはそうではありません)。

;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

OKなので、カレンダーテーブルを作成してそれに参加することをお勧めします。

最後のクエリは次のとおりです。

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 に答える