我有一个包含SQL语句的存储过程,类似于:
CREATE PROCEDURE SaveUser
@UserName nvarchar(10),
@FirstName nvarchar(150),
@LastName nvarchar(150)
AS
BEGIN
INSERT INTO Users (UserName, FirstName, LastName)
VALUES (@UserName, @FirstName, @LastName)
SELECT SCOPE_IDENTITY()
END
有些用户无法登录系统,也没有用户名;但是,UserName字段上有一个唯一索引,所以我希望能够将用户ID#(一个自动增量字段)作为UserName插入。
是否有人知道MS SQL Server方法或变量可以让我做类似的事情?
INSERT INTO Users (UserName, FirstName, LastName)
VALUES (ISNULL(@UserName, SCOPE_IDENTITY()),@FirstName,@LastName)
编辑我现在的意图是使用类似下面的内容
DECLARE @NextID int
SET @NextID = IDENT_CURRENT(Users) + IDENT_INCR(Users)
INSERT INTO Users (UserName, FirstName, LastName)
VALUES (ISNULL(@UserName, @NextID), @FirstName, @LastName)
我想知道是否有内置方法可以保证这是一致的。
答案 0 :(得分:3)
INSERT NULL或随机字符串,然后使用scope_identity进行更新
INSERT INTO Users (UserName, FirstName, LastName)
VALUES (ISNULL(@UserName, CAST(NEWID() AS varchar(50)),@FirstName,@LastName)
UPDATE Users
SET @UserName = CAST(SCOPE_IDENTITY() AS int)
WHERE UserId = SCOPE_IDENTITY()
(道歉,如果newid没有直接投射......现在无法测试)
可以使用聚合进行一体化但快速连续不可靠(2次调用)等。
答案 1 :(得分:2)
您可以在检索时解决此问题,而不是复制ID列。例如,假设您为任意用户使用用户名为NULL。然后,您可以检索用户名,如:
select
UserName = IsNull(UserName,UserId)
from WebUsers
编辑:如果您喜欢名称上的UNIQUE约束,则可以使用计算列:
create table WebUsers (
id int identity,
name varchar(12),
uniqueid as isnull(name,id)
)
create unique index ix_webusers_uniqueid on WebUsers (uniqueid)
列uniqueid是一个计算列,只要您使用它就会转换为isnull(name,id)。使用此设置,您可以在一个查询中插入用户:
insert into WebUsers (name) values ('Dark Lord')
insert into WebUsers (name) values ('The Ring')
insert into WebUsers (name) values (NULL)
insert into WebUsers (name) values (NULL)
但不是重复用户;以下将挽救错误:
insert into WebUsers (name) values ('The Ring')
您可以在uniqueid上查询以查找指定用户的用户名,或查找任意用户的ID:
select uniqueid from WebUsers
答案 2 :(得分:1)
您可以添加AFTER INSERT触发器,使用插入的表格中的Identity列值更新UserName字段。
答案 3 :(得分:1)
对于使用SQL Server 2008或更高版本的任何人,有一项新功能可以非常轻松地解决此问题,无需进行任何应用程序或Proc更改:过滤索引。过滤的索引允许您在索引上放置WHERE条件,以便索引将忽略这些值。在这种情况下,即使在唯一索引中,也可以忽略空的UserName值。
语法如下:
CREATE UNIQUE INDEX IX_Users_UserName ON Users (UserName)
WHERE UserName is not null
使用Filtered Index解决此特定问题也意味着您不需要将垃圾数据放入UserName字段。
答案 4 :(得分:1)
如何将它包装在事务中,并将spid用于UserName。像这样:
CREATE PROC BlahBlah
...
BEGIN
BEGIN TRAN UserInsert
BEGIN TRY
INSERT INTO Users (UserName, FirstName, LastName)
VALUES (COALESCE(@UserName,@@SPID), @FirstName, @LastName)
IF @UserName IS NULL
BEGIN
DECLARE @MyUserID int
SET @MyUserID = (SELECT SCOPE_IDENTITY())
UPDATE Users
SET UserName = @MyUserID
WHERE UserID = @MyUserID
END
END TRY
BEGIN CATCH
ROLLBACK TRAN UserInsert
RETURN
END CATCH
COMMIT TRAN UserInsert
END
答案 5 :(得分:0)
必须分两步完成。在这种情况下,我只需使用NEWID()函数生成用于用户名的随机GUID值,然后使用update语句对其进行更新。由于您使用存储过程,因此在这种情况下使用的步骤数量不会导致重大问题。
有关NEWID及其使用的详细信息,请访问here
答案 6 :(得分:0)
如何将它包装在事务中,并将spid用于UserName。像这样:
CREATE PROC BlahBlah
...
BEGIN
BEGIN TRAN UserInsert
BEGIN TRY
INSERT INTO Users (UserName, FirstName, LastName)
VALUES (COALESCE(@UserName,@@SPID), @FirstName, @LastName)
IF @UserName IS NULL
BEGIN
DECLARE @MyUserID int
SET @MyUserID = (SELECT SCOPE_IDENTITY())
UPDATE Users
SET UserName = @MyUserID
WHERE UserID = @MyUserID
END
END TRY
BEGIN CATCH
ROLLBACK TRAN UserInsert
RETURN
END CATCH
COMMIT TRAN UserInsert
END
其他几点: - 这似乎是一个非常奇怪的要求。您可能想看看您的设计。 - 小心SCOPE_IDENTITY() issues with parallel query plans。 <{3}}子句目前更安全,直到bug得到解决。