0

我目前正在研究一个 DataImport 脚本,该脚本旨在将数据从一个数据库移动到另一个数据库。我遇到的主要问题是有问题的表包含很多重复的记录,重复的字段是产品代码、语言、立法、品牌名称、公式和版本,即我们可能在数据库中有以下内容:

我的测试产品,英语,英国,测试品牌,测试公式,1(ID 1 - 不包括在分组依据中)
我的测试产品,英语,英国,测试品牌,测试公式,1(ID 2 - 不包括在分组依据中)
我的测试产品,英语,英国,测试品牌,测试公式,1(ID 3 - 不包括在分组依据中)
我的测试产品,英语,英国,测试品牌,测试公式,1(ID 4 - 不包括在分组依据中)

如您所见,这些记录在各个方面都是相同的。我的问题是,作为数据加载脚本的一部分,我希望删除 ID 为 1、2 和 3 的记录,同时保留 ID 为 4 的记录,因为这将是最新的记录,因此是我想保留。为此,我编写了一个 T-SQL 脚本,如下所示:

-- get the list of items where there is at least one duplicate
DECLARE cDuplicateList CURSOR FOR
SELECT productcode, languageid, legislationid, brandName, versionnumber, formulaid
FROM allproducts
GROUP BY productcode, languageid, legislationid, brandName, versionnumber, formulaid
HAVING COUNT (*) > 1  

OPEN cDuplicateList

FETCH cDuplicateList INTO @productCode, @languageId, @legislationId, @brandName, @versionNumber, @formulaId

-- while there are still duplicates
WHILE @@FETCH_STATUS=0
BEGIN

-- delete from the table where the product ID is in the sub-query, which contains all
-- of the records apart from the last one
DELETE FROM AllProducts 
WHERE productId IN
(
    SELECT productId
    FROM allProducts
    WHERE productCode = @productCode 
        AND (languageId = @languageId OR @languageId IS NULL) 
        AND (legislationId = @legislationId OR @legislationId IS NULL)
        AND (brandName = @brandName OR @brandName IS NULL)
        AND (versionNumber = @versionNumber OR @versionNumber IS NULL)
        AND (formulaId = @formulaId OR @formulaId IS NULL)
    EXCEPT
    SELECT TOP 1 productId
    FROM allProducts
    WHERE productCode = @productCode 
        AND (languageId = @languageId OR @languageId IS NULL) 
        AND (legislationId = @legislationId OR @legislationId IS NULL)
        AND (brandName = @brandName OR @brandName IS NULL)
        AND (versionNumber = @versionNumber OR @versionNumber IS NULL)
        AND (formulaId = @formulaId OR @formulaId IS NULL)
)

FETCH cDuplicateList INTO @productCode, @languageId, @legislationId, @brandName, @versionNumber, @formulaId

END

现在,这确实有效 - 它非常慢,我想不出任何简单的方法来让它更快。有谁知道如何保持相同的功能但让它运行得更快?

4

3 回答 3

3

您已经可以在 SQL_Server 2005 中使用common-table-expressionand了:ROW_NUMBER

WITH CTE AS
(
    SELECT ProductCode, Language, Legislation, BrandName, Formula, Version,
       RN = ROW_NUMBER() 
                   OVER ( 
                     PARTITION BY productcode, language, legislation, brandname, formula, version 
                     ORDER BY id DESC) 
    FROM dbo.Students
)
DELETE FROM CTE WHERE RN > 1

如果您想查看要删除的内容,请更改DELETE为。SELECT *

于 2013-10-08T11:02:11.580 回答
0

假设您的 productId 列是唯一 ID:

delete  p1
from    AllProducts p1
join    AllProducts p2
on      p1.languageId = p2.languageId
and     p1.legislationId = p2.legislationId
and     p1.brandName = p2.brandName
and     p1.versionNumber = p2.versionNumber
and     p1.formulaId = p2.formulaId
and     p1.productId < p2.productId

这将删除所有匹配的最新记录。

如果要删除符合某些条件的记录(例如,仅品牌名称和版本号,则从联接中删除其他子句)。

于 2013-10-10T14:22:46.427 回答
0

您可以使用 row_number() 覆盖(按产品代码、语言 ID、立法 ID、品牌名称、版本号、按产品 ID 顺序排列的公式 ID 顺序)并删除 row_number > 1 的所有产品

于 2013-10-08T11:02:14.973 回答