从不存在的内连接中插入选择

时间:2016-05-04 15:29:17

标签: sql sql-server tsql

我有这个SQL Server代码。除了重复具有相同RightsIdUserId的行外,一切正常。 where not exists子句不起作用。 任何帮助表示赞赏。

INSERT INTO dbo.UserAccessRights (Id, UserId, RightType, RightsId, CreatedOn, CreatedBy)
    SELECT DISTINCT 
        NEWID(),
        @changedUserId,
        N'Process ' + @rightsTypeSuffix,
        ptm.ProcessInstance_id,
        getdate(),
        @loggedInUserId
    FROM 
        dbo.ProcessTeamMembers ptm WITH (NOLOCK)
    INNER JOIN 
        dbo.Users u WITH (NOLOCK) ON ptm.TeamMemberProfile_id = u.ProfileID
                                  AND u.Id = @changedUserId
                                  AND ptm.TenantId = @tenantId
    INNER JOIN 
        dbo.ProcessInstances p_i WITH (NOLOCK) ON p_i.Id = ptm.ProcessInstance_id
                                               AND p_i.DeletedOn IS NULL
    WHERE 
        NOT EXISTS (SELECT * 
                    FROM UserAccessRights uar WITH (NOLOCK) 
                    WHERE uar.UserId = @changedUserId 
                      AND uar.RightsId = ptm.ProcessInstance_id)

2 个答案:

答案 0 :(得分:1)

您的重复项可能来自查询,而不是来自表中的现有行。可能的问题是select distinct没有做任何事情 - 因为newid()始终是唯一的。

我的建议是将id列更改为默认值newid()。然后您不需要插入它,select distinct将起作用。如果没有,您可以修复查询:

INSERT INTO dbo.UserAccessRights (Id, UserId, RightType, RightsId, CreatedOn, CreatedBy)
    SELECT DISTINCT NEWID(), @changedUserId, N'Process ' + @rightsTypeSuffix,
           ProcessInstance_id, getdate(), @loggedInUserId
    FROM (SELECT DISTINCT ptm.ProcessInstance_id
          FROM dbo.ProcessTeamMembers ptm WITH (NOLOCK) INNER JOIN 
               dbo.Users u WITH (NOLOCK)
               ON ptm.TeamMemberProfile_id = u.ProfileID AND
                  u.Id = @changedUserId AND
                ptm.TenantId = @tenantId INNER JOIN 
               dbo.ProcessInstances p_i WITH (NOLOCK)
               ON p_i.Id = ptm.ProcessInstance_id AND
                  p_i.DeletedOn IS NULL
          WHERE NOT EXISTS (SELECT 1
                            FROM UserAccessRights uar WITH (NOLOCK) 
                            WHERE uar.UserId = @changedUserId AND   
                                  uar.RightsId = ptm.ProcessInstance_id
                           )
    ) t;

嗯,正如我想的那样,也许你应该使用TOP 1而不是SELECT DISTINCT。我不确定哪些列导致了distinct上的问题,但是您在许多列中插入了相同的值,因此多行可能会导致问题。

答案 1 :(得分:0)

尝试"左排除加入" (参见Visual Representation of SQL Joins)而不是WHERE NOT EXISTS子句。

INSERT INTO dbo.UserAccessRights (Id, UserId, RightType, RightsId, CreatedOn, CreatedBy)
    SELECT DISTINCT 
        NEWID(),
        @changedUserId,
        N'Process ' + @rightsTypeSuffix,
        ptm.ProcessInstance_id,
        getdate(),
        @loggedInUserId
    FROM 
        dbo.ProcessTeamMembers ptm 
    INNER JOIN 
        dbo.Users u ON ptm.TeamMemberProfile_id = u.ProfileID
                                  AND u.Id = @changedUserId
                                  AND ptm.TenantId = @tenantId
    INNER JOIN 
        dbo.ProcessInstances p_i ON p_i.Id = ptm.ProcessInstance_id
                                               AND p_i.DeletedOn IS NULL
    LEFT JOIN UserAccessRights uar
        ON uar.UserId = u.Id
            AND uar.RightsId = ptm.ProcessInstance_id
    WHERE 
        uar.Id IS NULL -- Replace with the actual pkey on UserAccessRights if not Id