我的表中有一个字符串列,其中包含“以字符分隔”的数据,例如:
“值|数据| 4 | Z | 2012年11月6日”
此数据被馈送到“解析器”中并反序列化为特定对象。 (此细节无关紧要,无法更改)
我的对象的结构已更改,现在我想摆脱数据的某些“部分”
所以我希望以前的值变成这个
“值|数据| 2012年11月6日”
我希望我能在T-SQL中获得一些帮助。
数据始终具有相同的节数,'n',而我将要为所有行'n-x和'n-y'删除相同的节
到目前为止,我知道我需要一条update语句来更新我的列值。 我发现了分割字符串的各种方法,但是我正在努力将其应用于我的场景。
在C#中我会做
string RemoveSecitons(string value)
{
string[] bits = string.split(value,'|');
List<string> wantedBits = new List<string>();
for(var i = 0; i < bits.Length; i++)
{
if ( i==2 || i==3) // position of sections I no longer want
{
continue;
}
wantedBits.Add(bits[i]);
}
return string.Join(wantedBits,'|');
}
但是我如何在SQL中执行此操作,我不确定从哪里开始。这里的任何帮助将不胜感激
谢谢
Ps。我需要在SQL Server 2012上运行此SQL
编辑:看起来以某种方式解析为xml可能是一个流行的答案,但是我不能保证我的字符串不会包含诸如'<'或'&'
之类的字符。答案 0 :(得分:3)
使用NGrams8K,您可以轻松编写讨厌的快速自定义拆分器。这里的逻辑基于DelimitedSplit8K。即使您发布的C#代码也可能会胜过。
DECLARE @string VARCHAR(8000) = '"Value|Data|4|Z|11/06/2012"',
@delim CHAR(1) = '|';
SELECT newString =
(
SELECT SUBSTRING(
@string, split.pos+1,
ISNULL(NULLIF(CHARINDEX(@delim,@string,split.pos+1),0),8000)-split.pos)
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY d.Pos), d.Pos
FROM
(
SELECT 0 UNION ALL
SELECT ng.position
FROM samd.ngrams8k(@string,1) AS ng
WHERE ng.token = @delim
) AS d(Pos)
) AS split(ItemNumber,Pos)
WHERE split.ItemNumber IN (1,2,5)
ORDER BY split.ItemNumber
FOR XML PATH('')
);
返回:
newString
----------------------------
"Value|Data|11/06/2012"
答案 1 :(得分:2)
您可以尝试一些XQuery
:
DECLARE @s VARCHAR(100)='Value|Data|4|Z|11/06/2012';
SELECT CAST('<x>' + REPLACE(@s,'|','</x><x>') + '</x>' AS XML)
.value('concat(/x[1],"|",/x[2],"|",/x[5])','nvarchar(max)');
简而言之:通过一些字符串替换将值转换为XML。然后,我们使用XQuery
-concat将第一个,第二个和第五个元素再次绑定在一起。
此版本的效率较低,但是可以使用禁止的字符进行安全操作
SELECT CAST('<x>' + REPLACE((SELECT @s AS [*] FOR XML PATH('')),'|','</x><x>') + '</x>' AS XML)
.value('concat(/x[1],"|",/x[2],"|",/x[5])','nvarchar(max)')
答案 2 :(得分:2)
只需添加一个非xml选项即可获得乐趣:
编辑和警告-万一有人尝试此解决方案而又看不到注释...
HABO正确地指出,如果其中任何列中有句点(“。”),则很容易破坏它。 PARSENAME取决于4部分的命名结构,如果超过该名称,则将返回NULL。如果任何值包含另一个管道(“ |”)或添加另一个分隔列,则该解决方案也会中断-我的答案中的子字符串专门存在,作为对4部分命名的依赖的变通方法。例如,如果您尝试在具有7个分隔列的变量上使用此解决方案,则需要对其进行重新处理或废弃,以使用此处的其他答案之一。
std::vector<char>
答案 3 :(得分:2)
不是最优雅的方法,但是可以起作用:
SELECT SUBSTRING(@str,1, CHARINDEX('|',@str,CHARINDEX('|',@str,1)+1)-1)
+ SUBSTRING(@str, CHARINDEX('|',@str,CHARINDEX('|',@str,CHARINDEX('|',@str,CHARINDEX('|',@str,1)+1)+1)+1), LEN(@str))
----------------------
Value|Data|11/06/2012
答案 4 :(得分:0)
这是一种快速的方法。
CREATE FUNCTION [dbo].StringSplitXML
(
@String VARCHAR(MAX), @Separator CHAR(1)
)
RETURNS @RESULT TABLE(id int identity(1,1),Value VARCHAR(MAX))
AS
BEGIN
DECLARE @XML XML
SET @XML = CAST(
('<i>' + REPLACE(@String, @Separator, '</i><i>') + '</i>')
AS XML)
INSERT INTO @RESULT
SELECT t.i.value('.', 'VARCHAR(MAX)')
FROM @XML.nodes('i') AS t(i)
WHERE t.i.value('.', 'VARCHAR(MAX)') <> ''
RETURN
END
GO
SELECT * FROM dbo.StringSplitXML( 'Value|Data|4|Z|11/06/2012','|')
WHERE id not in (3,4)
请注意,使用UDF会使速度变慢,因此仅当您要使用的数据集较小时才应考虑使用此解决方案。