我认为你需要先了解一下,为什么你认为XML
方法不执行不够好,您的需求,为it has actually been shown to perform very well for larger input strings。
如果只需要处理的输入串高达要么4000或8000个字符(分别非max
nvarchar
和varchar
类型),则可以利用包含内嵌表值函数which will also perform very well内的帐簿表。我使用的版本可以在这篇文章的末尾找到。
利用这个功能,我们可以在你的InputLocations
柱拆分出来的价值观,但我们仍然需要使用for xml
将它们串联到一起为你想要的格式:
-- Define data
declare @InputLocationTable table (SKUID int,InputLocations varchar(100),Flag varchar(100));
declare @Location table (SKUID int,Locations varchar(100));
insert into @InputLocationTable(SKUID,InputLocations) values (11,'Loc1, Loc2, Loc3, Loc4, Loc5, Loc6'),(12,'Loc1, Loc2'),(13,'Loc4,Loc5'),(14,'Loc1');
insert into @Location(SKUID,Locations) values (11,'Loc3'),(11,'Loc4'),(11,'Loc5'),(11,'Loc7'),(12,'Loc10'),(12,'Loc1'),(12,'Loc5'),(13,'Loc4'),(13,'Loc2'),(13,'Loc2'),(14,'Loc1');
--Query
-- Derived table splits out the values held within the InputLocations column
with i as
(
select i.SKUID
,i.InputLocations
,s.item as Loc
from @InputLocationTable as i
cross apply dbo.fn_StringSplit4k(replace(i.InputLocations,' ',''),',',null) as s
)
select il.SKUID
,il.InputLocations
,isnull('Add ' -- The split Locations are then matched to those already in @Location and those not present are concatenated together.
+ stuff((select ', ' + i.Loc
from i
left join @Location as l
on i.SKUID = l.SKUID
and i.Loc = l.Locations
where il.SKUID = i.SKUID
and l.SKUID is null
for xml path('')
)
,1,2,''
)
,'No Flag') as Flag
from @InputLocationTable as il
order by il.SKUID;
输出:
+-------+------------------------------------+----------------------+
| SKUID | InputLocations | Flag |
+-------+------------------------------------+----------------------+
| 11 | Loc1, Loc2, Loc3, Loc4, Loc5, Loc6 | Add Loc1, Loc2, Loc6 |
| 12 | Loc1, Loc2 | Add Loc2 |
| 13 | Loc4,Loc5 | Add Loc5 |
| 14 | Loc1 | No Flag |
+-------+------------------------------------+----------------------+
对于nvarchar
输入(我有不同的功能varchar
和max
类型输入)这是我的版本的字符串分裂功能链接上面:
create function [dbo].[fn_StringSplit4k]
(
@str nvarchar(4000) = ' ' -- String to split.
,@delimiter as nvarchar(1) = ',' -- Delimiting value to split on.
,@num as int = null -- Which value in the list to return. NULL returns all.
)
returns table
as
return
-- Start tally table with 10 rows.
with n(n) as (select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1)
-- Select the same number of rows as characters in @str as incremental row numbers.
-- Cross joins increase exponentially to a max possible 10,000 rows to cover largest @str length.
,t(t) as (select top (select len(isnull(@str,'')) a) row_number() over (order by (select null)) from n n1,n n2,n n3,n n4)
-- Return the position of every value that follows the specified delimiter.
,s(s) as (select 1 union all select t+1 from t where substring(isnull(@str,''),t,1) = @delimiter)
-- Return the start and length of every value, to use in the SUBSTRING function.
-- ISNULL/NULLIF combo handles the last value where there is no delimiter at the end of the string.
,l(s,l) as (select s,isnull(nullif(charindex(@delimiter,isnull(@str,''),s),0)-s,4000) from s)
select rn
,item
from(select row_number() over(order by s) as rn
,substring(@str,s,l) as item
from l
) a
where rn = @num
or @num is null;
go
你的意思是说,更新的标志的列,其中INputLocation不是位置表的位置scolumn –
我不知道如果我正确地理解你的问题......你说,你设法找到与XML解决方案但宁愿避免使用它。那么,“FOR XML PATH”afaik是直到SQL Server 2016执行字符串连接的最佳和推荐的解决方案。2016年,MSFT添加了STRING_AGG函数。在SQL Server 2008上,您可以使用自定义程序集作为替代方案。但这有其不利之处。看看https://www.sqlshack.com/string-concatenation-done-right-part-2-an-effective-technique/。 –
嗨,感谢您的重播,我只是避免使用XML路径,这并不意味着我不应该使用和所有,我使用的SQL服务器2014年,所以请建议我更好的代码或答案为 – Karthik