列中每个值的调用过程?

时间:2011-09-06 16:35:42

标签: sql-server-2005

我有一个从数据库中删除用户的过程:

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的列,然后迭代,依次删除每个用户。

然而,在阅读了有关如何执行此操作的其他一些问题之后,我明白这不是首选的方法,而是我应该寻找更基于集合的解决方案。

那么,实现此过程以更加基于集合的方式工作的更好方法是什么?

1 个答案:

答案 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,它将会爆炸。