Получить последние три значения в строке с разделителями, используя SQL Server - PullRequest
0 голосов
/ 24 июня 2018

Я хотел бы извлечь только последние три значения из строки с разделителями и сгенерировать подстроку с разделителями из этих трех значений.Кто-нибудь может подсказать, как лучше всего это сделать.Я попытался использовать 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'

Ответы [ 3 ]

0 голосов
/ 24 июня 2018

Возможно, еще один вариант, использующий немного 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
0 голосов
/ 24 июня 2018

Я использую эту табличную функцию уже много лет.Работает отлично.После создания вызова функции 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  
0 голосов
/ 24 июня 2018

К сожалению, 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;
...