我有一个从数据库中删除用户的过程:
CREATE PROCEDURE [dbo].[sp_removeUser]
@UserId uniqueidentifier
,@result int OUT
AS
BEGIN
SET NOCOUNT ON
SET @Result=0
-- whether User exists
IF NOT EXISTS(SELECT 1 FROM [dbo].[Users] (nolock) WHERE UserId = @UserId)
RETURN
-- Prevent to remove admin
IF EXISTS(SELECT 1 FROM [dbo].[aspnet_Users] (nolock) WHERE UserId= @UserId AND UserName = 'admin' )
RETURN
BEGIN TRAN
-- Remove User Addresses
DELETE FROM [dbo].[AddressesUserAccess] WHERE AddressId IN (SELECT AddressId FROM Addresses WHERE UserId = @UserId)
DELETE FROM [dbo].[AddressesInGroups] WHERE AddressId IN (SELECT AddressId FROM Addresses WHERE UserId = @UserId)
DELETE FROM [dbo].[Addresses] WHERE UserId = @UserId
-- Remove User Numbers
DELETE FROM [dbo].[NumbersUserAccess] WHERE NumberId IN (SELECT NumberId FROM Numbers WHERE UserId = @UserId)
DELETE FROM [dbo].[NumbersInGroups] WHERE NumberId IN (SELECT NumberId FROM Numbers WHERE UserId = @UserId)
DELETE FROM [dbo].[Numbers] WHERE UserId = @UserId
...
... and lots more below...
...
我想删除一大堆用户,所以我首先想到的是获取我要删除的所有UserID的列,然后迭代,依次删除每个用户。
然而,在阅读了有关如何执行此操作的其他一些问题之后,我明白这不是首选的方法,而是我应该寻找更基于集合的解决方案。
那么,实现此过程以更加基于集合的方式工作的更好方法是什么?
答案 0 :(得分:1)
您可以使用拆分功能,例如
CREATE FUNCTION dbo.SplitGUIDs
(
@List VARCHAR(MAX)
)
RETURNS TABLE
AS
RETURN
(
SELECT Item = CONVERT(UNIQUEIDENTIFIER, Item)
FROM
(
SELECT Item = x.i.value('(./text())[1]', 'VARCHAR(36)')
FROM
(
SELECT [XML] = CONVERT(XML, '<i>'
+ REPLACE(@List, ',', '</i><i>')
+ '</i>').query('.')
) AS a
CROSS APPLY
[XML].nodes('i') AS x(i)
) AS y
WHERE Item IS NOT NULL
);
GO
然后你的程序只需稍微改变(虽然我强烈建议不要使用sp_前缀):
CREATE PROCEDURE dbo.RemoveUsers
@UserList VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @u TABLE(UserID UNIQUEIDENTIFIER PRIMARY KEY);
INSERT @u
SELECT DISTINCT i.Item
FROM dbo.SplitGUIDs(@UserList) AS i
INNER JOIN dbo.Users AS u
ON u.UserID = i.Item
WHERE NOT EXISTS
(
SELECT 1 FROM dbo.aspnet_users
WHERE UserID = i.Item
AND Username = 'Admin'
);
-- now all your delete statements can use IN instead of =
DELETE ... WHERE UserID IN (SELECT UserID FROM @u);
END
GO
您可能必须从应用程序层或其他地方构建以逗号分隔的GUID列表,但您可以像这样调用过程:
EXEC dbo.RemoveUsers
@UserList = '89E31B4B-68B5-4B7B-B226-F51BE388F815,C947AE20-DEC1-4EBC-A838-CCCE033BD1FF'
请注意,如果任何元素不是有效的GUID,它将会爆炸。