2011-04-19 34 views
4

在存储过程中,我使用INSERT动态创建查询。这是为了强制默认值(如果它是NULL,则使用@name)。从动态INSERT获取IDENTITY

SET @sql = 'INSERT INTO table (username, password' 
    + CASE @name IS NULL THEN '' ELSE ',name' END 
    + ') VALUES (''root'',''gelehallon''' + 
    + CASE @name IS NULL THEN '' ELSE ',''@name''' END 
    + ')' 
EXEC sp_executesql @sql 

SET @id = SCOPE_IDENTITY() 

@id无论如何都是0。
即使另一个线程同时运行相同的存储过程,如何以安全方式检索IDENTITY?

+0

为什么你动态创建一个存储过程的查询? – 2011-04-19 08:09:42

+0

这是一种强制未传递到存储过程的字段上的默认值的方法。假设我可能需要@name,但是如果不通过,它应该默认为表格的默认值。因此,我动态构建它,如果没有传递,则删除@name。 – ANisus 2011-04-19 08:12:44

回答

10
SET @sql = 'INSERT INTO table (username, password) VALUES (@username,@pwd) 
    SELECT @id = SCOPE_IDENTITY()' 
EXEC sp_executesql @sql, 
    N'@username VARCHAR(50), @pwd VARCHAR(50), @id INTEGER OUTPUT', 
    'root', 'gelehallon', @id OUTPUT 

-- @id now has SCOPE_IDENTITY() value in 

虽然几点:
- 假设这是因为似乎没有成为一个需要使用动态SQL在这个例子中
一个简单的例子 - 假设你不打算用来存储实时密码在纯文本中的数据库!

+0

*笑*不,这是一个简化的例子,不,我正在使用salt和Sha1进行加密。别担心。但谢谢你的答案! – ANisus 2011-04-19 08:18:22

+0

SHA1不再被视为安全。 SHA-2在SQL Server 2012及更高版本中,或者您可以使用一些更加安全的方式(例如bcrypt),并付出一些额外的努力。 – reedstonefood 2016-03-22 12:33:31

1

或者,您可以使用带有INSERT语句的OUTPUT子句。这将导致动态语句,并因此用于调用它的系统存储过程返回一个行集(在你的情况下是一行)。您可以抓住机会并将行集插入到表变量中,然后读取该值。

基本上,它可能是这样的:

SET @sql = 'INSERT INTO table (...) OUTPUT inserted.ID VALUES (...)'; 
DECLARE @ScopeIdentity (ID int); 
INSERT INTO @ScopeIdentity 
    EXEC sp_executesql @sql; 
SELECT @id = ID FROM @ScopeIdentity;