「SELECT @@ IDENTITY」が小数を返すのはなぜですか?


24

Dapperを使用して、ASP.NET MVC 3(.NET 4.0)アプリケーションからSQL Server 2008 R2 Expressインスタンスに対して次のクエリを実行しています。

INSERT INTO Customers (
         Type, Name, Address, ContactName, 
         ContactNumber, ContactEmail, Supplier)
VALUES (
         @Type, @Name, @Address, @ContactName, 
         @ContactNumber, @ContactEmail, @Supplier)

SELECT @@IDENTITY

への呼び出しconnection.Query<int>(sql, ...)は、無効なキャスト例外をスローしています。デバッグしましたが、DapperがGetValue返されたを呼び出す時点SqlDataReaderです。

の戻り値の型GetValueObject、デバッガーショーでそれを検査し、それがボックス10進数であることを示します。

selectをに変更するとSELECT CAST(@@IDENTITY as int)、GetValueの戻り値はボックス化されたintになり、例外はスローされません。

Id列は間違いなくint型です。なぜSELECT @@IDENTITY小数を返すのですか?

追加情報:

  • データベースは真新しいです。
  • Customersテーブルは、私がそれに追加した唯一のオブジェクトです。データベースには、他の(ユーザー)テーブル、ビュー、トリガー、またはストアドプロシージャはありません。
  • データベースには10行があり、IDは1,2,3,4,5,6,7,8,9,10です(つまり、列はintの制限を超えていません)。

私のテーブル定義は

CREATE TABLE [dbo].[Customers](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Type] [int] NOT NULL,
    [Name] [nvarchar](255) NOT NULL,
    [Address] [nvarchar](1000) NOT NULL,
    [ContactName] [nvarchar](255) NOT NULL,
    [ContactNumber] [nvarchar](50) NOT NULL,
    [ContactEmail] [nvarchar](255) NOT NULL,
    [Supplier] [nvarchar](255) NOT NULL,
 CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (
    PAD_INDEX  = OFF, 
    STATISTICS_NORECOMPUTE  = OFF, 
    IGNORE_DUP_KEY = OFF, 
    ALLOW_ROW_LOCKS  = ON, 
    ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Customersテーブルにトリガーがありますか?
リチャード

3
@@ IDENTITYの代わりにSCOPE_IDENTITY()を使用します。@@ IDENTITYは、現在のスコープではなく、現在の接続上のすべてのものによって作成された最後のID値を提供します。したがって、Richardが示唆したように、別のテーブルを変更してIDを生成するトリガーは、@@ IDENTITYの戻り値に影響します。
ニックチャンマス

DBにはトリガーがありません。これは新しいデータベースであり、Customersテーブルは私が作成した唯一のテーブルです。
グレッグB

@Greg B:これは関数の戻り値の型です。(質問が示唆するように)戻り値の型としてint / bigintを期待していましたか、またはこの関数のMSの選択に疑問を持っていますか?
マリアン

回答:


28
  1. @@ identityはnumeric(38,0)を返します。intにするには、キャストする必要があります。

    SELECT CAST(@@ identity AS INT)

  2. また、代わりにscope_identityを使用してみてください。Customersテーブルにトリガーがある場合、別のテーブルから最後のIDを取得することになります。

  3. 最後に、dapperを使用しているので、すべてをストアドプロシージャ内にラップして、同じバッチ内でIDの挿入と選択の実行が保証されるようにします。

    理論的には、これらの両方を単独で実行するためにほとんどの時間機能するはずです。ただし、データベースに2回アクセスする必要がある場合は、問題が発生する可能性があります。(たとえば、これは接続プーリングでどのように機能しますか?接続のドロップについてはどうでしょうか。など)ストアドプロシージャですべてを投げるだけであれば、その余分な労力を心配する必要はありません。


#3をありがとう。アドホック SQLステートメントでバッチを定義する方法はありませんか?
グレッグB

私はそれをもう一度見ていた。1つの呼び出しにすべてのステートメントを含めると、すべて1つのバッチになります。ステートメントを別々の呼び出しに分割すると、バグが発生する可能性があります。
リチャード

3
SCOPE_IDENTITY()を推奨するための+1
アンドリュービッカートン

10

テーブルの作成は言う:

IDENTITY

新しい列がID列であることを示します。新しい行がテーブルに追加されると、Microsoft®SQL Server™は列に一意の増分値を提供します。ID列は通常、PRIMARY KEY制約と組み合わせて使用​​され、テーブルの一意の行識別子として機能します。IDENTITYプロパティは、tinyint、smallint、int、bigint、decimal(p、0)、またはnumeric(p、0)列に割り当てることができます。テーブルごとに1つのID列のみを作成できます。バインドされたデフォルトとDEFAULT制約は、ID列では使用できません。シードと増分の両方を指定するか、どちらも指定しないでください。どちらも指定されていない場合、デフォルトは(1,1)です。

シード

テーブルにロードされる最初の行に使用される値です。

インクリメント

ロードされた前の行のID値に追加される増分値です。」

したがって、システム関数@@ identityは、最もカバーするタイプに対処する必要があります。


そして、これがnumeric最も広い範囲を持っているのでそれが戻る理由です。ありがとう
グレッグB

3
関数に複数の戻り値型を含めることはできません。すべての可能性を含めるには、最も幅の広いタイプを使用する必要があります。
マリアン

6

「SELECT @@ IDENTITYが小数を返す理由」

に収まるには大きすぎるかもしれないのでint、それはID列の型と一致したが、リチャードが言うように、数値(38,0)を返します(しない- numericdecimal 同義語です

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.