我在Table1中有几个字符串,我想根据表2中的可用值进行更新。
示例代码
http://rextester.com/HQFOQ18215
IF OBJECT_ID('Test1','U') iS NOT NULL
DROP TABLE Test1;
IF OBJECT_ID('Test2','U') iS NOT NULL
DROP TABLE Test2;
Create table Test1
(
Id INT
,Lid INT
,MyString VARCHAR(MAX)
,Did INT
,Secid INT
);
INSERT INTO Test1 values (1,100,'you,shall,not,pass,gandlaf,the,grey', 401, 501);
INSERT INTO Test1 values (2,100,'ok,fine,bye', 401, 501);
INSERT INTO Test1 values (3,100,'test,dev,uat,prod', 403, 501);
INSERT INTO Test1 values (4,100,'1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16', 404, 501);
Create table Test2
(
Id INT IDENTITY(1,1)
,SecId INT
,CommaPosition INT
,Value VARCHAR(50)
,Did INT
,RowId INT
);
INSERT INTO Test2 Values (501, 4, '[Quantity]', 401, 1);
INSERT INTO Test2 Values (501, 14, '[Price]', 401, 1);
INSERT INTO Test2 Values (501, 4, '[Quantity]', 401, 2);
INSERT INTO Test2 Values (501, 14, '[Price]', 401, 2);
INSERT INTO Test2 Values (501, 14, '[Quantity|Price]', 403, 3);
INSERT INTO Test2 Values (501, 4, '[Interest]', 404, 4);
INSERT INTO Test2 Values (501, 14, '[Expired]', 404, 4);
SELECT * FROM Test1;
SELECT * FROM Test2;
预期产出
/*
Expected OUTPUT
Id Lid MyString Did Secid
1 100 you,shall,not,[quantity],gandlaf,the,grey,,,,,,,[Price], 401 501
2 100 ok,fine,bye,[quantity],,,,,,,,,,[Price], 402 501
3 100 test,dev,uat,prod,,,,,,,,,,[Quantity|Price], 403 501
4 100 1,2,3,[Quantity],5,6,7,8,9,10,11,12,13,[Price],15,16 404 501
*/
第一个字符串you,shall,not,pass,gandlaf,the,grey
其中"pass"
位于第4个逗号位置之前,该位置由table2中的[quantity]
替换但是没有第14个逗号
所以逗号被复制,直到达到第14个逗号并且在第14个逗号[Price]
被替换之前。最终输出为"you,shall,not,[quantity],gandlaf,the,grey,,,,,,,[Price],"
第二个字符串ok,fine,bye
没有第四个逗号或者第14个逗号,所以添加第4个逗号,然后替换[quantity]
,然后添加逗号直到第14个位置
基于表2中的逗号位置列,最终字符串变为ok,fine,bye,[quantity],,,,,,,,,,[Price],
表2中只有第三个字符串test,dev,uat,prod
可用的第14个逗号位置,因此逗号被复制到第14个逗号和第14个逗号[Quantity|Price]
字符串之前
添加最终字符串变为test,dev,uat,prod,,,,,,,,,,[Quantity|Price],
在第4个字符串1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
中,如果您看到第4个和第14个变为逗号,则第14个逗号之前的字符串被[Interest]
替换,字符串变为第14个逗号被替换为
[Expired]
保持剩下的字符串不受影响。
我想实现上面的输出,我在下面尝试更新语句并没有给我想要的结果。
UPDATE T1
SET T1.MyString = T1.MyString + REPLICATE(',',T2.CommaPosition - (len(T1.MyString) - LEN(REPLACE(T1.MyString,',',''))))
FROM Test1 as T1 INNER JOIN Test2 as T2 ON T1.Secid = T2.SecId AND T1.Did = T2.Did AND T1.Id = T2.RowId;
SELECT DISTINCT T1.Lid, T1.MyString, T1.Did, T1.Secid, T2.RowId
FROM Test1 as T1 INNER JOIN Test2 as T2 ON T1.Secid = T2.SecId AND T1.Did = T2.Did AND T1.Id = T2.RowId;
答案 0 :(得分:2)
我假设您正在执行某种宏观替代。
几点说明:
示例强>
Select A.ID
,A.Lid
,B.MyString
,A.Did
,A.Secid
From Test1 A
Cross Apply (
Select MyString = Stuff((Select ',' +RetVal
From (
Select RetSeq
,RetVal = max(IsNull(B2.Value,B1.RetVal))
From (
Select Top (Select max(CommaPosition) From Test2 Where RowID=A.ID )
RetSeq=Row_Number() Over (Order By (Select null))
,RetVal=''
From master..spt_values
Union All
Select RetSeq = Row_Number() over (Order By (Select null))
,RetVal = LTrim(RTrim(N.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(A.MyString,',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as X
Cross Apply x.nodes('x') AS N(i)
) B1
Left Join Test2 B2 on B2.RowID=A.ID and B2.CommaPosition=B1.RetSeq
Group By B1.RetSeq
) B3
Order by RetSeq
For XML Path ('')),1,1,'')
) B
<强>返回强>
答案 1 :(得分:2)
正确答案是不要在一个列中存储多个值。这违反了第一范式 !!!
如果将连接的字符串分解为父表和子表,则最好。您的示例Table2
似乎是一组修改命令,已经具有所需的结构 - 您只需将完整的值集合放入永久表中即可。
完成后,处理您的更改数据非常简单:加入关键值并更新!热潮,完成了。您的数据库应该规范化,不应该存储易于修改的数据,格式需要解压缩,修改并重新打包。
如果您需要某种方法将值连接在一起以生成MyString
中的Table1
输出,请为此创建视图,或者在前端代码中执行此操作。有FOR XML PATH
的基于SQL的精彩解决方案可以轻松完成。请注意您可能遇到的随机XML PATH
解决方案,因为那里的大多数解决方案都无法容纳包含xml类元素的字符串,例如>
和<
。使用以下示例中的一个(带有.value()
表达式) 可以容纳这些字符。
这是一个通用示例,演示如何将父表和子表组合成单行,每个父表一行,所有子值连接在一起。您可以使用ORDER BY
将FOR XML
子句放入查询中以获取特定订单。
CREATE TABLE dbo.Parent (
ParentId int identity(1,1) NOT NULL CONSTRAINT PK_Parent PRIMARY KEY CLUSTERED,
Name varchar(100) NOT NULL CONSTRAINT UQ_Parent_Name UNIQUE
);
CREATE TABLE dbo.ParentChild (
ParentId int NOT NULL,
ChildName varchar(100)
);
INSERT dbo.Parent (Name) VALUES
('Parent 1'), ('Parent X'), ('Parent B');
INSERT dbo.ParentChild (ParentId, ChildName) VALUES
(1, 'ABC'), (1, 'WHOAMAN'), (1, 'QRT'),
(2, 'XYZ'), (3, 'LMN'), (3, 'MAN'), (3, 'WHOADOG');
SELECT
p.*,
Children = Substring((
SELECT ', ' + ChildName
FROM ParentChild pc
WHERE p.ParentId = pc.ParentId
FOR XML PATH(''), TYPE
).value('.[1]', 'varchar(max)'), 3, 8000)
FROM
dbo.Parent p
WHERE -- an example of filtering by a child value without substrings on the combined string
EXISTS (
SELECT *
FROM dbo.ParentChild pc
WHERE
p.ParentId = pc.ParentId
AND pc.ChildName = 'WHOADOG'
);