我有一个包含逗号分隔数字列表的varchar列:
listOfNumbers
1,2,3,4
11,1,1,3
4,2,1
1
现在我需要创建一个输入数字的函数,并从列中删除。
示例:如果输入为1,则结果应为:
listOfNumbers
2,3,4
11,3
4,2
empty
我尝试使用多个REPLACE,如:
declare @listOfNumbers as varchar(max)
set @listOfNumbers = '1,2,3,1'
select *, REPLACE(REPLACE(listOfNumbers,',1', ''),'1,', '') from
(
select @listOfNumbers as listOfNumbers
) t1
但这不正确,因为我甚至会更换像11或111这样的数字。
有没有办法捕捉所有案件?
提前感谢您的回复。
编辑: 我知道这不是处理这类数据的正确方法,但我没有选择它。
答案 0 :(得分:1)
将值存储在字符串列表中不是一个好主意。
您选择解决问题的任何解决方案都取决于字符串是否格式良好。
现在这是一个简单的解决方案,假设你的字符串中没有空格,而且分隔符始终是','是
select
reverse(
stuff(
reverse(
stuff(
replace(
','+c+','
,','+cast(@i as nvarchar(max))+','
,','
)
,1,1,'')
)
,1,1,'')
)
from
(values
('1,2,3,4')
,('11,1,1,3')
,('4,2,1')
,('1')
) a(c)
我所做的是我添加一个','到每个字符串的开头和结尾。
然后在替换',1,' (如果你想删除1)用','
这会留下一个两端都有逗号的字符串,这是你不想要的,所以我使用" STUFF"删除第一个逗号,然后我反转结果,并使用&#删除第一个逗号34; STUFF",然后我将字符串反转,最后得到结果
答案 1 :(得分:0)
一种方法是将逗号分隔列表转换为XML,从XML中提取值,删除指定的受害者,然后重新组合剩余的内容。
-- Sample data.
declare @ListsOfNumbers as Table ( Id Int Identity, BadThing VarChar(256) );
insert into @ListsOfNumbers values
( '1,2,3,4' ), ( '11,1,1,3' ), ( '4,2,1' ), ( '1' );
select * from @ListsOfNumbers;
-- Make a new mess.
declare @ValueToDrop as Int = 1;
-- Just to see what's going on: show everything.
select *
from (
select Id, BadThing,
Cast( '<root><csv>' + Replace( BadThing, ',', '</csv><csv>' ) + '</csv></root>' as XML ) as XMLBadThing
from @ListsOfNumbers ) as PH cross apply
( select Val.value( '.', 'integer' ) as Val
from XMLBadThing.nodes( 'root/csv' ) as SeparatedValues( Val ) ) as OtherPH;
-- Just to see what's going on: without the specified target.
select *
from (
select Id, BadThing,
Cast( '<root><csv>' + Replace( BadThing, ',', '</csv><csv>' ) + '</csv></root>' as XML ) as XMLBadThing
from @ListsOfNumbers ) as PH cross apply
( select Val.value( '.', 'integer' ) as Val
from XMLBadThing.nodes( 'root/csv' ) as SeparatedValues( Val ) ) as OtherPH
where Val <> @ValueToDrop;
-- Go from the sample data to regrouped stuff without the target value.
with BadThings as (
select Id, BadThing, XMLBadThing, Val
from (
select Id, BadThing,
Cast( '<root><csv>' + Replace( BadThing, ',', '</csv><csv>' ) + '</csv></root>' as XML ) as XMLBadThing
from @ListsOfNumbers ) as PH cross apply
( select Val.value( '.', 'integer' ) as Val
from XMLBadThing.nodes( 'root/csv' ) as SeparatedValues( Val ) ) as OtherPH
where Val <> @ValueToDrop )
select distinct Id, NewBadThing
from BadThings as BT cross apply
( select Stuff( ( select ',' + Cast( Val as VarChar(10) )
from BadThings where Id = BT.Id order by Val for XML path(''), type).value('.[1]', 'VarChar(max)' ), 1, 1, '' ) as NewBadThing ) as X
<强>更新强>
最终查询的稍微整洁的版本:
with BadThings as ( -- @ListsOfNumbers with the comma-delimited list converted to an XML column.
select Id, BadThing,
Cast( '<root><csv>' + Replace( BadThing, ',', '</csv><csv>' ) + '</csv></root>' as XML ) as XMLBadThing
from @ListsOfNumbers ),
BadThingValues as ( -- BadThings with the XML parsed to produce one value per row.
select Id, BadThing, XMLBadThing, BadThingNodes.XMLNode.value( '.', 'integer' ) as BadThingValue
from BadThings as BT cross apply
XMLBadThing.nodes( 'root/csv' ) as BadThingNodes( XMLNode ) )
-- select * from BadThings; -- To see the first step in the CTE use this SELECT .
-- select * from BadThingValues; -- To see the second step in the CTE use this SELECT .
select distinct BTV.Id, BTV.BadThing, Coalesce( CDL.NewBadThing, '' ) as NewBadThing
from BadThingValues as BTV cross apply
( select Stuff( ( select ',' + Cast( BadThingValue as VarChar(10) )
from BadThingValues
where Id = BTV.Id and BadThingValue <> @ValueToDrop
for XML path(''), type).value('.[1]', 'VarChar(max)' ), 1, 1, '' ) as NewBadThing ) as CDL;
答案 2 :(得分:0)
这里有一些你可以玩的黑客攻击。同样,以这种格式存储数据肯定不是一个明智的想法,尽管你仍然可以在数据库领域之外找到这种有用的东西。
declare @list nvarchar(256) = '1, 2, 1, 3, 4';
declare @value_to_remove nvarchar(16) = '1';
select
replace(substring(
replace(
replace(
', ' + replace(@list, ',', ',,') + ',,,',
', ' + @value_to_remove + ',',
''
), ',,', ','),
3, 256), ',,', ''
)
我甚至在看到其他答案之前写了这个,但注意到它确实处理了相邻的列表项。诀窍是加倍逗号,当然也包括搜索和替换字符串中的周围逗号。
您可能会更清楚这个备用版本。请注意,列表中的值不能包含任何方括号字符。
select
replace(substring(
replace(
replace(
'[ ' + replace(@list, ',', '][') + ']',
'[ ' + @value_to_remove + ']',
''
), '][', ','),
3, 256), ']', ''
);