为什么“ 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调用return GetValue的时候SqlDataReader

返回类型GetValueObject,在调试器中检查它的显示类型是装箱的十进制数。

如果将select更改为SELECT CAST(@@IDENTITY as int),则GetValue的返回是装箱的int,并且不会引发异常。

Id列绝对是int类型;为什么要SELECT @@IDENTITY返回小数?

一些其他信息:

  • 该数据库是全新的。
  • 客户表是我添加到其中的唯一对象。数据库中没有其他(用户)表,视图,触发器或存储过程。
  • 数据库中有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]

您在“客户”表上是否有任何触发器?
理查德

3
我将使用SCOPE_IDENTITY()而不是@@ IDENTITY。@@ IDENTITY将为您提供由当前连接(而不是当前作用域)上的任何内容创建的最后一个身份值。因此,正如Richard所建议的那样,修改另一个表并生成标识的触发器将影响@@ IDENTITY的返回。
Nick Chammas

数据库中没有触发器。这是一个全新的数据库,Customers表是我创建的唯一表。
格雷格B

@Greg B:这是函数的返回类型。您是否希望将int / bigint作为返回类型(如问题所提示),或者您对此功能的MS选择表示疑问?
玛丽安

Answers:


28
  1. @@ identity返回一个数字(38,0)。您需要将其强制转换为整数。

    SELECT CAST(@@ identity AS INT)

  2. 另外,尝试改用scope_identity。如果“客户”表上有任何触发器,则最终可能会从另一个表中获取最后一个标识。

  3. 最后,由于您使用的是dapper,因此需要将所有包装在存储过程中,以确保执行同一批处理中的插入然后对标识进行选择。

    从理论上讲,它应该在大多数时间都可以自行执行。但是,如果您必须两次访问数据库,则可能会出现问题。(例如,这如何与连接池一起使用?断开的连接又如何?等等。)如果将其全部放入存储过程中,则无需担心将来会付出额外的努力。


感谢#3。没有办法在即席 SQL语句中定义批处理?
格雷格·B

我又看了一眼。如果一次调用中包含所有语句,则全部为一批。如果将语句分解为多个单独的调用,则可能会出现问题。
理查德

3
+1推荐SCOPE_IDENTITY()
安德鲁·比克顿

10

创建表说:

IDENTITY

指示新列是标识列。将新行添加到表中后,Microsoft®SQL Server™将为该列提供唯一的增量值。标识列通常与PRIMARY KEY约束结合使用,以用作表的唯一行标识符。可以将IDENTITY属性分配给tinyint,smallint,int,bigint,decimal(p,0)或numeric(p,0)列。每个表只能创建一个标识列。绑定的默认值和DEFAULT约束不能与Identity列一起使用。您必须同时指定种子和增量,或者都不指定。如果未指定,则默认为(1,1)。

种子

是用于加载到表中第一行的值。

增量

是将增量值添加到加载的上一行的标识值中。”

因此,系统函数@@ identity将必须处理最覆盖的类型。


这就是为什么它返回numeric的范围最广的原因..?谢谢
Greg B

3
一个函数不能有多个返回类型。它必须使用最广泛的类型来包含所有可能性。
玛丽安

6

“为什么SELECT @@ IDENTITY返回小数”

因为它可能太大而无法放入int-它与Identity列的类型不匹配,但是正如Richard所说的返回了numeric(38,0)(numeric并且decimal 是同义词

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.