web-dev-qa-db-ja.com

月と年のみに基づいたSQL Serverの日付比較

月と年のみに基づいてSQLの日付を比較する最良の方法を決定するのに苦労しています。

日付に基づいて計算を行います。請求は月単位で行われるため、月の日付がより多くの障害を引き起こしています。

例えば

DECLARE @date1 DATETIME = CAST('6/15/2014' AS DATETIME),
        @date2 DATETIME = CAST('6/14/2014' AS DATETIME)

SELECT * FROM tableName WHERE @date1 <= @date2

@ date1は@ date2より大きいため、上記の例では行は返されません。だから私は方程式から一日を取る方法を見つけたいです。

同様に、次の状況でも同じ理由で悲しみを覚えます。

DECLARE @date1 DATETIME = CAST('6/14/2014' AS DATETIME),
        @date2 DATETIME = CAST('6/15/2014' AS DATETIME),
        @date3 DATETIME = CAST('7/1/2014' AS DATETIME)

SELECT * FROM tableName WHERE @date2 BETWEEN @date1 AND @date3

日付のインライン変換を行って、指定された日付の月の最初の日と最後の日を導き出しました。

SELECT * 
FROM tableName 
WHERE date2 BETWEEN
    DATEADD(month, DATEDIFF(month, 0, date1), 0) -- The first day of the month for date1
    AND
    DATEADD(s, -1, DATEADD(mm, DATEDIFF(m, 0, date2) + 1, 0)) -- The lastday of the month for date3

これを行うには簡単な方法が必要です。助言がありますか?

18
Andy Evans

間のような不等式を処理するために、日付/時刻を文字列または整数としてYYYYMM表現に変換するのが好きです。この例では:

DECLARE @date1 DATETIME = CAST('6/14/2014' AS DATETIME),
        @date2 DATETIME = CAST('6/15/2014' AS DATETIME),
        @date3 DATETIME = CAST('7/1/2014' AS DATETIME);

SELECT * FROM tableName WHERE @date2 BETWEEN @date1 AND @date3;

クエリを次のように記述します。

SELECT *
FROM tableName
WHERE year(@date2) * 100 + month(@date2) BETWEEN year(@date1) * 100 + month(@date1) AND
                                                 year(@date3) * 100 + month(@date1);
21
Gordon Linoff

次のように、特定の日付の月と年を現在の日付にフィルターできます。

_SELECT * 
FROM tableName 
WHERE month(date2) = month(getdate()) and year(date2) = year(getdate())
_

GETDATE()メソッドを目的の日付に置き換えるだけです。

15
Tanner

MONTH および YEAR の日付の値に参加できます。

SELECT * 
FROM tableName 
WHERE YEAR(@date1) = YEAR(@date2) AND MONTH(@date1) = MONTH(@date2)
9
DavidG

最初に、使用している_'YYYYMMDD'_ではなく、標準の_'6/15/2014'_のような明確な日付の形式を使用します。 Aaron Bertrandのブログは、私ができるよりもはるかによく、これがうまくいかないさまざまな方法を説明しています。
悪い習慣:日付/範囲のクエリを誤って処理する

特定の問題については、月の最初と最後の日(date1とdate3)を見つける最後のクエリは、私が正しいと思う意見です。 evil BETWEENを避ければ、月の最初の日(date1の最初の日とdate3の翌月の最初の日)だけが必要です。 BETWEENと悪魔の共通点は何ですか?

_SELECT * 
FROM tableName 
WHERE date2 >= DATEADD(month, DATEDIFF(month, '19000101', @date1), '19000101')
  AND date2 < DATEADD(month, 1+DATEDIFF(month, '19000101', @date3), '19000101') ;
_

クエリは、_date2_(DATEDATETIME、_DATETIME2_、またはSMALLDATTEIME)のデータ型に関係なく、そのまま機能します。

ボーナスポイント、_date2_のインデックスは、このようにオプティマイザーによって考慮されます。


(別の)Aaronのブログ投稿によると、DATEDIFF()を使用して式を評価する際のカーディナリティ推定の問題を回避するための改善:
パフォーマンスの驚きと仮定:DATEDIFF

_SELECT * 
FROM tableName 
WHERE date2 >= CONVERT(DATE, DATEADD(day, 1 - DAY(@date1), @date1))
  AND date2 < DATEADD(month, 1, 
                      CONVERT(DATE, DATEADD(day, 1 - DAY(@date3), @date3))) ;
_
8
ypercubeᵀᴹ

この 'yyyyMM'のように日付の書式設定を使用できるため、同じ年の月のみが選択されます。

SELECT * 
FROM tableName 
WHERE FORMAT(date_month_bill, 'yyyyMM') < FORMAT(DATEADD(MONTH, -1, GETDATE()), 'yyyyMM') 
AND FORMAT(date_month_bill, 'yyyyMM') > FORMAT(DATEADD(MONTH, -3, GETDATE()), 'yyyyMM')
0
Andy Ferdian