web-dev-qa-db-ja.com

SQL Serverエージェント-日付変数を使用して毎月末にクエリを実行

SQL Server 2008 R2を実行していて、基本的に毎月の初め(毎月1日の午前11:00)にクエリを実行する新しいジョブを作成する必要があります。

これがクエリです:

INSERT INTO [SupportTracker].[dbo].[DashboardRecords]
SELECT [bg_id]
      ,[bg_short_desc]
      ,[bg_reported_date]
      ,[bg_status_updated_date]
      ,[us_firstname]
      ,[us_lastname]
      ,[LastUpdatedUserFirstname]
      ,[LastUpdatedUserLastname]
      ,[st_name]
      ,[pr_name]
      ,[ct_name]
      ,[pj_name]
      ,[AssignedUserFirstname]
      ,[AssignedUserLastname]
      ,[bg_project]
      ,[no_of_hours]
      ,[BugType]
      ,[SubType]
      ,[Device]
      ,[pj_parent_id]
FROM [SupportTracker].[dbo].[ViewIssueListwBugTypeNDevice]
WHERE 
     bg_reported_date between '2012-12-01 00:00:00.000' AND '2012-12-31 23:59:59.999' 
     AND bg_id NOT IN (SELECT bg_id FROM [SupportTracker].[dbo].[DashboardRecords])
ORDER BY bg_reported_date ASC

私の問題はWHERE句にあります。これら2つの日付は毎月変更する必要があります。

  • 01-01-2013 01:00:00:00、これら2つの日付が必要です。
    2012-12-01 00:00:00.000および2012-12-31 23:59:59.999

  • 01-02-2013 01:00:00:00、これら2つの日付が必要です。
    2013-01-01 00:00:00.000および2013-01-31 23:59:59.999

基本的に、毎月末のように、データベースの一部をキャプチャしてテーブルに保存する必要があります...

ありがとう

3
Thanos

このブログ投稿で概要を説明している理由により、このクエリを満たすためにBETWEENを使用したくありません。

代わりに、無期限の日付範囲が必要です。問題の月の最初から始まり、翌月より少ない。任意の日付が与えられた月の最初を決定するには、次のようにします。

SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0);

そして、翌月の最初に取得するには、1つ追加するだけです。

SELECT DATEADD(MONTH, 1+DATEDIFF(MONTH, 0, GETDATE()), 0);

もちろん、先月が今月の最初の月だけになり、今月が最初の月の後になるようにする場合は、次のように言うことができます。

SELECT DATEADD(MONTH, 1+DATEDIFF(MONTH, 0, DATEADD(DAY, -1, GETDATE())), 0);

したがって、クエリについて、常に現在の月と比較したい場合:

...
FROM SupportTracker.dbo.ViewIssueListwBugTypeNDevice AS v
WHERE NOT EXISTS 
(
  SELECT 1 FROM SupportTracker.dbo.DashboardRecords
    WHERE bg_id = v.bg_id
)
AND v.bg_reported_date >= DATEADD(MONTH, 0, DATEDIFF(MONTH, 0, DATEADD(DAY, -1, GETDATE()))
AND v.bg_reported_date < DATEADD(MONTH, 1, DATEDIFF(MONTH, 0, DATEADD(DAY, -1, GETDATE()));

または、日付をオプションのパラメーターとして取得する場合、日を減算する必要はありません。実際に必要な月内の日付を渡すだけです(そして、NULLを渡した場合でも、上記の式にフォールバック):

  @Month DATE = NULL
...

  SET @Month = DATEADD(MONTH, 0, DATEDIFF(MONTH, 0, COALESCE(@Month, 
    DATEADD(DAY, -1, GETDATE())));  

...
FROM SupportTracker.dbo.ViewIssueListwBugTypeNDevice AS v
WHERE NOT EXISTS 
(
  SELECT 1 FROM SupportTracker.dbo.DashboardRecords
    WHERE bg_id = v.bg_id
)
AND v.bg_reported_date >= @Month
AND v.bg_reported_date < DATEADD(MONTH, 1, @Month);

ただし、 datediffが問題を引き起こす可能性があるため、一般的に、以下は特定の月を決定するのに適しています

SELECT FirstOfThisMonth = DATEADD(DAY, 1-DAY(GETDATE()), CONVERT(date, GETDATE()));
7
Aaron Bertrand

月の最初と最後の日を見つけるには:

DECLARE @MonthStart DATETIME
DECLARE @Date  DATETIME
DECLARE @next DATETIME 
-- create the required date. because today is the 21st i subtracted month. 
-- since you're running the job on the first day of the new month, 
-- you may want to change MONTH to DAY. however, if the job fails that change
-- that may cause you some problems
SET @Date = DATEADD(MONTH,-1,DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0)) 

-- get the first day of the month of the date specified
SET @MonthStart = DATEADD(DAY, 1, @Date - DAY(@Date) + 1) -1

-- get the first day of next month
SET @Next = DATEADD(MONTH,1,@MonthStart)

-- prove to yourself that these dates are correct (sanity check)
SELECT @MonthStart, @next

ロジックに従って、ニーズに合わせて編集できるように、このようにレイアウトしました。

余談ですが、NOT IN慣習はやや反パターンであり、 一部の専門家BETWEENの使用は推奨されません。

LEFT JOIN

INSERT INTO [SupportTracker].[dbo].[DashboardRecords]
SELECT [bg_id]
      ,[bg_short_desc]
      ,[bg_reported_date]
      ,[bg_status_updated_date]
      ,[us_firstname]
      ,[us_lastname]
      ,[LastUpdatedUserFirstname]
      ,[LastUpdatedUserLastname]
      ,[st_name]
      ,[pr_name]
      ,[ct_name]
      ,[pj_name]
      ,[AssignedUserFirstname]
      ,[AssignedUserLastname]
      ,[bg_project]
      ,[no_of_hours]
      ,[BugType]
      ,[SubType]
      ,[Device]
      ,[pj_parent_id]
FROM [SupportTracker].[dbo].[ViewIssueListwBugTypeNDevice] b
LEFT JOIN [SupportTracker].[dbo].[DashboardRecords] d
    ON b.bg_id = d.bg_id
WHERE b.bg_reported_date >= @MonthStart and b.bg_reported_date < @Next
    AND d.[bg_short_desc] IS NULL

(これは、[bg_short_desc]が[DashboardRecords] テーブル。

EVEN BETTERは

存在しません

INSERT INTO [SupportTracker].[dbo].[DashboardRecords]

SELECT [bg_id]
      ,[bg_short_desc]
      ,[bg_reported_date]
      ,[bg_status_updated_date]
      ,[us_firstname]
      ,[us_lastname]
      ,[LastUpdatedUserFirstname]
      ,[LastUpdatedUserLastname]
      ,[st_name]
      ,[pr_name]
      ,[ct_name]
      ,[pj_name]
      ,[AssignedUserFirstname]
      ,[AssignedUserLastname]
      ,[bg_project]
      ,[no_of_hours]
      ,[BugType]
      ,[SubType]
      ,[Device]
      ,[pj_parent_id]
FROM [SupportTracker].[dbo].[ViewIssueListwBugTypeNDevice] b
WHERE b.bg_reported_date >= @MonthStart and b.bg_reported_date < @Next
    AND NOT EXISTS (SELECT 1 FROM [SupportTracker].[dbo].[DashboardRecords] d
        WHERE b.bg_id = d.bg_id);

また、なぜインサートを注文するのですか? DashboardRecordsテーブルから選択する場合、順序付けの方が便利でしょう。

7
swasheck