首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >SQL Server游标-无法正确分配变量

SQL Server游标-无法正确分配变量
EN

Stack Overflow用户
提问于 2018-05-31 02:54:52
回答 1查看 108关注 0票数 0

我使用SQL Server 2016。我需要将用户从旧系统转移到新系统。但是在从遗留系统引入所有用户之前,我需要检查他们在我们的新系统中是否还不存在。这样的确定是基于每个系统中用户的电子邮件地址的比较来完成的。

因此,如果新系统中不存在用户,我需要将这样的记录从旧系统插入到新系统中。但如果用户确实存在,我需要用旧系统中的数据更新新系统中的一些列。

为了完成这个任务,我在SCOPE_IDENTITY()中使用了一个游标。

此外,我还需要在每次游标迭代中记录新插入的和现有的更新记录。问题是我的代码没有区分新的和现有的记录,因此它在日志表中插入了两次所有用户id。一次是userID (@ContactID)为空(新系统中不存在),另一次是userID (@ContactID)不为空-存在于新系统中。

在下面的示例中,我有1条记录在新系统中不存在,3条记录已经匹配。因此,在IF (@CoantactID IS NULL)中,我打算只将新插入的记录插入到MyDB.dbo.Contact表记录中,而在IF (@CoantactID IS NOT NULL)中,在日志表中插入的只是在新系统中匹配(存在)的树记录。

但问题是,即使在this IF (@ContactID is NULL)和for in IF (@ContactID IS NOT NULL)中,它也会将所有四个ContactID插入到日志表中。

代码语言:javascript
复制
;USE [MyDB];
GO

-- exec dbo.sp_UserMigration_Users_Copy
DROP PROCEDURE IF EXISTS dbo.sp_UserMigration_Users_Copy
GO

;USE [MyDB];
GO

CREATE  PROCEDURE dbo.sp_UserMigration_Users_Copy
 @UserID UNIQUEIDENTIFIER = NULL
 --,@ContactID INT

AS 

DECLARE @Email nvarchar(100),
        @ContactID INT;
-- @UserID UNIQUEIDENTIFIER,

DECLARE @SysID INT
SET @SysId = 17511; -- system contactID

---- creating log table 
--CREATE TABLE #T 
--(
-- UserID UNIQUEIDENTIFIER NOT NULL,
-- Email NVARCHAR(50) NOT NULL 
--);

SELECT * INTO #T 
FROM MyDB.dbo.User
WHERE UserID IN (   
                        '0604C514',
                        'C1FDAF34', 
                        '23BABE2D',
                        'EBA21D10'
                    ); 

IF NOT EXISTS (select * from MyDB.sys.tables where name = N'UserIDContactIDMigrationLog')

    CREATE TABLE MyDB.dbo.UserIDContactIDMigrationLog
        (
            UserID UNIQUEIDENTIFIER /* CONSTRAINT [PK_UserIDContactIDMigrationLog_UserID] PRIMARY KEY */ NOT NULL,  -- somehow inserts duplicate UserIDs 
            ContactId INT /*UNIQUE CONSTRAINT [UNIQUE_ContactId] */ NOT NULL,
            CreatedDt DATETIME2 NULL,
            UpdatedDt DATETIME2 NULL,
            UpdatedFlag BIT /*CONSTRAINT [DF_MigratedFlag] DEFAULT(0) */ NULL
        );

-- -----------------------------------------------------
-- Cursor: For all contacts to be migrated
-- -----------------------------------------------------
IF (SELECT CURSOR_STATUS('global','user_cursor')) >= -1
 BEGIN
  IF (SELECT CURSOR_STATUS('global','user_cursor')) > -1
   BEGIN
    CLOSE user_cursor
   END
 DEALLOCATE user_cursor
END

DECLARE user_cursor CURSOR
    FOR 
        SELECT a.UserID, LTRIM(RTRIM(a.Email)) AS Email
        FROM #T a WITH (NOLOCK)      
        --WHERE a.UserID = @UserID

-- begin cursor loop
OPEN user_cursor
FETCH NEXT FROM user_cursor INTO @UserID, @Email

WHILE @@FETCH_STATUS = 0
BEGIN

    SELECT @ContactID = (
        SELECT c.ContactId
        FROM MyDB.dbo.Contact c 
        LEFT OUTER JOIN MyDB.dbo.Login l ON c.ContactId = l.ContactId  
        WHERE (LTRIM(RTRIM(c.ContactEmailTx)) = @Email 
                OR LTRIM(RTRIM(l.ContactLoginNameTx)) = @Email 
                --OR l.ContactLoginNameTx LIKE @Email+'%'  -- this concept does not work in case of leading space at the ContactLoginNameTx so need to use the code below 
                OR SUBSTRING(LTRIM(RTRIM(l.ContactLoginNameTx)), -1, CHARINDEX('.INACTIVE.', l.ContactLoginNameTx)) = @Email)
        AND (c.ContactEmailTx != '' OR c.ContactEmailTx IS NOT NULL OR l.ContactLoginNameTx != '' OR l.ContactLoginNameTx IS NOT NULL)
                        )

-- check if a contact is new
    IF (@ContactID IS NULL)
    BEGIN
        -- -----------------------------------------------------
        -- MyDB.dbo.Contact
        -- -----------------------------------------------------
        INSERT INTO [MyDB].[dbo].[Contact]
            (   
                [ContactFirstNameTx],
                [ContactLastNameTx],
                [ContactEmailTx],
                [ContactTitleTx],
                [ContactCreateDt],
                [ContactCreateByID],
                [ContactCreateLoginTypeID]
            )
        SELECT 
                [FirstName],
                [LastName],
                [Email],
                [Title],
                --[AccountId],
                [UserCreatedDate],
                @SysId AS [ContactCreateByID],  -- as as flag for import [ContactCreateLoginTypeID]
                -10 AS [ContactCreateLoginTypeID]
        FROM #T o WITH (NOLOCK) 
        WHERE UserID = @UserID 

        SET @ContactID = SCOPE_IDENTITY()
    END
--   select * from  [MyDB].[dbo].[Contact] where contactid in ( 1051364, 466440, 560466, 618576)
    -- -----------------------------------------------------
    --MyDB.dbo.Login
    -- -----------------------------------------------------
    INSERT INTO [MyDB].[dbo].[Login]          
    (   
        ContactID,
        [ContactLoginNameTx], -- V.C. this is email. the field is has a unique constraint
        [ContactLoginActiveIn],
        [ContactLoginCreateDt],
        [ContactLoginCreateByID],
        [ContactLoginCreateLoginTypeID],
        [ContactLoginPasswordLastChangeDt],
        [ContactLoginLastLoginDt],
        [ContactLoginPasswordExclusionIn] -- this is not nullable and BIT
    )
    SELECT 
        @ContactID AS ContactID,
        [Email],
        CASE WHEN [UserStatusID] IN (1, 3) THEN 1 ELSE 0 END AS [ContactLoginActiveIn], -- v.c. in Onvia 1 is Active, 2 - Inactive, 3 - Invited, 4 - Inactive By System, 5 - Pending Registration
        [UserCreatedDate],
        @SysId AS ContactLoginCreateByID,  -- as as flag for Onvia import[ContactCreateLoginTypeID]
        -10 AS [ContactLoginCreateLoginTypeID],
        [UserLastPasswordChangedDate],
        [UserLastLoginDate],
        0 as ContactLoginPasswordExclusionIn -- this is not nullable and BIT
    FROM #T o WITH (NOLOCK) 
    WHERE UserID = @UserID
    AND NOT EXISTS (select * from MyDB.dbo.Login z where z.ContactID = @ContactID)

    -- -----------------------------------------------------
    -- Activate any inactive users 
    -- -----------------------------------------------------

    IF EXISTS (select * from MyDB.dbo.Login where ContactLoginActiveIn = 0 and ContactID = @ContactID)
        AND NOT EXISTS (select * from MyDB.dbo.Login where ContactLoginActiveIn = 1 and ContactID = @ContactID)
    BEGIN
        UPDATE [MyDB].[dbo].[Login]
        SET ContactLoginNameTx = @Email,
            ContactLoginActiveIn = (select case when [UserStatusID] IN (1, 3) then 1 else 0 end 
                                        from #T o where o.UserID = @UserID) 
        WHERE ContactID = @ContactID
    END

    -- -----------------------------------------------------
    --MyDB.dbo.ContactPhoneNumber
    -- -----------------------------------------------------
    INSERT INTO [MyDB].[dbo].[PhoneNumber]        
    (   
        ContactID,
        PhoneNumberTypeID,
        ContactPhoneNumberValueTx 
    )

    SELECT 
        @ContactID AS ContactID,
        1 AS PhoneNumberTypeID,
        ISNULL([PhoneNumber1],'') AS ContactPhoneNumberValueTx
    FROM #T o WITH (NOLOCK) 
    WHERE o.UserID = @UserID 
    AND NOT EXISTS (select * from [MyDB].[dbo].[PhoneNumber] z where z.ContactID = @ContactID);

    -- -----------------------------------------------------
    --MyDB.dbo.ContactOrg
    -- -----------------------------------------------------
    INSERT INTO [MyDB].[dbo].[Org]      
    (   
        ContactID,
        OrgID
    )
    SELECT 
        @ContactID AS ContactID,
        b.OrgID AS OrgID
    FROM #T o WITH (NOLOCK) 
    INNER JOIN ImportQueue.dbo.OnviaAccountIDOrgIDMigrationLog b WITH (NOLOCK) ON o.AccountId = b.OnviaAccountID
    WHERE o.UserID = @UserID 
    AND NOT EXISTS (select * from [MyDB].[dbo].[Org] z where z.ContactID = @ContactID);

    -- -----------------------------------------------------
    ---- MyDB.dbo.UserIDContactIDMigrationLog
    ---- log output for new users
    -- -----------------------------------------------------

    INSERT INTO MyDB.dbo.UserIDContactIDMigrationLog
    (
        UserID,
        ContactId,
        CreatedDt,
        UpdatedFlag
    )
    VALUES 
    (
        @UserID,
        @ContactID,
        GETDATE(),
        0 
    )

        -- -----------------------------------------------------
        --  EXISTING MATCHED USERS
        -- -----------------------------------------------------
            -- check if a contact is existing
    IF (@ContactID IS NOT NULL)
    BEGIN
        -- -----------------------------------------------------
        -- MyDB.dbo.Contact
        -- -----------------------------------------------------
        UPDATE MyDB.dbo.Contact
        SET ContactFirstNameTx =
                CASE 
                    WHEN ContactFirstNameTx NOT IN ('', NULL) THEN c.FirstName
                    ELSE ContactFirstNameTx
                END,
            ContactLastNameTx = 
                CASE 
                    WHEN ContactLastNameTx IN ('', NULL) THEN c.LastName
                    ELSE ContactLastNameTx
                END,
            ContactEmailTx = 
                CASE 
                    WHEN ContactEmailTx IN ('', NULL) THEN c.Email
                    ELSE ContactEmailTx
                END,
            ContactTitleTx =
                CASE 
                    WHEN ContactTitleTx IN ('', NULL) THEN c.Title
                    ELSE ContactTitleTx
                END,
            [ContactCreateDt] =
                CASE 
                    WHEN ContactCreateDt IN ('', NULL) THEN c.UserCreatedDate
                    ELSE ContactCreateDt
                END,
            [ContactModifyByID] = @SysId,
            [ContactModifyLoginTypeID] = - 10

        FROM #T c
            WHERE UserID = @UserID 
            AND ContactID = @ContactID;
    -- -----------------------------------------------------
    ---- MyDB.dbo.UserIDContactIDMigrationLog
    ---- log output for existing matched users
    -- -----------------------------------------------------

            INSERT INTO MyDB.dbo.UserIDContactIDMigrationLog 
             (
                 UserID,
                 ContactId,
                 UpdatedDt,
                 UpdatedFlag
             )

            VALUES 
             (
                @UserID,
                @ContactID,
                GETDATE(),
                1 
             );

        FETCH NEXT FROM user_cursor INTO @UserID, @Email

        -- end cursor loop

    END
END

CLOSE user_cursor
        DEALLOCATE user_cursor

GO
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-05-31 03:38:52

尝试下面的代码,而不是游标。

代码语言:javascript
复制
- exec dbo.sp_UserMigration_Users_Copy
    DROP PROCEDURE IF EXISTS dbo.sp_UserMigration_Users_Copy
    GO

    ;USE [MyDB];
    GO

    CREATE  PROCEDURE dbo.sp_UserMigration_Users_Copy
     @UserID UNIQUEIDENTIFIER = NULL
     --,@ContactID INT

    AS 

    DECLARE @Email nvarchar(100),
            @ContactID INT;


    DECLARE @SysID INT
    SET @SysId = 17511; 

    CREATE TABLE #T 
    (
    ID INT IDENTITY(1,1) NOT NULL,
     UserID NVARCHAR(50)NOT NULL,
     Email NVARCHAR(50) NOT NULL 
    );
    INSERT INTO #T 
    SELECT * 
    FROM MyDB.dbo.User
    WHERE UserID IN (   
                            '0604C514',
                            'C1FDAF34', 
                            '23BABE2D',
                            'EBA21D10'
                        ); 

    IF NOT EXISTS (select * from MyDB.sys.tables where name = N'UserIDContactIDMigrationLog')

        CREATE TABLE MyDB.dbo.UserIDContactIDMigrationLog
            (
                UserID UNIQUEIDENTIFIER /* CONSTRAINT [PK_UserIDContactIDMigrationLog_UserID] PRIMARY KEY */ NOT NULL,  -- somehow inserts duplicate UserIDs 
                ContactId INT /*UNIQUE CONSTRAINT [UNIQUE_ContactId] */ NOT NULL,
                CreatedDt DATETIME2 NULL,
                UpdatedDt DATETIME2 NULL,
                UpdatedFlag BIT /*CONSTRAINT [DF_MigratedFlag] DEFAULT(0) */ NULL
            );


    DECLARE @COUNT INT 
    DECLARE @I INT = 1
    DECLARE @UserID NVARCHAR(50) ;
    DECLARE @Email NVARCHAR(50)
    SELECT @COUNT = COUNT(*) FROM #T
    WHILE(@I <= @COUNT)

    BEGIN 
            SELECT @UserID = UserID, @Email= LTRIM(RTRIM(Email)) FROM #T WHERE ID = @I   


        SELECT @ContactID = (
            SELECT c.ContactId
            FROM MyDB.dbo.Contact c 
            LEFT OUTER JOIN MyDB.dbo.Login l ON c.ContactId = l.ContactId  
            WHERE (LTRIM(RTRIM(c.ContactEmailTx)) = @Email 
                    OR LTRIM(RTRIM(l.ContactLoginNameTx)) = @Email 
                    --OR l.ContactLoginNameTx LIKE @Email+'%'  -- this concept does not work in case of leading space at the ContactLoginNameTx so need to use the code below 
                    OR SUBSTRING(LTRIM(RTRIM(l.ContactLoginNameTx)), -1, CHARINDEX('.INACTIVE.', l.ContactLoginNameTx)) = @Email)
            AND (c.ContactEmailTx != '' OR c.ContactEmailTx IS NOT NULL OR l.ContactLoginNameTx != '' OR l.ContactLoginNameTx IS NOT NULL)
                            )

    -- check if a contact is new
        IF (@ContactID IS NULL)
        BEGIN
            -- -----------------------------------------------------
            -- MyDB.dbo.Contact
            -- -----------------------------------------------------
            INSERT INTO [MyDB].[dbo].[Contact]
                (   
                    [ContactFirstNameTx],
                    [ContactLastNameTx],
                    [ContactEmailTx],
                    [ContactTitleTx],
                    [ContactCreateDt],
                    [ContactCreateByID],
                    [ContactCreateLoginTypeID]
                )
            SELECT 
                    [FirstName],
                    [LastName],
                    [Email],
                    [Title],
                    --[AccountId],
                    [UserCreatedDate],
                    @SysId AS [ContactCreateByID],  -- as as flag for Onvia import[ContactCreateLoginTypeID]
                    -10 AS [ContactCreateLoginTypeID]
            FROM #T o WITH (NOLOCK) 
            WHERE UserID = @UserID 

            SET @ContactID = SCOPE_IDENTITY()
        END
    --   select * from  [MyDB].[dbo].[Contact] where contactid in ( 1051364, 466440, 560466, 618576)
        -- -----------------------------------------------------
        --MyDB.dbo.Login
        -- -----------------------------------------------------
        INSERT INTO [MyDB].[dbo].[Login]          
        (   
            ContactID,
            [ContactLoginNameTx], -- V.C. this is email. the field is has a unique constraint
            [ContactLoginActiveIn],
            [ContactLoginCreateDt],
            [ContactLoginCreateByID],
            [ContactLoginCreateLoginTypeID],
            [ContactLoginPasswordLastChangeDt],
            [ContactLoginLastLoginDt],
            [ContactLoginPasswordExclusionIn] -- this is not nullable and BIT
        )
        SELECT 
            @ContactID AS ContactID,
            [Email],
            CASE WHEN [UserStatusID] IN (1, 3) THEN 1 ELSE 0 END AS [ContactLoginActiveIn], -- v.c. in Onvia 1 is Active, 2 - Inactive, 3 - Invited, 4 - Inactive By System, 5 - Pending Registration
            [UserCreatedDate],
            @SysId AS ContactLoginCreateByID,  -- as as flag for Onvia import[ContactCreateLoginTypeID]
            -10 AS [ContactLoginCreateLoginTypeID],
            [UserLastPasswordChangedDate],
            [UserLastLoginDate],
            0 as ContactLoginPasswordExclusionIn -- this is not nullable and BIT
        FROM #T o WITH (NOLOCK) 
        WHERE UserID = @UserID
        AND NOT EXISTS (select * from MyDB.dbo.Login z where z.ContactID = @ContactID)

        -- -----------------------------------------------------
        -- Activate any inactive users 
        -- -----------------------------------------------------

        IF EXISTS (select * from MyDB.dbo.Login where ContactLoginActiveIn = 0 and ContactID = @ContactID)
            AND NOT EXISTS (select * from MyDB.dbo.Login where ContactLoginActiveIn = 1 and ContactID = @ContactID)
        BEGIN
            UPDATE [MyDB].[dbo].[Login]
            SET ContactLoginNameTx = @Email,
                ContactLoginActiveIn = (select case when [UserStatusID] IN (1, 3) then 1 else 0 end 
                                            from #T o where o.UserID = @UserID) 
            WHERE ContactID = @ContactID
        END

        -- -----------------------------------------------------
        --MyDB.dbo.ContactPhoneNumber
        -- -----------------------------------------------------
        INSERT INTO [MyDB].[dbo].[PhoneNumber]        
        (   
            ContactID,
            PhoneNumberTypeID,
            ContactPhoneNumberValueTx 
        )

        SELECT 
            @ContactID AS ContactID,
            1 AS PhoneNumberTypeID,
            ISNULL([PhoneNumber1],'') AS ContactPhoneNumberValueTx
        FROM #T o WITH (NOLOCK) 
        WHERE o.UserID = @UserID 
        AND NOT EXISTS (select * from [MyDB].[dbo].[PhoneNumber] z where z.ContactID = @ContactID);

        -- -----------------------------------------------------
        --MyDB.dbo.ContactOrg
        -- -----------------------------------------------------
        INSERT INTO [MyDB].[dbo].[Org]      
        (   
            ContactID,
            OrgID
        )
        SELECT 
            @ContactID AS ContactID,
            b.OrgID AS OrgID
        FROM #T o WITH (NOLOCK) 
        INNER JOIN ImportQueue.dbo.OnviaAccountIDOrgIDMigrationLog b WITH (NOLOCK) ON o.AccountId = b.OnviaAccountID
        WHERE o.UserID = @UserID 
        AND NOT EXISTS (select * from [MyDB].[dbo].[Org] z where z.ContactID = @ContactID);

        -- -----------------------------------------------------
        ---- MyDB.dbo.UserIDContactIDMigrationLog
        ---- log output for new users
        -- -----------------------------------------------------

        INSERT INTO MyDB.dbo.UserIDContactIDMigrationLog
        (
            UserID,
            ContactId,
            CreatedDt,
            UpdatedFlag
        )
        VALUES 
        (
            @UserID,
            @ContactID,
            GETDATE(),
            0 
        )

            -- -----------------------------------------------------
            --  EXISTING MATCHED USERS
            -- -----------------------------------------------------
                -- check if a contact is existing
        IF (@ContactID IS NOT NULL)
        BEGIN
            -- -----------------------------------------------------
            -- MyDB.dbo.Contact
            -- -----------------------------------------------------
            UPDATE MyDB.dbo.Contact
            SET ContactFirstNameTx =
                    CASE 
                        WHEN ContactFirstNameTx NOT IN ('', NULL) THEN c.FirstName
                        ELSE ContactFirstNameTx
                    END,
                ContactLastNameTx = 
                    CASE 
                        WHEN ContactLastNameTx IN ('', NULL) THEN c.LastName
                        ELSE ContactLastNameTx
                    END,
                ContactEmailTx = 
                    CASE 
                        WHEN ContactEmailTx IN ('', NULL) THEN c.Email
                        ELSE ContactEmailTx
                    END,
                ContactTitleTx =
                    CASE 
                        WHEN ContactTitleTx IN ('', NULL) THEN c.Title
                        ELSE ContactTitleTx
                    END,
                [ContactCreateDt] =
                    CASE 
                        WHEN ContactCreateDt IN ('', NULL) THEN c.UserCreatedDate
                        ELSE ContactCreateDt
                    END,
                [ContactModifyByID] = @SysId,
                [ContactModifyLoginTypeID] = - 10

            FROM #T c
                WHERE UserID = @UserID 
                AND ContactID = @ContactID;
        -- -----------------------------------------------------
        ---- MyDB.dbo.UserIDContactIDMigrationLog
        ---- log output for existing matched users
        -- -----------------------------------------------------

                INSERT INTO MyDB.dbo.UserIDContactIDMigrationLog 
                 (
                     UserID,
                     ContactId,
                     UpdatedDt,
                     UpdatedFlag
                 )

                VALUES 
                 (
                    @UserID,
                    @ContactID,
                    GETDATE(),
                    1 
                 );




        END
 SET @I = @I+1;
    END
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50611659

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档