SQL server在多个表中进行多次更新和删除
我有四张桌子,分别是城市、地点、顾客和商店。设计此数据库的人已使主键自动递增。因此,数据库中存在冗余数据。我正在尝试清理数据库,但更新和删除行需要很长时间。这些表的示例如下所示:SQL server在多个表中进行多次更新和删除,sql,sql-server,Sql,Sql Server,我有四张桌子,分别是城市、地点、顾客和商店。设计此数据库的人已使主键自动递增。因此,数据库中存在冗余数据。我正在尝试清理数据库,但更新和删除行需要很长时间。这些表的示例如下所示: Table 1: City: ID_city(PK) | City | ID_City | |-----------|---------| | Chennai | 1 | | Benagluru | 2 | | Chennai | 3 | | Delhi |
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 |
预期表格:
如您所见,到处都有重复的记录,需要使用3个update语句(使用join和2个delete语句)来删除1个重复的城市。
有没有办法减少执行此任务的SQL语句的数量
我写的问题是:
更新客户集ID\u位置=1,其中客户ID=5
更新车间集合ID\u位置=1,其中车间ID=5
从ID_location=7的位置删除
更新位置集ID_City=1,其中ID_City=3或ID_City=5
从ID\u Location=3或ID\u Location=5的城市中删除
这是为了删除1个重复的城市,城市表中大约有1300个重复的城市。是否有一种简单的方法来检查重复项、更新并最终删除?您可以根据条件一次性更新整个表。在您的情况下,存在另一个具有重复值的行
-- (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
-- ...
其余的查询可以模拟这些示例并不完美,但应该能够从这里开始工作
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;
你能重新格式化你的数据示例吗?这是什么意思?a是编写查询的时间,b是执行查询的时间。如果是a,则不能少做,除非是在无效行上写。但我不认为编写6个查询是一个问题。如果是b,那么这更像是一个查询优化问题,您应该显示您编写的查询,并告诉我们有关表中行数的信息。@SamSegers是时候计算它们了。我在City表中有9000多行,location表中有16000多行,Customer表中有48000多行,Shop表中有4000多行。对我来说,您更新的问题与之前的评论相矛盾。你要一个接一个地写所有的查询吗?而您可能只希望每个操作/表有一个查询来执行所有更改?您更新的问题中的查询由于其简单性或多或少是最优的。@SamSegers抱歉,我的意思是逐个编写所有查询很耗时。我想知道是否所有这些都是在一个查询中完成的。可能类似于其他语言中的for循环,用于搜索重复项、进行更新和删除。
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;