我只想从定界字符串中提取最后三个值,并用这三个值生成定界子字符串。任何人都可以建议什么是最好的方法。我尝试使用STRING_SPLIT并能够成功地将字符串拆分为多个值,但是我不确定如何继续进行。任何想法都将不胜感激。
SELECT value FROM STRING_SPLIT('CatalogTypeCode VARCHAR(10) NOT NULL
,EventID INT NOT NULL
,ModelCode TINYINT NOT NULL
,YearID INT NOT NULL
,PerilSetCode INT NOT NULL
,GrossLoss FLOAT NULL
,GrossSD FLOAT NULL
,GrossMaxLoss FLOAT NULL',',')
输出:
CatalogTypeCode VARCHAR(10) NOT NULL
EventID INT NOT NULL
ModelCode TINYINT NOT NULL
YearID INT NOT NULL
PerilSetCode INT NOT NULL
GrossLoss FLOAT NULL
GrossSD FLOAT NULL
GrossMaxLoss FLOAT NULL
预期输出:
'GrossLoss FLOAT NULL,GrossSD FLOAT NULL,GrossMaxLoss FLOAT NULL'
答案 0 :(得分:2)
也许另一个选择是与XML
...一起使用一点reverse()
...两次
示例
Declare @YourTable table (ID int,SomeCol varchar(150))
Insert Into @YourTable values
(1,'Val1,Val2,Val3,Val4')
,(2,'Val1,Val2,Val3,Val4,Val5,Val6')
,(3,'Val1,Val2')
,(4,'Val1')
,(5,null)
Select A.ID
,LastThree = reverse(concat(Pos1,','+Pos2,','+Pos3))
From @YourTable A
Cross Apply (
Select Pos1 = n.value('/x[1]','varchar(max)')
,Pos2 = n.value('/x[2]','varchar(max)')
,Pos3 = n.value('/x[3]','varchar(max)')
From (Select cast('<x>' + replace(reverse(SomeCol),',','</x><x>')+'</x>' as xml) as n) X
) B
返回
ID LastThree
1 Val2,Val3,Val4
2 Val4,Val5,Val6
3 Val1,Val2 -- Notice only 2 values
4 Val1 -- Notice only 1 value
5 -- Notice value was null
答案 1 :(得分:0)
不幸的是,split_string()
不会返回值在字符串中的位置。
这将起作用,假设各行之间没有重复:
SELECT string_agg(line, ',') within group (order by pos) as lines_3
FROM (SELECT TOP (3) s.line, CHARINDEX(line, lines) as pos
FROM (VALUES ('CatalogTypeCode VARCHAR(10) NOT NULL
,EventID INT NOT NULL
,ModelCode TINYINT NOT NULL
,YearID INT NOT NULL
,PerilSetCode INT NOT NULL
,GrossLoss FLOAT NULL
,GrossSD FLOAT NULL
,GrossMaxLoss FLOAT NULL')
) v(lines) OUTER APPLY
STRING_SPLIT(v.lines, ',') s(line)
ORDER BY pos
) s
编辑:
糟糕,以上内容适用于SQL Server 2017,但不适用于2016。您可以使用条件聚合:
SELECT (MAX(CASE WHEN seqnum = 1 THEN line END) + ','
MAX(CASE WHEN seqnum = 2 THEN line END) + ','
MAX(CASE WHEN seqnum = 3 THEN line END)
) as lines_3
FROM (SELECT TOP (3) s.line,
ROW_NUMBER() OVER (ORDER BY CHARINDEX(line, lines)) as seqnum
FROM (VALUES ('CatalogTypeCode VARCHAR(10) NOT NULL
,EventID INT NOT NULL
,ModelCode TINYINT NOT NULL
,YearID INT NOT NULL
,PerilSetCode INT NOT NULL
,GrossLoss FLOAT NULL
,GrossSD FLOAT NULL
,GrossMaxLoss FLOAT NULL')
) v(lines) OUTER APPLY
STRING_SPLIT(v.lines, ',') s(line)
ORDER BY pos
) s;
答案 2 :(得分:0)
我使用这种表值函数已有多年了。工作良好。创建函数后,请select top 3 * from lma.dbo.split_test('a,b,c,d,e',',') order by id desc
CREATE FUNCTION [dbo].[Split]
(
@String VARCHAR(MAX),
@Delimiter VARCHAR(10)
)
RETURNS @Temptable TABLE (id int identity, items varchar(MAX))
AS
BEGIN
DECLARE @Idx INT
DECLARE @Slice VARCHAR(MAX)
DECLARE @Delimiterlen INT=LEN(@Delimiter)
--,@String VARCHAR(MAX)='N'
--,@Delimiter VARCHAR(10)=';;'
IF (@String like '%' + @Delimiter + '%')
BEGIN
SELECT @Idx = 1
IF LEN(@String)<@Delimiterlen or @String is null RETURN
WHILE @Idx!= 0
BEGIN
SET @Idx = CHARINDEX(@Delimiter,@String)
IF @Idx!=0
SET @Slice = left(@String,@idx-1)
ELSE
SET @Slice = @String
IF(LEN(@Slice)>0)
INSERT INTO @Temptable(Items) values(@Slice)
--290913 : IF WE WANT TO USE DELIMETER LENGTH GREATER THAN 2
IF LEN(@String) >= (@Idx -1 + @Delimiterlen)
SET @String = RIGHT(@String,LEN(@String) - (@Idx-1+@Delimiterlen))
IF LEN(@String) = 0 BREAK
END
END
ELSE
BEGIN
INSERT INTO @Temptable(Items) values(@String)
END
DELETE @Temptable WHERE items =''
RETURN
END