我正在合并两个金融交易数据库。在其中一个表中,有一个字段用来表示与同一表中另一条记录的事务分配。 它使用记录ID和金额来引用相应的记录。当合并两个数据库的两个表中的数据时,记录ID将更改。 如何更改此字段中的所有记录ID,从旧的ID更改为新的对应ID?有办法吗 RecordID是“ I =“值,需要用NewRecordID替换。
换句话说,例如,如何在“分配”字段中的所有位置将值I = 53983替换为I = 3,并用所有其他“ I =“值替换该值?
NewID OldID Allocation
1 53033 I=53983;A=260.28
2 53038 I=53983;A=2922.59|I=54420;A=2194.19
3 53983 I=53033;A=260.28|I=54261;A=62.93|I=53038;A=2922.59
4 54261 I=53983;A=62.93
5 54420 I=53038;A=2194.19
答案 0 :(得分:1)
通常我不建议使用像这样的循环,但是我想不出更干净的方法。
-- Your table
DECLARE @table TABLE ([newid] INT, oldId INT, Allocation VARCHAR(8000));
INSERT @table
([newid],oldId,Allocation)
VALUES
(1,53033,'I=53983;A=260.28'),
(2,53038,'I=53983;A=2922.59|I=54420;A=2194.19'),
(3,53983,'I=53033;A=260.28|I=54261;A=62.93|I=53038;A=2922.59'),
(4,54261,'I=53983;A=62.93'),
(5,54420,'I=53038;A=2194.19');
-- table to collect all the ids
DECLARE @ids TABLE (id INT);
INSERT @ids(id)
SELECT [newid]
FROM @table;
-- routine to perform the update
DECLARE @id INT = 1;
WHILE @id <= (SELECT COUNT(*) FROM @table)
BEGIN
UPDATE @table
SET Allocation = REPLACE(t.Allocation,f.old,'I='+CAST(@id AS VARCHAR(10))+';')
FROM @table t
CROSS APPLY (VALUES
('I='+CAST(
(SELECT t.oldId
FROM @table t
WHERE t.newid = @id)
AS VARCHAR(10))+';')) f(old)
WHERE CHARINDEX(f.old, t.Allocation) > 0;
SET @id += 1;
END
SELECT * FROM @table;
返回
newid oldId Allocation
----------- ----------- ------------------------------------------
1 53033 I=3;A=260.28
2 53038 I=3;A=2922.59|I=5;A=2194.19
3 53983 I=1;A=260.28|I=4;A=62.93|I=2;A=2922.59
4 54261 I=3;A=62.93
5 54420 I=2;A=2194.19
请注意,我的解决方案假定newId值是从1开始的连续数字集。如果不是这种情况,您可以轻松地进行调整。
答案 1 :(得分:1)
您已经被告知,桌子的设计不好。通过适当的设计,您将不必解决此问题。
以下方法将使用一些替换形式,以使级联字符串(一个糟糕的主意!)成为结构化XML。 CTE RowWise
的结果应该足以弥补您的不良设计。
如果您真的需要坚持下去,最后的SELECT
将返回重新组织的所有数据:
DECLARE @table TABLE ([newid] INT, oldId INT, Allocation VARCHAR(8000));
INSERT @table
([newid],oldId,Allocation)
VALUES
(1,53033,'I=53983;A=260.28'),
(2,53038,'I=53983;A=2922.59|I=54420;A=2194.19'),
(3,53983,'I=53033;A=260.28|I=54261;A=62.93|I=53038;A=2922.59'),
(4,54261,'I=53983;A=62.93'),
(5,54420,'I=53038;A=2194.19');
WITH Splitted AS
(
SELECT *
,CAST('<x><y type="' + REPLACE(REPLACE(REPLACE(Allocation,'=','">'),';','</y><y type="'),'|','</y></x><x><y type="') + '</y></x>' AS XML) AS TheXml
FROm @table
)
,RowWise AS
(
SELECT Splitted.oldId
,x.value('(y[@type="I"]/text())[1]','int') AS I
,x.value('(y[@type="A"]/text())[1]','decimal(10,4)') AS A
FROM Splitted
CROSS APPLY TheXml.nodes('/x') A(x)
)
SELECT t1.[newid],t1.oldId
,STUFF(
(
SELECT CONCAT('|','I=',t3.[newid],';A=',t2.A)
FROM RowWise t2
INNER JOIN @table t3 ON t2.I=t3.[oldId]
WHERE t2.oldId =t1.oldId
FOR XML PATH('')
),1,1,'')
FROM @table AS t1;
替换和强制转换为XML将返回以下内容:
<x>
<y type="I">53983</y>
<y type="A">2922.59</y>
</x>
<x>
<y type="I">54420</y>
<y type="A">2194.19</y>
</x>
答案 2 :(得分:0)
假设这是表中的数据,您可以执行以下操作:
ItemTemplate
但是,请注意,在一个列中保留一个以上的数据实体是非常不好的做法。
如果可能,最好对数据库进行规范化-为分配创建一个新表,该表包含该列中当前所有数据部分的列,并从中引用外表。
进一步的阅读:阅读Is storing a delimited list in a database column really that bad?的SO帖子及其答案,在这里您会看到很多答案,为什么这个问题的答案是绝对是!