我需要创建一个递归更新语句,从另一个表更新,以便ex ..
Table1
(
IdNumberGeneratedFromAService INT NOT NULL,
CodeName NVARCHAR(MAX)
)
Table2
(
Table2Id Auto_Increment,
Name NVARCHAR(MAX),
IdNumberThatComesFromTabl1,
CodeNameForTable1ToMatch
)
问题是CodeNameForTable1ToMatch不是唯一的,所以如果Table1对于相同的代码有2个idnumber并且Table2中有两行具有相同的CodeName我想要按顺序更新table2中的行,所以第一行得到第一个idnumber和第二行row获取第二个id号。
也想在没有光标的情况下这样做....
SAMPLE DATA
Table1
idNumber Code
C145-6678-90 Code1
C145-6678-91 Code1
C145-6678-92 Code1
C145-6678-93 Code1
C145-6678-94 Code1
Table 2
AutoIncrementIdNumber Code IdNumber
1 Code1 {NULL}
2 Code1 {NULL}
3 Code1 {NULL}
4 Code1 {NULL}
5 Code1 {NULL}
C145-6678-90 needs to got 1
C145-6678-91 needs to got 2
C145-6678-92 needs to got 3
C145-6678-93 needs to got 4
C145-6678-94 needs to got 5
in one update statement
答案 0 :(得分:6)
在每个表上使用ROW_NUMBER窗口函数,按代码分区,您可以对每个具有共同代码的行进行编号,然后将每个查询的结果组合在一起,以根据代码和行匹配行该代码的编号实例。因此,表1中的第一个代码A将匹配表2中的第一个代码A,等等。
显示此示例代码(SQL 2005或更高版本):
-- Sample code prep
CREATE TABLE #Table1
(
IdNumberGeneratedFromAService INT NOT NULL,
CodeName NVARCHAR(MAX)
);
CREATE TABLE #Table2
(
Table2Id INT NOT NULL IDENTITY(1,1),
Name NVARCHAR(MAX),
IdNumberThatComesFromTabl1 INT NULL,
CodeNameForTable1ToMatch NVARCHAR(MAX)
);
INSERT INTO #Table1(IdNumberGeneratedFromAService, CodeName)
VALUES(100,'Code A'),(150,'Code A'),(200,'Code B'),(250,'Code A'),(300,'Code C'),(400,'Nonexistent');
INSERT INTO #Table2(Name, IdNumberThatComesFromTabl1, CodeNameForTable1ToMatch)
VALUES('A1-100',0,'Code A'),('A2-150',0,'Code A'),('A3-250',0,'Code A'),('B1-200',0,'Code B'),('C1-300',0,'Code C'),('No Id For Me',0,'Code No Id :(');
-- Sample select statement that shows the row numbers
--SELECT *
--FROM
-- (SELECT *, ROW_NUMBER() OVER (Partition By IT2.CodeNameForTable1ToMatch Order By IT2.Table2Id) as RowNum
-- FROM #Table2 IT2) T2
-- INNER JOIN
-- (SELECT *, ROW_NUMBER() OVER (Partition By IT1.CodeName Order By IT1.IdNumberGeneratedFromAService) as RowNum
-- FROM #Table1 IT1) T1
-- ON T1.CodeName = T2.CodeNameForTable1ToMatch AND T1.RowNum = T2.RowNum;
-- Table 2 Before
SELECT * FROM #Table2;
-- Actual update statement
UPDATE #Table2
SET IdNumberThatComesFromTabl1 = T1.IdNumberGeneratedFromAService
FROM #Table2 AT2
INNER JOIN
(SELECT *, ROW_NUMBER() OVER (Partition By IT2.CodeNameForTable1ToMatch Order By IT2.IdNumberThatComesFromTabl1) as RowNum
FROM #Table2 IT2) T2
ON T2.Table2Id = AT2.Table2Id
INNER JOIN
(SELECT *, ROW_NUMBER() OVER (Partition By IT1.CodeName Order By IT1.IdNumberGeneratedFromAService) as RowNum
FROM #Table1 IT1) T1
ON T1.CodeName = T2.CodeNameForTable1ToMatch AND T1.RowNum = T2.RowNum;
-- Table 2 after
SELECT * FROM #Table2;
-- Cleanup
DROP TABLE #Table1;
DROP TABLE #Table2;
我将两个样本表转换为临时表,并为“代码A”添加了3条记录,为“代码B”添加了记录,并为“代码C”添加了记录。表1中的代码根据表1 ID的顺序编号,表2中的代码按自动递增表2 id排序。我还在每个表中包含了一条记录,在另一个表中没有匹配。我试图使代码具有描述性,因此更容易看到发生了正确的匹配(因为它具有自动递增ID,所以它们对表2的顺序很重要)
注释掉的示例选择用于帮助理解选择在我将其加入UPDATE语句之前的工作方式。
因此我们可以在更新之前看到表2全部为0,然后我们更新表2中的值,其中唯一表2的id与我们编号良好且匹配的连接中的唯一表2 id匹配,然后我们从表2中选择再看看结果。
答案 1 :(得分:1)
对Tarwn的解决方案进行了一次试验:
with cte1 as (
select code, row_number() over (partition by code order by idNumber) as [rn]
from table1
), cte2 as (
select code, row_number() over (partition by code order by AutoIncrementIdNumber) as [rn]
from table2
)
update cte2
set idNumber = cte1.idNumber
from cte2
inner join cte1
on cte2.code = cte1.code
and cte2.rn = cte1.rn
我只是提出这个问题,因为人们常常惊讶于你可以更新公用表表达式。
答案 2 :(得分:-3)
没有光标,这是不可能的。