用于删除存储过程中重复项的用户定义值

User Defined Value for Deleting Duplicates in Stored Procedure

我目前正在使用以下代码:

ALTER PROCEDURE [dbo].[sp_TidyBasket]
    @ReferenceNumber VARCHAR
AS
BEGIN
    BEGIN TRANSACTION

    DECLARE
        @GUID VARCHAR,
        @ErrorCode INT

    --Get the First Reference Number of a basket item being duplicated
    SET @GUID = (SELECT TOP 1 MIN(idx6) 
                 FROM iwfAccountOpening 
                 WHERE Idx29 = @ReferenceNumber 
                 GROUP BY Idx37 
                 HAVING COUNT(*) > 1)   

    --Executes a while loop whilst there is duplicates to be removed
    WHILE (@GUID IS NOT NULL)
    BEGIN
        DELETE FROM iwfAccountOpening WHERE Idx6 = @GUID;
    END

    --Rollbacks transactions when any errors occur
    SELECT @ErrorCode = @@ERROR

    IF (@ErrorCode <> 0) GOTO PROBLEM
    COMMIT TRANSACTION

PROBLEM:
    IF (@ErrorCode <> 0) BEGIN
        ROLLBACK TRANSACTION
    END
END

我希望它根据传递给它的定义值循环并删除重复项(同时保留一行重复数据)。

目前我的数据库没有显示任何变化 table。我知道这是由于我设置的 @GUID 值造成的,但我不知道如何解决这个问题。

这不是前面提到的重复问题的重复问题,因为它侧重于删除用户设置的具有重复项的约束。

试试这个。无需循环。

 DELETE FROM iwfAccountOpening WHERE Idx6 in (SELECT MIN(idx6) 
                 FROM iwfAccountOpening 
                 WHERE Idx29 = @ReferenceNumber 
                 GROUP BY Idx37 
                 HAVING COUNT(*) > 1) and Idx29 = @ReferenceNumber 

您可以通过以下示例查询找到所有重复记录

SELECT YourColumn, COUNT(*) TotalCount
FROM YourTable
GROUP BY YourColumn
HAVING COUNT(*) > 1
ORDER BY COUNT(*) DESC

在你的情况下你也可以这样做

Delete from iwfAccountOpening Where Idx29 in
 (           SELECT Count(idx6) 
             FROM iwfAccountOpening 
             WHERE   Idx29 = @ReferenceNumber
             GROUP BY Idx6,Idx37 
             HAVING COUNT(*) > 1 
             ORDER BY COUNT(*) DESC )
   )

本次循环:

WHILE (@GUID IS NOT NULL)
BEGIN
    DELETE FROM iwfAccountOpening WHERE Idx6 = @GUID;
END

看起来很奇怪。

首先,如果 @GUID 不为空 - 这将是无限循环,因为你 不修改 @GUID 内部循环。

其次 - 此删除语句不会帮助您实现目标 "delete all duplicate except one" - 只是因为在这里您只删除了一条您之前确定的具有 GUID 的记录。

按照你的逻辑,应该是这样的

DELETE FROM iwfAccountOpening 
WHERE Idx29 = @ReferenceNumber and idx6 <> @GUID

而且不需要周期。

另外 SELECT TOP 1 MIN(idx6) 对我来说看起来有点多余。它可以只是 SELECT MIN(idx6),你会得到相同的结果。

试试这个:

ALTER PROCEDURE [dbo].[sp_TidyBasket]
    @ReferenceNumber VARCHAR
AS
    BEGIN TRY

        BEGIN TRANSACTION;

            WITH    cte
                      AS ( SELECT   idx6 ,
                                    ROW_NUMBER() OVER ( PARTITION BY Idx37 ORDER BY ( SELECT ( 1 ) ) ) AS RN
                           FROM     iwfAccountOpening
                           WHERE    Idx29 = @ReferenceNumber
                         )
            DELETE  i
            FROM    cte c
                    JOIN iwfAccountOpening i ON c.idx6 = i.idx6
            WHERE   Idx29 = @ReferenceNumber AND RN > 1

        COMMIT TRANSACTION

    END TRY
    BEGIN CATCH  

        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION

    END CATCH                
GO