在删除循环行时更新具有特定ID的表行

时间:2013-06-13 11:06:51

标签: sql sql-server tsql

我有2张桌子

表名:Attributes

attribute_id  |   attribute_name

    1               attr_name_1
    2               attr_name_2
    3               attr_name_1
    4               attr_name_2

表名:Products

product_id    |   product_name    |    attribute_id
    1              prod_name_1              1
    2              prod_name_2              2
    3              prod_name_3              3
    4              prod_name_4              4

如果您看到,表attribute_id中的Products具有以下ID (1,2,3,4),而不是(1,2,1,2)

问题出在表Attributes中,即有不同ID的重复值(attribute_names),所以我想:

  1. 从表Attributes
  2. 中选择重复的一个ID
  3. 使用“已挑选” ID更新表格Products(仅限attribute_idAttributes中具有相同名称的情况)
  4. 之后,删除表Attributes中没有用的表格中的重复值Products
  5. 输出:

    表名:Attributes

    attribute_id  |   attribute_name
         1              attr_name_1
         2              attr_name_2
    

    表名:Products

    product_id    |   product_name    |    attribute_id
         1             prod_name_1              1
         2             prod_name_2              2
         3             prod_name_3              1
         4             prod_name_4              2
    
    SQLFiddle

    上的

    演示

    注意:

    如果我使用sql而不是手动修复此问题,它会对我有很大的帮助。

2 个答案:

答案 0 :(得分:4)

update Products
set attribute_id = (
    select min(attribute_id)
    from Attributes a
    where a.attribute_name=(select attribute_name from Attributes a2 where a2.attribute_id=Products.attribute_id)
);


DELETE
FROM Attributes
WHERE attribute_id NOT IN
(
    SELECT MIN(attribute_id)
    FROM Attributes
    GROUP BY attribute_name
);

答案 1 :(得分:1)

以下内容可能比@Alexander Sigachov's suggestion更快,但它至少需要SQL Server 2005来运行它,而Alexander的解决方案可以在任何(合理)版本的SQL Server上运行。尽管如此,即使只是为了提供替代方案,你也可以去:

WITH Min_IDs AS (
  SELECT
    attribute_id,
    min_attribute_id = MIN(attribute_id) OVER (PARTITION BY attribute_name)
  FROM Attributes
)
UPDATE p
SET    p.attribute_id = a.min_attribute_id
FROM   Products p
JOIN   Min_IDs  a ON a.attribute_id = p.attribute_id
WHERE  a.attribute_id <> a.min_attribute_id
;

DELETE FROM Attributes
WHERE attribute_id NOT IN (
  SELECT attribute_id
  FROM   Products
  WHERE  attribute_id IS NOT NULL
)
;

第一个语句的CTE返回一个行集,其中每个attribute_id映射到同一个attribute_id的最小attribute_name。通过加入此映射集,UPDATE语句使用它来替换{​​{1}}表中的attribute_id

当后来从Products删除时,仅检查Attributes列中是否找不到Attributes.attribute_id就足够了,这就是第二个语句的作用。也就是说,此时不需要分组和聚合,如另一个答案所示。

Products.attribute_id条件被添加到第二个查询的子查询中,以防该列可以为空并且可能确实包含NULL。在这种情况下需要过滤掉NULL,否则它们的存在会导致WHERE attribute_id IS NOT NULL谓词对NOT IN的评估,SQL Server会将其视为UNKNOWN(因此 no 行将被有效删除)。如果FALSE中不能有NULL,则可能会丢弃该条件。