您遇到了存储非规范化和特别是分隔数据的众多问题之一。task
从关系上讲,标准的解决方案是创建一个联结表来表示和之间的这种多对多关系job
(例如“JobToTask”)。
但是,如果您无法更改当前情况,一种方法是循环遍历您的集合并一次替换一次迭代:
-- Create a temporary spot for id replacements
declare @output table (
taskid int, jobnamelist varchar(1000)
)
insert into @output select taskid, ',' + jobid + ',' from task
-- Run replacements
while exists (select null from @output t join job j on t.jobnamelist like '%,' + cast(j.jobid as varchar(50)) + ',%') begin
update t
set jobnamelist = replace(
jobnamelist,
',' + (select cast(min(jobid) as varchar(11)) from job where t.jobnamelist like '%,' + cast(jobid as varchar(50)) + ',%') + ',',
',' + (select name from job where jobid = (select min(jobid) from job where t.jobnamelist like '%,' + cast(jobid as varchar(50)) + ',%')) + ','
)
from @output t
where exists (select null from job where t.jobnamelist like '%,' + cast(jobid as varchar(50)) + ',%')
end
-- Get final output
select taskid, substring(jobnamelist, 2, len(jobnamelist) - 2) as jobnamelist
from @output
-- taskid jobnamelist
-- ------ -----------
-- 1 Wash
-- 2 Dry
-- 3 Wash,Dry
请特别注意在查找或进行替换时始终将分隔符添加到字符串的两端。这可以防止您替换 ID 的一部分(例如 33 在 334 中)。
如果您必须在单个选择语句中执行此操作,您可能会使用递归 CTE来运行类似的逻辑。
要考虑的一个极端情况是,如果您的列job.name
中存在一个job.id
...您最终会替换两次(或更多)的东西,因此必须对此进行检查(替换历史字段或临时表,可能)。