【问题标题】:Multiple update and deletes in multiple tables SQL server多个表SQL Server中的多次更新和删除
【发布时间】:2018-02-21 18:00:05
【问题描述】:

我有四个表,分别是 City、Location、Customer 和 Shop。设计此数据库的人已使主键自动递增。因此,DB超时存在冗余数据。我正在尝试清理数据库,但更新和删除行需要很长时间。表格示例如下所示:

Table 1: City: ID_city(PK)
| City      | ID_City |
|-----------|---------|
| Chennai   | 1       |
| Benagluru | 2       |
| Chennai   | 3       |
| Delhi     | 4       |
| Chennai   | 5       |
| Bengaluru | 6       |

Table 2: Location: ID_Location(PK), ID_City(FK)
| Zip  | ID_location        | ID_City |
|------|--------------------|---------|
| 0001 | 1                  | 1       |
| 0011 | 2                  | 2       |
| 0002 | 3                  | 1       |
| 0021 | 4                  | 3       |
| 0003 | 5                  | 1       |
| 0012 | 6                  | 2       |
| 0001 | 7 (duplicate of 1) | 1       |

Table 3: Customer: Cust_ID(PK), ID_Location(FK)
| Cust_ID | ID_location |
|---------|-------------|
| 1       | 1           |
| 2       | 3           |
| 3       | 5           |
| 4       | 2           |
| 5       | 7           |

Table 4: Shop: Shop_ID(PK), ID_Location(FK)
| Shop_ID | ID_location |
|---------|-------------|
| 1       | 1           |
| 2       | 2           |
| 3       | 6           |
| 4       | 3           |
| 5       | 7           |

预期表格:

Table 1: City: ID_city(PK)
| City      | ID_City |
|-----------|---------|
| Chennai   | 1       |
| Benagluru | 2       |
| Delhi     | 4       |

Table 2: Location: ID_Location(PK), ID_City(FK)
| Zip  | ID_Location | ID_City |
|------|-------------|---------|
| 0001 | 1           | 1       |
| 0011 | 2           | 2       |
| 0002 | 3           | 1       |
| 0021 | 4           | 1       |
| 0003 | 5           | 1       |
| 0012 | 6           | 2       |

Table  3: Customer: Cust_ID(PK), ID_Location(FK)
| Cust_ID | ID_Location |
|---------|-------------|
| 1       | 1           |
| 2       | 3           |
| 3       | 5           |
| 4       | 2           |
| 5       | 1           |

Table 4: Shop: Shop_ID(PK), ID_Location(FK)
| Shop_ID | ID_Location |
|---------|-------------|
| 1       | 1           |
| 2       | 2           |
| 3       | 6           |
| 4       | 3           |
| 5       | 1           |

如您所见,到处都有重复记录,需要 3 个更新语句(使用连接)和 2 个删除语句才能删除 1 个重复的城市。 有没有办法减少执行此任务的 SQL 语句数量?

我写的查询是:

  1. 更新客户集 ID_location = 1 其中 Cust_ID = 5
  2. 更新商店集 ID_location = 1 其中 Shop_ID = 5
  3. 从 ID_location = 7 的位置删除
  4. 更新位置集 ID_City = 1 其中 ID_City = 3 或 ID_City = 5
  5. 从 ID_Location = 3 或 ID_Location = 5 的城市中删除

这是删除 1 个重复的 City,City 表中大约有 1300 个重复。有没有一种简单的方法来检查重复项、更新并最终删除?

【问题讨论】:

  • 您能否重新格式化您的数据示例
  • 花费大量时间是什么意思? (a) 编写查询的时间或 (b) 执行查询的时间。如果(a),不,你不能少做,除非你在每个无效行上写它们。但我不明白编写 6 个查询是个问题。 IF (b) 那么这更像是一个查询调优问题,您应该展示您编写的查询并告诉我们有关表中行数的信息。
  • @SamSegers 是时候执行它们了。我在 City 表中有大约 9,000 行,在 location 表中有 16000+ 行,在 Customer 表中有 48,000+ 行,在 Shop 表中有 4000+ 行。
  • 对我来说,您更新的问题与之前的评论相矛盾。您要一一编写所有查询吗?虽然您可能只想对每个操作/表进行一个查询来进行所有更改?由于其简单性,您更新的问题中的查询或多或少是最佳的。
  • @SamSegers 抱歉,我的意思是逐个编写所有查询非常耗时。我想知道是否所有这些都在一个查询中完成。可能类似于其他语言中的 for 循环,用于搜索重复项、进行更新和删除。

标签: sql sql-server


【解决方案1】:

您可以根据条件一次性更新整个表格。在您的情况下,存在具有重复值的另一行。

-- (1) UPDATE DUPLICATE CITIES ON LOCATION
UPDATE l SET l.Id_City = mstr.Id_City
-- SELECT c.Id_City oldId, mstr.Id_City newId  -- Check this for your convenience
FROM [Location] l
    INNER JOIN City c ON c.Id_City = l.Id_City 
    INNER JOIN (
        SELECT City, MIN(Id_City) Id_City -- KEEP FIRST ONLY
        FROM City
        GROUP BY City
        HAVING COUNT(1) > 1
    ) mstr ON mstr.City = c.City
        AND mstr.Id_City < Id_City

-- (2) DELETE DUPLICATE CITIES
DELETE c
-- SELECT c.Id_City oldId, mstr.Id_City newId  -- Check this for your convenience
FROM City c
    INNER JOIN (
        SELECT City, MIN(Id_City) Id_City -- KEEP FIRST ONLY
        FROM City
        GROUP BY City
        HAVING COUNT(1) > 1
    ) mstr ON mstr.City = c.City
        AND mstr.Id_City < Id_City

-- ...

其余的查询可以类比这些例子

【讨论】:

    【解决方案2】:

    不完美,但应该可以从这里开始工作

    declare @City table (ID_city int primary key, City varchar(10));
    insert into  @city values 
           (1, 'Chennai')
         , (2, 'Benagluru')
         , (3, 'Chennai')
         , (4, 'Delhi')
         , (5, 'Chennai')
         , (6, 'Benagluru');
    --select * from @city c order by c.City, c.ID_city;
    
    declare @Location table (ID_Location int primary key, ID_City int, zip char(4))
    insert into @Location values 
           (1, 1, '0001') 
         , (2, 2, '0011')
         , (3, 1, '0002')
         , (4, 3, '0021')
         , (5, 1, '0003')
         , (6, 2, '0012')
         , (7, 1, '0001');  --duplicate
    --select * from @Location l order by l.ID_Location;
    
    declare @Customer table (Cust_ID int primary key, ID_Location int)
    insert into @Customer values
           (1, 1)
         , (2, 3)
         , (3, 5)
         , (4, 2)
         , (5, 7);
    --select * from @Customer;
    
    declare @Shop table (Shop_ID int primary key, ID_Location int) 
    insert into @Shop values 
           (1, 1)
         , (2, 2)
         , (3, 6)
         , (4, 3)
         , (5, 7);
    --select * from @Shop s order by s.Shop_ID;
    
     declare @LocationMap table (ID_Location int primary key, ID_City int, zip char(4), cnt int, rn int)
     insert into @LocationMap
     select l.* 
          , count(*)     over (partition by zip) as cnt 
          , ROW_NUMBER() over (partition by zip order by ID_Location) as rn 
       from @Location l;
    --select * from @LocationMap where cnt > 1 order by zip, rn;
    
    declare @CityMap table (ID_city int primary key, City varchar(10), cnt int, rn int)
    insert into @CityMap 
    select c.* 
         , count(*)     over (partition by City) as cnt 
         , ROW_NUMBER() over (partition by City order by City, ID_city) as rn 
     from @City c;
    --select * from @CityMap m where m.cnt > 1 order by m.City, m.ID_city;
    
    update c 
    set c.ID_Location = f.ID_Location
    from @Customer c
    join @LocationMap m 
      on m.ID_Location = c.ID_Location
     and m.rn > 1
    join @LocationMap f 
      on f.ID_City = m.ID_City
     and m.rn = 1; 
    select c.* from @Customer c order by c.Cust_ID
    
    update s 
    set s.ID_Location = f.ID_Location
    from @shop s 
    join @LocationMap m 
      on m.ID_Location = s.ID_Location
     and m.rn > 1
    join @LocationMap f 
      on f.zip = m.zip 
     and m.rn = 1; 
    select s.* from @shop s order by s.Shop_ID;
    
    --select l.* from @Location l order by l.ID_Location;
    update l 
    set l.ID_City = f.ID_City
    from @Location l
    join @CityMap m 
      on m.ID_city = l.ID_City 
     and m.rn > 1
    join @CityMap f 
      on f.City = m.City
     and f.rn = 1; 
    select l.* from @Location l order by l.ID_Location;
    
     delete l 
     from @Location l 
     join @LocationMap m
       on l.ID_Location = m.ID_Location 
      and m.rn > 1;
    select * from @Location l order by l.ID_Location;
    
     delete c 
     from @City c
     join @CityMap m
       on c.ID_city = m.ID_city 
      and m.rn > 1;
    select * from @City c order by c.ID_city;
    

    【讨论】:

      猜你喜欢
      • 2011-02-22
      • 2016-10-08
      • 1970-01-01
      • 2014-07-20
      • 1970-01-01
      • 2023-03-04
      • 2011-09-03
      • 2020-09-17
      • 1970-01-01
      相关资源
      最近更新 更多