sql >> データベース >  >> RDS >> Sqlserver

SQLServerでSETDATEFIRSTを無視するDATEDIFF()の回避策(T-SQLの例)

    DATEDIFF()の興味深い点 SQL Serverの機能は、SET DATEFIRSTを無視することです。 価値。

    ただし、これはバグではありません。 DATEDIFF()に関するMicrosoftのドキュメント 次のことを明確に述べています:

    SET DATEFIRSTを指定する DATEDIFFには影響しません 。 DATEDIFF 関数が決定論的な方法で動作することを保証するために、常に日曜日を週の最初の日として使用します。

    わからない場合は、SET DATEFIRST セッションの最初の曜日を設定します。 1から7までの数字です(月曜日から日曜日に対応します)。

    SET DATEFIRSTの初期値 言語設定(SET LANGUAGEで設定できます)によって暗黙的に設定されます 声明)。実際の値は、設定されている言語によって異なります。たとえば、us_englishのデフォルト値 言語は7 (日曜日)、Britishのデフォルト 言語は1 (月曜日)。

    ただし、SET DATEFIRSTを使用できます これをオーバーライドして、週の最初の日に別の日を使用しながら同じ言語を使用し続けることができるようにするステートメント。

    ただし、前述のように、SET DATEFIRST 値はDATEDIFF()には影響しません 働き。 DATEDIFF() 関数は、SET DATEFIRSTに関係なく、日曜日が週の最初の日であると常に想定します。 値。

    これは、DATEDIFF()を使用するときにいくつかの興味深い問題を引き起こす可能性があります 仕組みがわからない場合。

    このような状況に陥った場合は、このページの例がお役に立てば幸いです。

    例1-問題

    まず、実際の問題の例を示します。 SET DATEFIRSTを取得できることに注意してください @@DATEFIRSTを選択して値を指定します 。

    DECLARE 
      @startdate date = '2025-01-05', 
      @enddate date = '2025-01-06';
    
    SET LANGUAGE us_english;
    SELECT 
      @@DATEFIRST AS 'SET DATEFIRST Value', 
      DATEDIFF(week, @startdate, @enddate) AS 'us_english DATEDIFF() Result';
    
    SET LANGUAGE British;
    SELECT 
      @@DATEFIRST AS 'SET DATEFIRST Value', 
      DATEDIFF(week, @startdate, @enddate) AS 'British DATEDIFF() Result';
    

    結果:

    +-----------------------+--------------------------------+
    | SET DATEFIRST Value   | us_english DATEDIFF() Result   |
    |-----------------------+--------------------------------|
    | 7                     | 0                              |
    +-----------------------+--------------------------------+
    
    +-----------------------+-----------------------------+
    | SET DATEFIRST Value   | British DATEDIFF() Result   |
    |-----------------------+-----------------------------|
    | 1                     | 0                           |
    +-----------------------+-----------------------------+
    

    この場合、最初の日付は日曜日になり、2番目の日付は月曜日になります。したがって、通常は英国のDATEDIFF()を期待します。 1を返す結果 。これは、日曜日から月曜日に行くときに週と部分の境界を越えるためです(SET DATEFIRSTのため) 値は1です これは「月曜日」を意味し、月曜日は新しい週の始まりを示します)。

    ただし、DATEDIFF() SET DATEFIRSTを無視します 値であり、日曜日が週の始まりであると想定すると、両方の言語で同じ結果が得られます。

    念のため、もう一度クエリを実行しますが、今回はSET DATEFIRSTを設定します。 値明示的に 。つまり、言語を設定する代わりに、SET DATEFIRSTを使用します ステートメント:

    DECLARE 
      @startdate date = '2025-01-05', 
      @enddate date = '2025-01-06';
    
    SET DATEFIRST 7;
    SELECT 
      @@DATEFIRST AS 'SET DATEFIRST Value', 
      DATEDIFF(week, @startdate, @enddate) AS 'us_english DATEDIFF() Result';
    
    SET DATEFIRST 1;
    SELECT 
      @@DATEFIRST AS 'SET DATEFIRST Value', 
      DATEDIFF(week, @startdate, @enddate) AS 'British DATEDIFF() Result';
    

    結果:

    +-----------------------+--------------------------------+
    | SET DATEFIRST Value   | us_english DATEDIFF() Result   |
    |-----------------------+--------------------------------|
    | 7                     | 0                              |
    +-----------------------+--------------------------------+
    
    +-----------------------+-----------------------------+
    | SET DATEFIRST Value   | British DATEDIFF() Result   |
    |-----------------------+-----------------------------|
    | 1                     | 0                           |
    +-----------------------+-----------------------------+
    

    SET DATEFIRSTを明示的に設定した場合でも、同じ結果になります 価値。ただし、これは驚くべきことではありません。そうでなかった場合は驚きます。 同じ結果を返します。

    また、これは単にDATEDIFF()であることを確認します 意図したとおりに機能しています。

    では、DATEDIFF()になるように変更するにはどうすればよいですか。 結果はSET DATEFIRSTを尊重します 値?

    ソリューション

    意図した結果を得ることができる解決策/回避策は次のとおりです。これにより、SET DATEFIRSTが確実になります 設定はDATEDIFF()に組み込まれます 結果。

    あなたがする必要があるのは@@DATEFIRSTを引くことだけです 入力日から。

    DECLARE 
      @startdate date = '2025-01-05', 
      @enddate date = '2025-01-06';
    
    SET DATEFIRST 7;
    SELECT 
      @@DATEFIRST AS 'SET DATEFIRST Value', 
      DATEDIFF(week, DATEADD(day, [email protected]@DATEFIRST, @startdate), DATEADD(day, [email protected]@DATEFIRST, @enddate)) AS 'us_english DATEDIFF() Result';
    
    SET DATEFIRST 1;
    SELECT 
      @@DATEFIRST AS 'SET DATEFIRST Value', 
      DATEDIFF(week, DATEADD(day, [email protected]@DATEFIRST, @startdate), DATEADD(day, [email protected]@DATEFIRST, @enddate)) AS 'British DATEDIFF() Result';
    

    結果:

    +-----------------------+--------------------------------+
    | SET DATEFIRST Value   | us_english DATEDIFF() Result   |
    |-----------------------+--------------------------------|
    | 7                     | 0                              |
    +-----------------------+--------------------------------+
    
    +-----------------------+-----------------------------+
    | SET DATEFIRST Value   | British DATEDIFF() Result   |
    |-----------------------+-----------------------------|
    | 1                     | 1                           |
    +-----------------------+-----------------------------+
    

    これはDATEADD()を使用します @@DATEFIRSTの量だけ入力日付を減らす関数 (これはSET DATEFIRST 値)。

    この場合、DATEDIFF() 関数は引き続き日曜日を週の最初の日として使用しますが、計算に使用される実際の日付は異なります。 @@DATEFIRSTの量だけ過去に戻されました 。

    次の例は、計算に使用された日付を示しています。

    DECLARE 
      @startdate date = '2025-01-05', 
      @enddate date = '2025-01-06';
    
    SET DATEFIRST 7;
    SELECT 
      @startdate AS 'Original Date', 
      @@DATEFIRST AS 'Subtract By',
      DATEADD(day, [email protected]@DATEFIRST, @startdate) AS 'Resulting Date'
    UNION ALL
    SELECT 
      @enddate, 
      @@DATEFIRST,
      DATEADD(day, [email protected]@DATEFIRST, @enddate);  
    
    SET DATEFIRST 1;
    SELECT 
      @startdate AS 'Original Date', 
      @@DATEFIRST AS 'Subtract By',
      DATEADD(day, [email protected]@DATEFIRST, @startdate) AS 'Resulting Date'
    UNION ALL
    SELECT 
      @enddate, 
      @@DATEFIRST,
      DATEADD(day, [email protected]@DATEFIRST, @enddate);  
    

    結果:

    +-----------------+---------------+------------------+
    | Original Date   | Subtract By   | Resulting Date   |
    |-----------------+---------------+------------------|
    | 2025-01-05      | 7             | 2024-12-29       |
    | 2025-01-06      | 7             | 2024-12-30       |
    +-----------------+---------------+------------------+
    
    +-----------------+---------------+------------------+
    | Original Date   | Subtract By   | Resulting Date   |
    |-----------------+---------------+------------------|
    | 2025-01-05      | 1             | 2025-01-04       |
    | 2025-01-06      | 1             | 2025-01-05       |
    +-----------------+---------------+------------------+
    

    したがって、回避策では、DATEDIFF() 計算には「結果の日付」を使用しました。

    DATEDIFF()で問題が発生した場合 SET DATEFIRSTを無視します 、この記事がお役に立てば幸いです。


    1. GroupingError:ERROR:列はGROUP BY句に表示されるか、集計関数で使用される必要があります

    2. SQL ServerビューへのODBCリンクテーブルをプログラムで作成し、編集可能にするにはどうすればよいですか?

    3. SQLiteOpenHelperクラスを使用してsqliteデータベースからアイテムを削除する方法

    4. OracleSQLDeveloperでの新しいデータベースと新しい接続の作成