首页 > 解决方案 > 谁能帮我写一个 SQL 语句?

问题描述

给定的是下表:

aID | bID | idx
1   | 1   | 0
2   | 2   | 0
2   | 3   | 1
3   | 1   | 0
4   | 2   | 0
4   | 3   | 1
4   | 4   | 2

是否可以仅使用 DELETE 和 UPDATE 语句而不是 CURSORS 获得以下结果?

aID | bID | idx
1   | 1   | 0
2   | 2   | 0
2   | 3   | 1
4   | 4   | 0

每个 aID 都应有一个唯一的 bID 列表。idx 列仅描述列表的顺序。

我想删除所有多个投标并只保留 aID 最低的投标。然后根据需要更新剩余行的 idx。

先感谢您。

标签: sql

解决方案


这似乎可以完成这项工作:

declare @t table (aID int, bID int, idx int)
insert into @t(aID,bID,idx) values
(1,1 ,0 ),
(2,2 ,0 ),
(2,3 ,1 ),
(3,1 ,0 ),
(4,2 ,0 ),
(4,3 ,1 ),
(4,4 ,2 )

delete
    t1
from @t t1
where exists (select * from @t t2 where t2.bID = t1.bID and t2.aID < t1.aID)

;With Numbered as (
    select *,ROW_NUMBER() OVER (PARTITION BY aID ORDER by bID) -1 as newIdx
    from @t
)
update Numbered set idx = newIdx

select * from @t

一旦你用文字说明了你的要求,查询的逻辑就会很自然地流动。删除另一行具有相同值bID和较低aID值的行。

然后idx只是基于每个 单独系列的行号aID。当然,这确实提出了一个问题,即当它们可以很容易地计算出来时,我们为什么还要存储它们1

结果:

aID         bID         idx
----------- ----------- -----------
1           1           0
2           2           0
2           3           1
4           4           0

(请注意,我使用 SQL Server 对此进行了测试 - 您没有将任何产品特定标签应用于问题 - 表变量语法是非标准的,并且delete ... from有点可疑,但其余的是标准 SQL)


1一般的经验法则是只存储基础数据,不存储派生数据。通过单独存储派生数据,您会引入计算值与基础数据不同步的机会。

第二条经验法则是,如果您确实必须存储派生数据,最好让数据库引擎而不是您自己负责维护它。但通常这仅在计算成本高得令人望而却步并且您严重偏向于读者而不是作者的情况下。


推荐阅读