Sql 在可能有多个相同行的联接表中只更新一行?
所以这可能有点复杂,但我试着尽可能地提取它。基本上,我有一个带有“items”的表,一个带有“slot”的表,一个连接表,两个插槽之间有“slot\u items”,因为插槽可以有项目,一个“history”表,以防一个项目更改为另一个项目,然后更新“slot\u items”表中的所有链接,还有一个“history\u slots”表,以指示哪些插槽受到项目更改的影响 现在,我正试图找到一种方法来撤销历史变更。如果有人创建了将项目a更改为项目B的历史记录,则插槽1可能已经有了项目B,在这种情况下,您可能会在联接表中获得两个连接项目B和插槽1的条目。这对我来说很好,因为我可以使用一些简单的分组来确保项目B只返回一次 但是,如果我想撤消历史记录更改,我会尝试找到一种方法,对每个插槽仅更新“插槽\u项”中的第一个实例,其中历史\u插槽项与插槽匹配,history.oldItem与项目匹配。我不想同时更新插槽1项目B的两个实例,因为该插槽上原来有一个项目B。所以我想从插槽1项目B的两个条目返回插槽1项目A和插槽1项目B 不幸的是,我似乎不能简单地更新TOP1。。。因为可能有多个插槽受项目历史记录更改的影响。因此,如果有一个插槽2也有一个更新为项目B的项目a,我想同时恢复该插槽\u项目条目 要将其放在SQL中Sql 在可能有多个相同行的联接表中只更新一行?,sql,sql-server,Sql,Sql Server,所以这可能有点复杂,但我试着尽可能地提取它。基本上,我有一个带有“items”的表,一个带有“slot”的表,一个连接表,两个插槽之间有“slot\u items”,因为插槽可以有项目,一个“history”表,以防一个项目更改为另一个项目,然后更新“slot\u items”表中的所有链接,还有一个“history\u slots”表,以指示哪些插槽受到项目更改的影响 现在,我正试图找到一种方法来撤销历史变更。如果有人创建了将项目a更改为项目B的历史记录,则插槽1可能已经有了项目B,在这种情况
DECLARE @items TABLE(
id VARCHAR
);
INSERT INTO @items VALUES('A'),('B'),('C');
DECLARE @slots TABLE(
id INT
);
INSERT INTO @slots VALUES(1),(2),(3);
DECLARE @slots_items TABLE(
fk_slots INT,
fk_items VARCHAR
);
INSERT INTO @slots_items VALUES(1,'B'),(1,'B'),(2,'C'),(2,'B'),(2,'C');
DECLARE @history TABLE(
id INT,
fk_oldItem VARCHAR,
fk_newItem VARCHAR
);
INSERT INTO @history VALUES(100,'A','B');
DECLARE @history_slots TABLE(
fk_history INT,
fk_slots INT
);
INSERT INTO @history_slots VALUES(100,1),(100,2);
因此,在这个数据集中,在项目更改之后,插槽1将有项目B、B、C,插槽2将有项目B、C
我希望能够撤消此操作并进行更新,这样它将显示插槽1有项目A、B、C,插槽2有项目A、C。有什么想法/帮助吗?编辑以尝试澄清:我希望更新@slots\u items中的所有条目,以将fk\u items从B设置为A,但每个插槽仅一次,因为同一插槽/项目组合可能会出现多次
我曾经考虑过这样一种可能性,即不是历史表指向受影响的插槽,而是指向受影响的联接表条目,但这需要向联接表添加主键。不太喜欢这个主意,但在绝对必要的情况下可以这样做。如果可能的话,我更愿意找到一种解决方案,不必向联接表中添加主键。为此,我经常使用row\u number。您需要某种列来指定顺序,因此让我假设一个creationdate列。我发现逻辑和数据很难理解。但是,要将@history\u slots中的最新记录更改为'A':
不完全是。。。我正在尝试更新slot\u项,因此我尝试将您的查询修改为以下内容。。。在cte为SELECT si.*的情况下,按h.id按h.changeDate为seqnum从@history h INNER JOIN@history\U slots hs ON h.id=hs.fk\U history INNER JOIN@slots\U items si ON hs.fk\U slots=si.fk\U slots从cte中选择*行数,其中fk\U items='B'和seqnum=1;这只给出了第一个结果,但我需要所有的结果,其中fk_items='B',但每个槽只有一个实例。
with toupdate as (
select hs.*, row_number() over (partition by id order by creationdate desc) as seqnum
from history_slots hs
)
update todupdate
set fk_oldItem = 'A'
where seqnum = 1;