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

SQL Serverのdatetime2とsmalldatetime:違いは何ですか?

    この記事では、 datetime2の主な違いについて説明します。 およびsmalldatetime SQLServerのデータ型。

    両方のデータ型は日付と時刻の値を格納するために使用されますが、2つの間にいくつかの重要な違いがあります。ほとんどの場合、 datetime2を使用することをお勧めします (Microsoftもこれを推奨しています)ただし、 smalldatetimeを使用する必要があるシナリオがいくつかある場合があります。 。

    これら2つのタイプの主な違いの概要を示す表を次に示します。

    機能 smalldatetime datetime2
    SQL準拠(ANSIおよびISO 8601) いいえ はい
    日付範囲 1900-01-01から2079-06-06 0001-01-01から9999-12-31
    時間範囲 00:00:00から23:59:59 00:00:00から23:59:59.9999999
    文字の長さ 最大19ポジション 最小19ポジション
    最大27ポジション
    ストレージサイズ 4バイト、固定 精度に応じて6〜8バイト*

    *精度を格納するためのプラス1バイト

    精度 1分 100ナノ秒
    フラクショナルセカンドプレシジョン いいえ はい
    ユーザー定義の分数秒精度 いいえ はい
    タイムゾーンオフセット なし なし
    タイムゾーンオフセットの認識と保存 いいえ いいえ
    夏時間対応 いいえ いいえ

    「datetime2」の利点

    上記の表に示されているように、 datetime2 タイプには、 smalldatetimeよりも多くの利点があります 、含む:

    • より広い日付範囲
    • 秒の精度
    • オプションのユーザー指定の精度
    • より高い精度
    • SQL標準(ANSIおよびISO 8601)に準拠

    *場合によってはdatetime2 valueは、精度を格納するために追加のバイトを使用しますが、データベースに格納される場合、精度は列定義に含まれるため、実際に格納された値は追加のバイトを必要としません。

    「datetime」と「smalldatetime」のどちらを使用する必要がありますか?

    Microsoftはdatetime2を推奨しています 新しい仕事のために(そして上記と同じ理由で)

    したがって、 datetime2を使用する必要があります 、特別な理由がない限り(レガシーシステムでの作業など)。

    例1-基本的な比較

    datetime2の基本的な違いを示す簡単な例を次に示します。 およびsmalldatetime

    DECLARE 
      @thedatetime2 datetime2(7), 
      @thesmalldatetime smalldatetime;
    SET @thedatetime2 = '2025-05-21 10:15:30.5555555';
    SET @thesmalldatetime = @thedatetime2;
    SELECT 
      @thedatetime2 AS 'datetime2',
      @thesmalldatetime AS 'smalldatetime';
    

    結果:

    +-----------------------------+---------------------+
    | datetime2                   | smalldatetime       |
    |-----------------------------+---------------------|
    | 2025-05-21 10:15:30.5555555 | 2025-05-21 10:16:00 |
    +-----------------------------+---------------------+
    

    ここでは、 smalldatetimeを設定します datetime2と同じ値に変数 変数。これにより、値が smalldatetimeに変換されます その後、SELECTを使用できます 各変数の値を確認するステートメント。

    この場合、 datetime2 変数は7のスケールを使用します。これは、小数点以下7桁であることを意味します。 smalldatetime 一方、価値はありません 小数位。さらに、秒はゼロに設定され、分は切り上げられます。

    Microsoftの公式ドキュメントには、smalldatetimeと記載されているため、これは予想されることです。 の時間は1日24時間に基づいており、秒は常にゼロ(:00)であり、小数秒はありません。 。

    したがって、 datetime2 typeは、はるかに正確で正確な日付/時刻の値を提供します。

    もちろん、これらすべての秒数は必要ないかもしれません。 datetime2の良いところの1つ つまり、必要な秒数(ある場合)を指定できます。

    例2–小数点以下の桁数を使用する

    この例では、 datetime2を減らします 0にスケール:

    DECLARE 
      @thedatetime2 datetime2(0), 
      @thesmalldatetime smalldatetime;
    SET @thedatetime2 = '2025-05-21 10:15:30.5555555';
    SET @thesmalldatetime = @thedatetime2;
    SELECT 
      @thedatetime2 AS 'datetime2',
      @thesmalldatetime AS 'smalldatetime';
    

    結果:

    +---------------------+---------------------+
    | datetime2           | smalldatetime       |
    |---------------------+---------------------|
    | 2025-05-21 10:15:31 | 2025-05-21 10:16:00 |
    +---------------------+---------------------+
    

    この場合、 datetime2 値に小数部分が含まれなくなりました。両方のタイプが同じ文字長(19ポジション)を共有するようになりました。

    しかし、まだ違いがあります。

    datetime2 値は秒の値を尊重しますが、この場合、その秒は切り上げられています。前述のように、 smalldatetime 値の秒コンポーネントは常にゼロに設定されており、この場合、その分は切り上げられています。

    datetime2の理由 秒の成分が切り上げられるのは、小数部が5以上であるためです。小数部分を減らすと、丸めは実行されません:

    DECLARE 
      @thedatetime2 datetime2(0), 
      @thesmalldatetime smalldatetime;
    SET @thedatetime2 = '2025-05-21 10:15:30.4444444';
    SET @thesmalldatetime = @thedatetime2;
    SELECT 
      @thedatetime2 AS 'datetime2',
      @thesmalldatetime AS 'smalldatetime';
    

    結果:

    +---------------------+---------------------+
    | datetime2           | smalldatetime       |
    |---------------------+---------------------|
    | 2025-05-21 10:15:30 | 2025-05-21 10:16:00 |
    +---------------------+---------------------+
    

    ただし、 smalldatetime 値の分は引き続き切り上げられます。

    例3–文字列リテラルからの値の設定

    前の例では、 smalldateime 値は、 datetime2と同じ値に設定することによって割り当てられました 価値。これを行うと、SQL Serverは、データが新しいデータ型に「適合する」ために暗黙的な変換を実行します。

    ただし、同じ文字列リテラルを smalldatetimeに割り当てようとすると 変数の場合、エラーが発生します:

    DECLARE 
      @thedatetime2 datetime2(0), 
      @thesmalldatetime smalldatetime
    SET @thedatetime2 = '2025-05-21 10:15:30.4444444'
    SET @thesmalldatetime = '2025-05-21 10:15:30.4444444'
    SELECT 
      @thedatetime2 AS 'datetime2',
      @thesmalldatetime AS 'smalldatetime';
    

    結果:

    Msg 295, Level 16, State 3, Line 5
    Conversion failed when converting character string to smalldatetime data type.
    

    これは、 smalldatetime 小数秒が3秒以下の文字列リテラルのみを受け入れます。

    anyの文字列リテラルは受け入れられないと思われるかもしれません。 分数秒は含まれていませんが、そうではありません。幸いにも3秒を受け入れますが、それ以上は受け入れません。

    したがって、この問題を克服するには、小数部分を小数点以下3桁(またはそれ以下)に減らす必要があります。

    DECLARE 
      @thedatetime2 datetime2(0), 
      @thesmalldatetime smalldatetime;
    SET @thedatetime2 = '2025-05-21 10:15:30.4444444';
    SET @thesmalldatetime = '2025-05-21 10:15:30.444';
    SELECT 
      @thedatetime2 AS 'datetime2',
      @thesmalldatetime AS 'smalldatetime';
    

    結果:

    +---------------------+---------------------+
    | datetime2           | smalldatetime       |
    |---------------------+---------------------|
    | 2025-05-21 10:15:30 | 2025-05-21 10:16:00 |
    +---------------------+---------------------+
    

    datetime2 スケール0を使用している場合でも、タイプにはこの制限はありません。

    例4–ストレージサイズ

    smalldatetime データ型のストレージサイズは4バイトに固定されています。これは、 smalldatetimeの数少ないメリットの1つです。 datetime2を超えています 。

    datetime2 精度に応じて、6、7、または8バイトのいずれかになります。つまり、 datetime2 値は常にsmalldatetimeよりも少なくとも2バイト多くのストレージを使用します 値。

    Microsoftは、 datetime2 typeは、精度を格納するために1バイト余分に使用します。この場合、 smalldatetimeより少なくとも3バイト多く使用します。 。

    ただし、これはおそらく、テーブルに格納するか変数に格納するか、およびバイナリ定数に変換するかどうかによって異なります。

    DATALENGTH()を使用するとどうなりますか 各値に使用されたバイト数を返す関数:

    DECLARE 
      @thedatetime2 datetime2(0), 
      @thesmalldatetime smalldatetime;
    SET @thedatetime2 = '2025-05-21 10:15:30';
    SET @thesmalldatetime = @thedatetime2;
    SELECT 
      DATALENGTH(@thedatetime2) AS 'datetime2',
      DATALENGTH(@thesmalldatetime) AS 'smalldatetime';
    

    結果

    +-------------+-----------------+
    | datetime2   | smalldatetime   |
    |-------------+-----------------|
    | 6           | 4               |
    +-------------+-----------------+
    

    しかし、それらを varbinaryに変換すると 、次のようになります:

    DECLARE 
      @thedatetime2 datetime2(0), 
      @thesmalldatetime smalldatetime;
    SET @thedatetime2 = '2025-05-21 10:15:30';
    SET @thesmalldatetime = @thedatetime2;
    SELECT 
      DATALENGTH(CAST(@thedatetime2 AS varbinary(10))) AS 'datetime2',
      DATALENGTH(CAST(@thesmalldatetime AS varbinary(10))) AS 'smalldatetime';
    

    結果

    +-------------+-----------------+
    | datetime2   | smalldatetime   |
    |-------------+-----------------|
    | 7           | 4               |
    +-------------+-----------------+
    

    つまり、 datetime2 varbinaryに変換されるときに余分なバイトを使用します 。多くの開発者は、 varbinaryへの変換を想定しています SQLServerが実際に日付と時刻の値を格納する方法を表しています。

    ただし、これは部分的にしか当てはまりません。 SQL Serverが日付と時刻の値を16進数で格納しているのは事実ですが、その16進値には実際には精度が含まれていません。これは、精度が列定義に含まれているためです。しかし、 varbinaryに変換すると 前の例で行ったように、精度が付加され、これにより余分なバイトが追加されます。

    次の例はこれを示しています。これは、データがデータベース列に格納されている場合、 datetime2の長さが6バイトになることを示しています。 vs smalldatetimeの場合は4バイト 。

    例5–保存されたデータのストレージサイズ

    この例では、データベースを作成し、COL_LENGTHを使用します 各列の長さをバイト単位で返します。次に、 datetime2を挿入します およびsmalldatetime 値を入力し、DBCC PAGE()を使用します ページファイル内の実際のデータの長さを検索します。これは、各データ型がデータベースに保存されるときに使用するストレージスペースを示しています。

    データベースを作成します:

    CREATE DATABASE CompareTypes;
    

    テーブルを作成します:

    USE CompareTypes;
    
    CREATE TABLE Datetime2vsSmalldatetime (
        TheDateTime2 datetime2(0),
        TheSmallDateTime smalldatetime
        );
    

    この場合、2つの列を作成します。1つは datetime2(0)です。 列ともう1つはsmalldatetime 列。

    列の長さを確認する

    各列の長さ(バイト単位)を確認してください:

    SELECT 
      COL_LENGTH ( 'dbo.Datetime2vsSmalldatetime' , 'TheDateTime2' ) AS 'datetime2',
      COL_LENGTH ( 'dbo.Datetime2vsSmalldatetime' , 'TheSmallDateTime' ) AS 'smalldatetime';  
    

    結果:

    +-------------+-----------------+
    | datetime2   | smalldatetime   |
    |-------------+-----------------|
    | 6           | 4               |
    +-------------+-----------------+
    

    したがって、 datetime2(0) smalldatetime と比較して、列の長さは6バイトです。 の長さは4バイトです。

    データを挿入

    次に、SQLServerに保存された実際の日付と時刻の値のストレージサイズを見てみましょう。 DBCC PAGE()を使用できます データファイルの実際のページを検査します。

    ただし、最初に、列にデータを挿入する必要があります。

    データの挿入:

    DECLARE @thedatetime2 datetime2 = '2025-05-21 10:15:30';
    INSERT INTO Datetime2vsSmalldatetime ( TheSmallDateTime, TheDateTime2 )
    SELECT @thedatetime2, @thedatetime2;
    

    データを選択します(確認するためだけに):

    SELECT * FROM Datetime2vsSmalldatetime;
    

    結果:

    +---------------------+---------------------+
    | TheDateTime2        | TheSmallDateTime    |
    |---------------------+---------------------|
    | 2025-05-21 10:15:30 | 2025-05-21 10:16:00 |
    +---------------------+---------------------+
    

    DBCC PAGE()の使用

    ここでDBCC PAGE()を使用します データファイルの実際のページを検査します。

    まず、DBCC IND()を使用します PagePIDを見つけるには:

    DBCC IND('CompareTypes', 'dbo.Datetime2vsSmalldatetime', 0);
    

    結果(垂直出力を使用):

    -[ RECORD 1 ]-------------------------
    PageFID         | 1
    PagePID         | 308
    IAMFID          | NULL
    IAMPID          | NULL
    ObjectID        | 1205579333
    IndexID         | 0
    PartitionNumber | 1
    PartitionID     | 72057594043039744
    iam_chain_type  | In-row data
    PageType        | 10
    IndexLevel      | NULL
    NextPageFID     | 0
    NextPagePID     | 0
    PrevPageFID     | 0
    PrevPagePID     | 0
    -[ RECORD 2 ]-------------------------
    PageFID         | 1
    PagePID         | 344
    IAMFID          | 1
    IAMPID          | 308
    ObjectID        | 1205579333
    IndexID         | 0
    PartitionNumber | 1
    PartitionID     | 72057594043039744
    iam_chain_type  | In-row data
    PageType        | 1
    IndexLevel      | 0
    NextPageFID     | 0
    NextPagePID     | 0
    PrevPageFID     | 0
    PrevPagePID     | 0
    

    これにより、2つのレコードが返されます。 PageType of 1(2番目のレコード)に関心があります。そのレコードからPagePIDが必要です。この場合、PagePIDは 344 です。 。

    これで、そのPagePIDを取得して、次の場所で使用できます。

    DBCC TRACEON(3604, -1);
    DBCC PAGE(CompareTypes, 1, 344, 3);
    

    これにより大量のデータが生成されますが、主に次の部分に関心があります。

    Slot 0 Column 1 Offset 0x4 Length 6 Length (physical) 6
    
    TheDateTime2 = 2025-05-21 10:15:30  
    
    Slot 0 Column 2 Offset 0xa Length 4 Length (physical) 4
    
    TheSmallDateTime = 2025-05-21 10:16:00.000                                          
    

    これは、 smalldatetime 長さは4バイトで、 datetime2(0) データベースに保存すると6バイトになります。

    したがって、この場合、2バイトの違いしかありませんが、 datetime2(0) より正確で、ANSIおよびISO8601規格に準拠しています。


    1. MariaDBでのCOERCIBILITY()の仕組み

    2. Postgresで再帰的なJSONキーを収集する

    3. EntityFrameworkをインストールせずに動作するようにODP.NETをデプロイおよび構成する

    4. ORA-29285の解決方法:ファイル書き込みエラー