Функция, которая возвращает TABLE после разбиения строки - PullRequest
1 голос
/ 07 апреля 2020

Я хочу создать функцию, которая возвращает таблицу с двумя столбцами, извлеченными из входной строки.

В качестве входных данных функция получает строку типа:

'@Name=John;@Secondname=Kowalsky;@Mail=example@mail.com;'

Функция Предполагается создать из этой строки два столбца - x, y.

X для @value и Y для значения после =.

Я создал это:

Create FUNCTION TwoColumnsFromString (
    @ReplaceString varchar(max)
)
Returns @temptable TABLE (x varchar(max), y varchar(max))
AS 
BEGIN
    DECLARE @value1 varchar(max) 
    WHILE (LEN(@value1)) > 0
    BEGIN    
        SELECT  @value1 = (Select @ReplaceString)
        INSERT INTO @temptable (x,y)
        VALUES ((SUBSTRING(@ReplaceString, CHARINDEX('@', @ReplaceString), CHARINDEX('=',@ReplaceString) -CHARINDEX('@',@ReplaceString))),
            (SUBSTRING(@ReplaceString, CHARINDEX('=', @ReplaceString)+1, CHARINDEX(';',@ReplaceString) -CHARINDEX('=',@ReplaceString)-1)))

        SET @value1 = REPLACE(@value1, SUBSTRING(@value1, 1, CHARINDEX(';', @value1)), '')
    END
    RETURN
END
GO

SELECT *
FROM TwoColumnsFromString('@Name=John;@Secondname=Kowalsky;@Mail=example@mail.com;')

Но это возвращает пустую таблицу. Что я тут не так делаю?

Ответы [ 4 ]

1 голос
/ 07 апреля 2020

Вы потеряли всю свою хорошую работу из предыдущего вопроса:)

  1. Вы должны присвоить @value1 его начальное значение за пределами ваш l oop
  2. Ваши вычисления вставки теперь должны ссылаться на @value1

Ваше тело функции должно быть

    BEGIN
      -- Set starting value outside the loop
      DECLARE @value1 VARCHAR(max) = @ReplaceString;

      WHILE (LEN(@value1)) > 0
      BEGIN
          -- We are now using @value1 not @ReplaceString
          INSERT INTO @temptable (x,y)
          VALUES ((SUBSTRING(@value1, CHARINDEX('@', @value1), CHARINDEX('=',@value1) -CHARINDEX('@',@value1))),
                  (SUBSTRING(@value1, CHARINDEX('=', @value1)+1, CHARINDEX(';',@value1) -CHARINDEX('=',@value1)-1)));

          SET @value1 = REPLACE(@value1, SUBSTRING(@value1, 1, CHARINDEX(';', @value1)), '');
      END
      RETURN;
    END
0 голосов
/ 09 апреля 2020

У меня другая стратегия без циклов, и я использую функцию STRING_SPLIT, доступную с 2016 года на сервере SQL.

Моя идея состоит в том, чтобы дважды разделить одну как структуру, а другую как функцию, поскольку он имеет два символа-разделителя.

  1. Реализация скалярной функции с именем SplitValue следующим образом

    CREATE FUNCTION SplitValue
    (
        @Info as varchar(4000),
        @position as int=1,
        @separator as char
    )
    RETURNS varchar(8000)
    AS 
    BEGIN
        declare @Returnvalue as varchar(4000);
        with DataList as
        (
            SELECT ROW_NUMBER() OVER(ORDER BY value ) AS ID,value as Returnvalue 
            FROM STRING_SPLIT(@Info, @separator)
        )
        select @Returnvalue= isnull(Returnvalue,'')
        from DataList
        where ID = @position
        RETURN @Returnvalue;
    END;
    go
    
  2. Вызовите эту функцию из запроса

    declare @InfoALL as varchar(4000) = '@Name=John;@Secondname=Kowalsky;@Mail=example@mail.com;';
    declare @position as int = 1
    declare @position2 as int = 2
    declare @separator as char = '='
    
    SELECT 
        ROW_NUMBER() OVER(ORDER BY value ) AS ID,
        value,
        dbo.SplitValue(value,1,'=') AS Name,
        dbo.SplitValue(value,2,'=') AS Name
    FROM STRING_SPLIT(@InfoALL, ';')
    where value <> ''
    go
    

Пример

0 голосов
/ 07 апреля 2020

Рабочая функция:

ALTER FUNCTION MailReplacer20 (
@ReplaceString varchar(max)
)
Returns @temptable TABLE (x varchar(max), y varchar(max))
AS 
BEGIN
DECLARE @value1 varchar(max) = @replacestring
WHILE (LEN(@value1)) > 0

    BEGIN
    INSERT INTO @temptable (x,y)
    VALUES ((SUBSTRING(@value1, CHARINDEX('@', @value1), CHARINDEX('=',@value1) -CHARINDEX('@',@value1))),
            (SUBSTRING(@value1, CHARINDEX('=', @value1)+1, CHARINDEX(';',@value1) -CHARINDEX('=',@value1)-1)))

    SET @value1 = REPLACE(@value1, SUBSTRING(@value1, 1, CHARINDEX(';', @value1)), '')
    END
RETURN
END
GO
0 голосов
/ 07 апреля 2020

Почему бы не попробовать что-то подобное вместо этого?

create function [dbo].[fn_GetKeyValuePairs](
    @ReplaceString nvarchar(max)
)
returns table
as return (
    select Left(a.[value], (CharIndex(N'=', a.[Value]) - 1)) as [Key]
         , Right(a.[value], (Len(a.[value]) - CharIndex(N'=', a.[Value]))) as [Value]
    from String_Split(Left(@ReplaceString, Len(@ReplaceString) - CharIndex(N';', Right(@ReplaceString, 1))), N';') as a
);
...