Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在创建标识的同一个T-SQL语句中获取标识值?_Sql_Sql Server_Tsql_Sql Server 2008 R2_Identity Column - Fatal编程技术网

在创建标识的同一个T-SQL语句中获取标识值?

在创建标识的同一个T-SQL语句中获取标识值?,sql,sql-server,tsql,sql-server-2008-r2,identity-column,Sql,Sql Server,Tsql,Sql Server 2008 R2,Identity Column,我被问到是否可以有一个insert语句,它的ID字段是一个“identity”列,并且分配的值是否也可以插入同一记录中的另一个字段,即同一个insert语句中 这是否可能(SQL Server 2008r2) 谢谢。两者都可以。 要插入带有列“identity”的行,您需要设置identity\u insert off 请注意,您仍然不能复制值 您可以看到该命令。 请注意set identity\u insert on之后 要创建具有相同记录的表,只需: 创建新列 插入空值或其他内容 在插入后

我被问到是否可以有一个insert语句,它的ID字段是一个“identity”列,并且分配的值是否也可以插入同一记录中的另一个字段,即同一个insert语句中

这是否可能(SQL Server 2008r2)


谢谢。

两者都可以。

要插入带有列“identity”的行,您需要
设置identity\u insert off

请注意,您仍然不能复制值

您可以看到该命令。 请注意
set identity\u insert on
之后

要创建具有相同记录的表,只需:

  • 创建新列
  • 插入空值或其他内容
  • 在插入后使用标识列的值更新该列
如果需要同时插入值,可以使用
@@identity
全局变量。它会给你最后一次插入。所以我认为您需要执行一个
@@identity+1
。在这种情况下,它可能给出错误的值,因为
@@identity
适用于所有表。因此,如果插入发生在另一个具有标识的表中,则它将计数


另一个解决方案是获取max id并添加一个:),然后获得所需的值

您无法真正做到这一点-因为将用于
标识
列的实际值实际上只有在
插入
完成时才是固定的和设置的

但是,您可以使用触发器等

CREATE TRIGGER trg_YourTableInsertID ON dbo.YourTable 
AFTER INSERT
AS 
UPDATE dbo.YourTable
SET dbo.YourTable.OtherID = i.ID
FROM dbo.YourTable t2
INNER JOIN INSERTED i ON i.ID = t2.ID

这将在插入任何行后立即触发,并将
OtherID
列设置为插入行的
IDENTITY
列的值。但是严格来说,它不是在同一个语句中,而是在原始语句之后。

您可以通过在表中设置一个计算列来实现这一点:

 DECLARE    @QQ TABLE (ID INT IDENTITY(1,1), Computed AS ID PERSISTED, Letter VARCHAR (1))

INSERT INTO @QQ (Letter)
VALUES ('h'),
('e'),
('l'),
('l'),
('o')

SELECT  *
FROM    @QQ

1   1   h

2   2   e

3   3   l

4   4   l

5   5   o

关于勾选答案:


您无法真正做到这一点,因为将使用的实际值 对于标识列,实际上只有在插入 已经完成

马克我想,你实际上是不对的<是的,他能))

解决方法是
IDENT_CURRENT()

此外,您甚至可以使用
IDENT_CURRENT()
作为
默认约束
,例如,它可以代替
SCOPE_IDENTITY()
。试试这个:

CREATE TABLE TemporaryTable(
    Id int PRIMARY KEY IDENTITY(1,1) NOT NULL,
    FkId int NOT NULL DEFAULT IDENT_CURRENT('[TemporaryTable]')
)

ALTER TABLE TemporaryTable
    ADD CONSTRAINT [Fk_const] FOREIGN KEY (FkId) REFERENCES [TemporaryTable] ([Id])

INSERT INTO TemporaryTable (FkId) VALUES (DEFAULT)
INSERT INTO TemporaryTable (FkId) VALUES (DEFAULT)
INSERT INTO TemporaryTable (FkId) VALUES (DEFAULT)
INSERT INTO TemporaryTable (FkId) VALUES (DEFAULT)

UPDATE TemporaryTable 
   SET [FkId] = 3
 WHERE Id = 2

SELECT * FROM TemporaryTable

DROP TABLE TemporaryTable
使用这个简单的代码
`SCOPE_IDENTITY()+1

我知道原来的帖子是很久以前的了。但是,最顶级的解决方案是在插入记录后使用触发器更新字段,我认为有一种更有效的方法

用触发器来做这件事总是让我感到不安。似乎总有更好的办法。该触发器基本上使每个insert执行2次对数据库的写入,(1)insert,然后(2)第2个int的更新。该触发器还将连接回表中。特别是对于大型数据库和大型表,这会带来一些开销。我怀疑,随着表变大,这种方法的开销也会变大。也许我错了。但是,在一张大桌子上,这似乎不是一个好的解决方案

我编写了一个函数fn_GetIdent,可用于此。有趣的是,这是多么简单,但实际上是一些工作要弄清楚。我最终偶然发现了这一点。事实证明,在从INSERT语句集值赋值子句调用的函数中调用IDENT_CURRENT(@variableTableName)与直接从INSERT语句调用IDENT_CURRENT(@variableTableName)的行为不同。它使您可以为插入的记录获取新的标识值

有一个警告。当标识为NULL时(即,一个没有记录的空表),由于sys.identity\u columns.last\u值为NULL,它的行为略有不同。因此,您必须以稍微不同的方式处理输入的第一条记录。我在函数中添加了代码来解决这个问题,现在它可以工作了

这是因为对函数的每次调用,即使在同一个INSERT语句中,都在函数中自己的新“作用域”中。(我认为这是正确的解释)。因此,您甚至可以使用此函数使用一条insert语句插入多行。如果直接从INSERT语句调用IDENT_CURRENT(@variableTableName),它将为所有行中的newID分配相同的值。这是因为标识在整个INSERT语句完成处理(在同一范围内)后更新。但是,从函数中调用IDENT_CURRENT(@variableTableName)会导致每个insert使用输入的每一行更新标识值。但是,这一切都是在INSERT语句本身的函数调用中完成的。因此,一旦创建了函数,就很容易实现

这种方法是调用函数(从INSERT语句),从函数中读取sys.identity_columns.last_值(查看它是否为NULL以及是否存在记录),然后调用IDENT_CURRENT(@variableTableName),然后从函数返回INSERT语句以插入行。因此,它是一个小的读取(对于插入的每一行),然后是插入的一个写入,这比我认为的触发器方法的开销要小。如果对具有大型表的大型数据库中的所有表都使用触发器方法,则触发器方法可能会非常低效。与触发器相比,我还没有做过任何性能分析。但是,我认为这会更有效率,尤其是在大桌子上

我一直在测试,这似乎在所有情况下都有效。我希望得到反馈,了解是否有人发现了这种方法不起作用的地方,或者这种方法是否存在任何问题。任何人都可以在这种方法中打洞吗?如果有,请告诉我。如果没有,你能投赞成票吗?我认为这是一个更好的选择
CREATE TABLE TemporaryTable(
    Id int PRIMARY KEY IDENTITY(1,1) NOT NULL,
    FkId int NOT NULL DEFAULT IDENT_CURRENT('[TemporaryTable]')
)

ALTER TABLE TemporaryTable
    ADD CONSTRAINT [Fk_const] FOREIGN KEY (FkId) REFERENCES [TemporaryTable] ([Id])

INSERT INTO TemporaryTable (FkId) VALUES (DEFAULT)
INSERT INTO TemporaryTable (FkId) VALUES (DEFAULT)
INSERT INTO TemporaryTable (FkId) VALUES (DEFAULT)
INSERT INTO TemporaryTable (FkId) VALUES (DEFAULT)

UPDATE TemporaryTable 
   SET [FkId] = 3
 WHERE Id = 2

SELECT * FROM TemporaryTable

DROP TABLE TemporaryTable
IF OBJECT_ID('dbo.fn_GetIdent') IS NOT NULL 
  DROP FUNCTION dbo.fn_GetIdent; 
GO

CREATE FUNCTION dbo.fn_GetIdent(@inTableName AS VARCHAR(MAX))
RETURNS Int
WITH EXECUTE AS CALLER
AS
BEGIN

    DECLARE @tableHasIdentity AS Int
    DECLARE @tableIdentitySeedValue AS Int  

    /*Check if the tables identity column is null - a special case*/
    SELECT 
        @tableHasIdentity = CASE identity_columns.last_value WHEN NULL THEN 0 ELSE 1 END,
        @tableIdentitySeedValue = CONVERT(int, identity_columns.seed_value)
    FROM sys.tables
    INNER JOIN sys.identity_columns
    ON tables.object_id = identity_columns.object_id
    WHERE identity_columns.is_identity = 1
    AND tables.type = 'U'
    AND tables.name = @inTableName;


    DECLARE @ReturnValue AS Int;
    SET @ReturnValue = CASE @tableHasIdentity WHEN 0 THEN @tableIdentitySeedValue
                            ELSE IDENT_CURRENT(@inTableName) 
                            END;

    RETURN (@ReturnValue);

END

GO

/* The function above only has to be created the one time to be used in the example below */

DECLARE @TableHasRows AS Bit

DROP TABLE IF EXISTS TestTable

CREATE TABLE TestTable (ID INT IDENTITY(1,1), 
                        New INT, 
                        Letter VARCHAR (1))

INSERT INTO TestTable (New, Letter)
VALUES  (dbo.fn_GetIdent('TestTable'), 'H')

INSERT INTO TestTable (New, Letter)
VALUES  (dbo.fn_GetIdent('TestTable'), 'e')

INSERT INTO TestTable (New, Letter)
VALUES  (dbo.fn_GetIdent('TestTable'), 'l'),
        (dbo.fn_GetIdent('TestTable'), 'l'),
        (dbo.fn_GetIdent('TestTable'), 'o') 
               
INSERT INTO TestTable (New, Letter)
VALUES  (dbo.fn_GetIdent('TestTable'), ' '),
        (dbo.fn_GetIdent('TestTable'), 'W'),
        (dbo.fn_GetIdent('TestTable'), 'o'),
        (dbo.fn_GetIdent('TestTable'), 'r'),
        (dbo.fn_GetIdent('TestTable'), 'l'),
        (dbo.fn_GetIdent('TestTable'), 'd')


INSERT INTO TestTable (New, Letter)
VALUES  (dbo.fn_GetIdent('TestTable'), '!')

SELECT * FROM TestTable

/*

Result
ID  New Letter
1   1   H
2   2   e
3   3   l
4   4   l
5   5   o
6   6    
7   7   W
8   8   o
9   9   r
10  10  l
11  11  d
12  12  !

*/