2008-08-05 5 views
433

Использование SQL Server, как мне разделить строку, чтобы я мог получить доступ к элементу x?Как разбить строку, чтобы я мог получить доступ к элементу x?

Возьмите строку «Привет, Джон Смит». Как я могу разделить строку по пробелу и получить доступ к элементу в индексе 1, который должен вернуть «Джон»?

+2

См http://stackoverflow.com/questions/314824/t-sql-opposite-to-string-concatenation-how-to -split-string-into-multiple-recor, а также – 2010-03-08 19:44:58

ответ

174

Вы можете найти решение в SQL User Defined Function to Parse a Delimited String полезно (от The Code Project).

Вы можете использовать эту простую логику:

Declare @products varchar(200) = '1|20|3|343|44|6|8765' 
Declare @individual varchar(20) = null 

WHILE LEN(@products) > 0 
BEGIN 
    IF PATINDEX('%|%', @products) > 0 
    BEGIN 
     SET @individual = SUBSTRING(@products, 
            0, 
            PATINDEX('%|%', @products)) 
     SELECT @individual 

     SET @products = SUBSTRING(@products, 
            LEN(@individual + '|') + 1, 
            LEN(@products)) 
    END 
    ELSE 
    BEGIN 
     SET @individual = @products 
     SET @products = NULL 
     SELECT @individual 
    END 
END 
+1

, почему `SET @p_SourceText = RTRIM (LTRIM (@p_SourceText)) SET @w_Length = DATALENGTH (RTRIM (LTRIM (@p_SourceText)))` , а не `SET @p_SourceText = RTRIM (LTRIM (@p_SourceText)) SET @w_Length = DATALENGTH (@p_SourceText) `? – Beth 2010-09-29 15:13:55

+11

@GateKiller Это решение не поддерживает Unicode и использует жестко закодированное числовое число (18,3), которое не делает его жизнеспособной «многоразовой» функцией. – 2011-03-18 13:55:40

0

Ну, у меня это не все, что проще, но вот код я использую, чтобы разделить с разделителями запятыми входной переменной в отдельные значения, и положить его в переменную таблицы. Я уверен, что вы можете немного изменить это, чтобы разбить на основе пробела, а затем сделать базовый запрос SELECT с этой переменной таблицы, чтобы получить ваши результаты.

-- Create temporary table to parse the list of accounting cycles. 
DECLARE @tblAccountingCycles table 
(
    AccountingCycle varchar(10) 
) 

DECLARE @vchAccountingCycle varchar(10) 
DECLARE @intPosition int 

SET @vchAccountingCycleIDs = LTRIM(RTRIM(@vchAccountingCycleIDs)) + ',' 
SET @intPosition = CHARINDEX(',', @vchAccountingCycleIDs, 1) 

IF REPLACE(@vchAccountingCycleIDs, ',', '') <> '' 
BEGIN 
    WHILE @intPosition > 0 
    BEGIN 
     SET @vchAccountingCycle = LTRIM(RTRIM(LEFT(@vchAccountingCycleIDs, @intPosition - 1))) 
     IF @vchAccountingCycle <> '' 
     BEGIN 
      INSERT INTO @tblAccountingCycles (AccountingCycle) VALUES (@vchAccountingCycle) 
     END 
     SET @vchAccountingCycleIDs = RIGHT(@vchAccountingCycleIDs, LEN(@vchAccountingCycleIDs) - @intPosition) 
     SET @intPosition = CHARINDEX(',', @vchAccountingCycleIDs, 1) 
    END 
END 

Концепция практически такая же. Еще одна альтернатива - использовать совместимость .NET в самом SQL Server 2005. Вы можете по существу написать себе простой метод в .NET, который разделил бы строку, а затем выложил ее как хранимую процедуру/функцию.

+0

пример этого в .NET (процедуры/функции CLR) можно найти здесь http://www.cstruter.com/blog/260 – cstruter 2011-01-28 05:47:01

20

Вот UDF, который это сделает. Он вернет таблицу разделенных значений, не пробовал все сценарии, но ваш пример отлично работает.


CREATE FUNCTION SplitString 
(
    -- Add the parameters for the function here 
    @myString varchar(500), 
    @deliminator varchar(10) 
) 
RETURNS 
@ReturnTable TABLE 
(
    -- Add the column definitions for the TABLE variable here 
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [part] [varchar](50) NULL 
) 
AS 
BEGIN 
     Declare @iSpaces int 
     Declare @part varchar(50) 

     --initialize spaces 
     Select @iSpaces = charindex(@deliminator,@myString,0) 
     While @iSpaces > 0 

     Begin 
      Select @part = substring(@myString,0,charindex(@deliminator,@myString,0)) 

      Insert Into @ReturnTable(part) 
      Select @part 

    Select @myString = substring(@mystring,charindex(@deliminator,@myString,0)+ len(@deliminator),len(@myString) - charindex(' ',@myString,0)) 


      Select @iSpaces = charindex(@deliminator,@myString,0) 
     end 

     If len(@myString) > 0 
      Insert Into @ReturnTable 
      Select @myString 

    RETURN 
END 
GO 

Вы назвали бы это так:


Select * From SplitString('Hello John Smith',' ') 

Edit: Обновленный решение для обработки delimters с Len> 1, как показано:


select * From SplitString('Hello**John**Smith','**') 
+0

Не работает для выберите * из dbo.ethos_SplitString_fn ('guy, wicks , был здесь ',', ') id part ----------- ------------------------- ------------------------- 1 guy 2 wick – Guy 2008-10-20 15:25:24

+2

смотреть с len(), так как он не вернет правильное число, если его аргумент конечные пробелы., например len ('-') = 2. – Rory 2009-10-17 16:30:54

+0

Не работает: выберите * из dbo.SplitString ('foo, foo test ,,,, foo', ',') – cbp 2010-04-14 05:14:35

5

Попробуйте это:

CREATE function [SplitWordList] 
(
@list varchar(8000) 
) 
returns @t table 
(
Word varchar(50) not null, 
Position int identity(1,1) not null 
) 
as begin 
    declare 
    @pos int, 
    @lpos int, 
    @item varchar(100), 
    @ignore varchar(100), 
    @dl int, 
    @a1 int, 
    @a2 int, 
    @z1 int, 
    @z2 int, 
    @n1 int, 
    @n2 int, 
    @c varchar(1), 
    @a smallint 
    select 
    @a1 = ascii('a'), 
    @a2 = ascii('A'), 
    @z1 = ascii('z'), 
    @z2 = ascii('Z'), 
    @n1 = ascii('0'), 
    @n2 = ascii('9') 
    set @ignore = '''"' 
    set @pos = 1 
    set @dl = datalength(@list) 
    set @lpos = 1 
    set @item = '' 
    while (@pos <= @dl) begin 
    set @c = substring(@list, @pos, 1) 
    if (@ignore not like '%' + @c + '%') begin 
     set @a = ascii(@c) 
     if ((@a >= @a1) and (@a <= @z1)) 
     or ((@a >= @a2) and (@a <= @z2)) 
     or ((@a >= @n1) and (@a <= @n2)) 
     begin 
     set @item = @item + @c 
     end else if (@item > '') begin 
     insert into @t values (@item) 
     set @item = '' 
     end 
    end 
    set @pos = @pos + 1 
    end 
    if (@item > '') begin 
    insert into @t values (@item) 
    end 
    return 
end 

Проверьте это следующим образом:

select * from SplitWordList('Hello John Smith') 
+0

Я прошел через это, и это совершенно так, как я хочу! даже я могу настроить его для игнорирования специальных символов, которые я выбираю! – Vikas 2010-09-15 06:57:48

330

Я не верю, что SQL Server имеет встроенный сплит функцию, таким образом, кроме UDF, единственный другой ответ, который я знаю, угнать функция ParseName:

SELECT PARSENAME(REPLACE('Hello John Smith', ' ', '.'), 2) 

ParseName принимает строка и разбивает ее на символ периода. В качестве второго аргумента он принимает число, и это число указывает, какой сегмент строки возвратится (работает от начала до фронта).

SELECT PARSENAME(REPLACE('Hello John Smith', ' ', '.'), 3) --return Hello 

Очевидная проблема в том, что строка уже содержит период. Я все еще думаю, что использование UDF - лучший способ ... любые другие предложения?

+96

Спасибо Saul ... Я должен отметить, что это решение действительно плохое решение для реального развития. PARSENAME ожидает только четыре части, поэтому использование строки с более чем четырьмя частями заставляет ее возвращать NULL. Решения UDF, очевидно, лучше. – 2009-07-01 15:54:58

+30

Это отличный взлом, а также заставляет меня плакать, что что-то подобное нужно для чего-то такого простого, простого на реальных языках. – 2010-07-12 14:09:43

+32

Чтобы индексы работали «правильным» способом, то есть начиная с 1, я захватил ваш захват с помощью REVERSE: REVERSE (PARSENAME (REPLACE (REWERSE ('Hello John Smith'), '', ' . '), 1)) - Возвращает Hello – NothingsImpossible 2012-05-14 13:57:58

105

Во-первых, создать функцию (с помощью КТР, общее табличное выражение покончила с необходимостью для временной таблицы)

create function dbo.SplitString 
    (
     @str nvarchar(4000), 
     @separator char(1) 
    ) 
    returns table 
    AS 
    return (
     with tokens(p, a, b) AS (
      select 
       1, 
       1, 
       charindex(@separator, @str) 
      union all 
      select 
       p + 1, 
       b + 1, 
       charindex(@separator, @str, b + 1) 
      from tokens 
      where b > 0 
     ) 
     select 
      p-1 zeroBasedOccurance, 
      substring(
       @str, 
       a, 
       case when b > 0 then b-a ELSE 4000 end) 
      AS s 
     from tokens 
    ) 
    GO 

Затем, используйте его как любой таблицы (или изменить его, чтобы вписываться в ваш существующий хранится proc) вот так.

select s 
from dbo.SplitString('Hello John Smith', ' ') 
where zeroBasedOccurance=1 

Update

Предыдущая версия потерпит неудачу для входной строки длиннее 4000 символов. Эта версия позаботится об ограничении:

create function dbo.SplitString 
(
    @str nvarchar(max), 
    @separator char(1) 
) 
returns table 
AS 
return (
with tokens(p, a, b) AS (
    select 
     cast(1 as bigint), 
     cast(1 as bigint), 
     charindex(@separator, @str) 
    union all 
    select 
     p + 1, 
     b + 1, 
     charindex(@separator, @str, b + 1) 
    from tokens 
    where b > 0 
) 
select 
    p-1 ItemIndex, 
    substring(
     @str, 
     a, 
     case when b > 0 then b-a ELSE LEN(@str) end) 
    AS s 
from tokens 
); 

GO 

Использование остается неизменным.

+14

Это элегантный, но работает только на 100 элементов из-за предела глубины рекурсии. – Pking 2012-11-07 15:31:18

+3

@Pking, нет, по умолчанию `100` (для предотвращения бесконечного цикла). Используйте [MAXRECURSION hint] (http://msdn.microsoft.com/en-us/library/ms175972%28v=sql.90%29.aspx), чтобы определить количество уровней рекурсии (от 0 до 32767, 0` - «без ограничений» - может раздавить сервер). Кстати, гораздо лучший ответ, чем «PARSENAME», потому что он универсален :-). +1 – 2013-03-14 14:45:06

+0

Добавляя `maxrecursion` к этому решению, помните об этом вопросе и его ответах [Как настроить параметр« maxrecursion »для CTE внутри функции с табличной оценкой] (http://stackoverflow.com/questions/7428669/как в установке самой maxrecursion-вариант-для-а-CTE-внутри-а-табличное значение-функция). – 2013-03-15 09:03:46

37

Вы можете использовать таблицу Number, чтобы выполнить синтаксический анализ строки.

Создание физического номера таблицы:

create table dbo.Numbers (N int primary key); 
    insert into dbo.Numbers 
     select top 1000 row_number() over(order by number) from master..spt_values 
    go 

Создать тестовую таблицу с 1000000 строк

create table #yak (i int identity(1,1) primary key, array varchar(50)) 

    insert into #yak(array) 
     select 'a,b,c' from dbo.Numbers n cross join dbo.Numbers nn 
    go 

создать функцию

create function [dbo].[ufn_ParseArray] 
     ( @Input  nvarchar(4000), 
      @Delimiter char(1) = ',', 
      @BaseIdent int 
     ) 
    returns table as 
    return 
     ( select row_number() over (order by n asc) + (@BaseIdent - 1) [i], 
        substring(@Input, n, charindex(@Delimiter, @Input + @Delimiter, n) - n) s 
      from dbo.Numbers 
      where n <= convert(int, len(@Input)) and 
        substring(@Delimiter + @Input, n, 1) = @Delimiter 
     ) 
    go 

Использование (выходы 3mil строк в 40-х годах на моем ноутбуке)

select * 
    from #yak 
    cross apply dbo.ufn_ParseArray(array, ',', 1) 

очистки

drop table dbo.Numbers; 
    drop function [dbo].[ufn_ParseArray] 

Производительность здесь не удивительно, но вызов функции над таблицей миллионов строк не лучшая идея. Если выполнение строки разделено на многие строки, я бы избегал функции.

+2

. Лучшее решение IMO, другие имеют какое-то ограничение .. это быстро и может анализировать длинные строки со многими элементами. – Pking 2012-12-06 13:01:09

16

Нет кода, но прочитайте окончательную статью по этому вопросу. Все решения в других ответах являются ароматы те, что перечислены в этой статье: Arrays and Lists in SQL Server 2005 and Beyond

Лично я использовал решение Числа таблицы чаще всего потому, что это устраивает то, что я должен сделать ...

6

I искал решение в сети и ниже работает для меня. Ref.

И вы называете функцию следующим образом:

SELECT * FROM dbo.split('ram shyam hari gopal',' ') 

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

CREATE FUNCTION [dbo].[Split](@String VARCHAR(8000), @Delimiter CHAR(1))  
RETURNS @temptable TABLE (items VARCHAR(8000))  
AS  
BEGIN  
    DECLARE @idx INT  
    DECLARE @slice VARCHAR(8000)   
    SELECT @idx = 1  
    IF len(@String)<1 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)  
     SET @String = RIGHT(@String,len(@String) - @idx)  
     IF len(@String) = 0 break  
    END 
    RETURN  
END 
10

По-моему, вы, ребята делают это слишком сложно. Просто создайте UDF CLR и сделайте с ним.

using System; 
using System.Data; 
using System.Data.SqlClient; 
using System.Data.SqlTypes; 
using Microsoft.SqlServer.Server; 
using System.Collections.Generic; 

public partial class UserDefinedFunctions { 
    [SqlFunction] 
    public static SqlString SearchString(string Search) { 
    List<string> SearchWords = new List<string>(); 
    foreach (string s in Search.Split(new char[] { ' ' })) { 
     if (!s.ToLower().Equals("or") && !s.ToLower().Equals("and")) { 
     SearchWords.Add(s); 
     } 
    } 

    return new SqlString(string.Join(" OR ", SearchWords.ToArray())); 
    } 
}; 
+16

Я думаю, это слишком сложно, потому что мне нужно иметь Visual Studio, затем включить CLR на сервере, затем создать и скомпилировать проект и, наконец, добавить сборки в базу данных, чтобы использовать его. Но все же это интересный ответ. – 2012-09-27 13:55:53

2

Я знаю, что это старый вопрос, но я думаю, что кто-то может воспользоваться моим решением.

select 
SUBSTRING(column_name,1,CHARINDEX(' ',column_name,1)-1) 
,SUBSTRING(SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name)) 
    ,1 
    ,CHARINDEX(' ',SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name)),1)-1) 
,SUBSTRING(SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name)) 
    ,CHARINDEX(' ',SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name)),1)+1 
    ,LEN(column_name)) 
from table_name 

SQL FIDDLE

Преимущества:

  • Он отделяет все deliminator 3 суб-строк с ''.
  • Нельзя использовать цикл while, так как он снижает производительность.
  • Нет необходимости Опускайте как все результирующей подстроки будет отображаться в один Роу

Ограничения:

  • нужно знать Total No. пробелов (подстрока).

Примечание: решение может дать подстроку до до N.

Для того, чтобы преодолеть ограничения, мы можем использовать следующие ref.

Но снова вышеуказанный solution не может использоваться в таблице (Actaully i не смог его использовать).

Снова я надеюсь, что это решение может помочь кому-то.

Update: В случае Рекордов> 50000 не рекомендуется использовать LOOPS как это приведет к ухудшению производительности

15

Здесь я выкладываю простой способ решения

CREATE FUNCTION [dbo].[split](
      @delimited NVARCHAR(MAX), 
      @delimiter NVARCHAR(100) 
     ) RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX)) 
     AS 
     BEGIN 
      DECLARE @xml XML 
      SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>' 

      INSERT INTO @t(val) 
      SELECT r.value('.','varchar(MAX)') as item 
      FROM @xml.nodes('/t') as records(r) 
      RETURN 
     END 


Выполните функцию следующим образом

select * from dbo.split('Hello John Smith',' ') 
+0

Мне понравилось это решение. Развернул его, чтобы вернуть скалярное значение на основе указанного столбца в результатах. – Alan 2013-02-22 22:21:09

10

Как насчет использования string и values() заявление?

DECLARE @str varchar(max) 
SET @str = 'Hello John Smith' 

DECLARE @separator varchar(max) 
SET @separator = ' ' 

DECLARE @Splited TABLE(id int IDENTITY(1,1), item varchar(max)) 

SET @str = REPLACE(@str, @separator, '''),(''') 
SET @str = 'SELECT * FROM (VALUES(''' + @str + ''')) AS V(A)' 

INSERT INTO @Splited 
EXEC(@str) 

SELECT * FROM @Splited 

Достигнутый результат.

id item 
1 Hello 
2 John 
3 Smith 
+1

Я использовал ваш ответ, но не работал, но я изменил, и это сработало с объединением всех, я использую sql 2005 – angel 2013-08-13 15:06:08

5

В следующем примере используется рекурсивное CTE

Обновление 18.09.2013

CREATE FUNCTION dbo.SplitStrings_CTE(@List nvarchar(max), @Delimiter nvarchar(1)) 
RETURNS @returns TABLE (val nvarchar(max), [level] int, PRIMARY KEY CLUSTERED([level])) 
AS 
BEGIN 
;WITH cte AS 
(
    SELECT SUBSTRING(@List, 0, CHARINDEX(@Delimiter, @List + @Delimiter)) AS val, 
     CAST(STUFF(@List + @Delimiter, 1, CHARINDEX(@Delimiter, @List + @Delimiter), '') AS nvarchar(max)) AS stval, 
     1 AS [level] 
    UNION ALL 
    SELECT SUBSTRING(stval, 0, CHARINDEX(@Delimiter, stval)), 
     CAST(STUFF(stval, 1, CHARINDEX(@Delimiter, stval), '') AS nvarchar(max)), 
     [level] + 1 
    FROM cte 
    WHERE stval != '' 
) 
    INSERT @returns 
    SELECT REPLACE(val, ' ','') AS val, [level] 
    FROM cte 
    WHERE val > '' 
    RETURN 
END 

Демо на SQLFiddle

-1

Вот мое решение, которое может помочь кому-то. Модификация ответа Джонсайтора выше.

Если у меня есть строка значений INT с ограничением и требуется вернуть таблицу INTs (к которой я могу присоединиться). например'1,20,3,343,44,6,8765'

Создать UDF:

IF OBJECT_ID(N'dbo.ufn_GetIntTableFromDelimitedList', N'TF') IS NOT NULL 
    DROP FUNCTION dbo.[ufn_GetIntTableFromDelimitedList]; 
GO 

CREATE FUNCTION dbo.[ufn_GetIntTableFromDelimitedList](@String NVARCHAR(MAX),     @Delimiter CHAR(1)) 

RETURNS @table TABLE 
(
    Value INT NOT NULL 
) 
AS 
BEGIN 
DECLARE @Pattern NVARCHAR(3) 
SET @Pattern = '%' + @Delimiter + '%' 
DECLARE @Value NVARCHAR(MAX) 

WHILE LEN(@String) > 0 
    BEGIN 
     IF PATINDEX(@Pattern, @String) > 0 
     BEGIN 
      SET @Value = SUBSTRING(@String, 0, PATINDEX(@Pattern, @String)) 
      INSERT INTO @table (Value) VALUES (@Value) 

      SET @String = SUBSTRING(@String, LEN(@Value + @Delimiter) + 1, LEN(@String)) 
     END 
     ELSE 
     BEGIN 
      -- Just the one value. 
      INSERT INTO @table (Value) VALUES (@String) 
      RETURN 
     END 
    END 

RETURN 
END 
GO 

Затем получить табличные результаты:

SELECT * FROM dbo.[ufn_GetIntTableFromDelimitedList]('1,20,3,343,44,6,8765', ',') 

1 
20 
3 
343 
44 
6 
8765 

И в присоединиться заявление:

SELECT [ID], [FirstName] 
FROM [User] u 
JOIN dbo.[ufn_GetIntTableFromDelimitedList]('1,20,3,343,44,6,8765', ',') t ON u.[ID] = t.[Value] 

1 Elvis 
20 Karen 
3 David 
343 Simon 
44 Raj 
6 Mike 
8765 Richard 

Если вы хотите вернуть список NVARCHAR вместо INT, просто измените определение таблицы:

RETURNS @table TABLE 
(
    Value NVARCHAR(MAX) NOT NULL 
) 
0

Это то, что я сделал, чтобы получить конкретный токен в строке. (Проверено в MSSQL 2008)

Во-первых, создавая следующие функции: (найденные в: here

CREATE FUNCTION dbo.SplitStrings_Moden 
(
    @List NVARCHAR(MAX), 
    @Delimiter NVARCHAR(255) 
) 
RETURNS TABLE 
WITH SCHEMABINDING AS 
RETURN 
    WITH E1(N)  AS (SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1), 
     E2(N)  AS (SELECT 1 FROM E1 a, E1 b), 
     E4(N)  AS (SELECT 1 FROM E2 a, E2 b), 
     E42(N)  AS (SELECT 1 FROM E4 a, E2 b), 
     cteTally(N) AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1))) 
         ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42), 
     cteStart(N1) AS (SELECT t.N+1 FROM cteTally t 
         WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0)) 
    SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000)) 
    FROM cteStart s; 

и

create FUNCTION dbo.getToken 
(
@List NVARCHAR(MAX), 
@Delimiter NVARCHAR(255), 
@Pos int 
) 
RETURNS varchar(max) 
as 
begin 
declare @returnValue varchar(max); 
select @returnValue = tbl.Item from (
select ROW_NUMBER() over (order by (select null)) as id, * from dbo.SplitStrings_Moden(@List, @Delimiter) 
) as tbl 
where tbl.id = @Pos 
return @returnValue 
end 

, то вы можете использовать его так:

select dbo.getToken('1111_2222_3333_', '_', 1) 

которые возвращаются 1111

8

Я использую ответ Фридерика, но это не работает в SQL Server 2005

Я изменил его, и я использую select с union all и работает

DECLARE @str varchar(max) 
SET @str = 'Hello John Smith how are you' 

DECLARE @separator varchar(max) 
SET @separator = ' ' 

DECLARE @Splited table(id int IDENTITY(1,1), item varchar(max)) 

SET @str = REPLACE(@str, @separator, ''' UNION ALL SELECT ''') 
SET @str = ' SELECT ''' + @str + ''' ' 

INSERT INTO @Splited 
EXEC(@str) 

SELECT * FROM @Splited 

И результат-набор:

id item 
1 Hello 
2 John 
3 Smith 
4 how 
5 are 
6 you 
3


    Alter Function dbo.fn_Split 
    (
    @Expression nvarchar(max), 
    @Delimiter nvarchar(20) = ',', 
    @Qualifier char(1) = Null 
    ) 
    RETURNS @Results TABLE (id int IDENTITY(1,1), value nvarchar(max)) 
    AS 
    BEGIN 
     /* USAGE 
      Select * From dbo.fn_Split('apple pear grape banana orange honeydew cantalope 3 2 1 4', ' ', Null) 
      Select * From dbo.fn_Split('1,abc,"Doe, John",4', ',', '"') 
      Select * From dbo.fn_Split('Hello 0,"&""&&&&', ',', '"') 
     */ 

     -- Declare Variables 
     DECLARE 
      @X  xml, 
      @Temp nvarchar(max), 
      @Temp2 nvarchar(max), 
      @Start int, 
      @End int 

     -- HTML Encode @Expression 
     Select @Expression = (Select @Expression For XML Path('')) 

     -- Find all occurences of @Delimiter within @Qualifier and replace with |||***||| 
     While PATINDEX('%' + @Qualifier + '%', @Expression) > 0 AND Len(IsNull(@Qualifier, '')) > 0 
     BEGIN 
      Select 
      -- Starting character position of @Qualifier 
      @Start = PATINDEX('%' + @Qualifier + '%', @Expression), 
      -- @Expression starting at the @Start position 
      @Temp = SubString(@Expression, @Start + 1, LEN(@Expression)[email protected]+1), 
      -- Next position of @Qualifier within @Expression 
      @End = PATINDEX('%' + @Qualifier + '%', @Temp) - 1, 
      -- The part of Expression found between the @Qualifiers 
      @Temp2 = Case When @End < 0 Then @Temp Else Left(@Temp, @End) End, 
      -- New @Expression 
      @Expression = REPLACE(@Expression, 
            @Qualifier + @Temp2 + Case When @End < 0 Then '' Else @Qualifier End, 
            Replace(@Temp2, @Delimiter, '|||***|||') 
          ) 
     END 

     -- Replace all occurences of @Delimiter within @Expression with '</fn_Split>&ltfn_Split>' 
     -- And convert it to XML so we can select from it 
     SET 
      @X = Cast('&ltfn_Split>' + 
        Replace(@Expression, @Delimiter, '</fn_Split>&ltfn_Split>') + 
        '</fn_Split>' as xml) 

     -- Insert into our returnable table replacing '|||***|||' back to @Delimiter 
     INSERT @Results 
     SELECT 
      "Value" = LTRIM(RTrim(Replace(C.value('.', 'nvarchar(max)'), '|||***|||', @Delimiter))) 
     FROM 
      @X.nodes('fn_Split') as X(C) 

     -- Return our temp table 
     RETURN 
    END 

49

Большинство решений здесь использует в то время как петлю или рекурсивный КТР.Подход на основе набора будет выше, я обещаю:

CREATE FUNCTION [dbo].[SplitString] 
    (
     @List NVARCHAR(MAX), 
     @Delim VARCHAR(255) 
    ) 
    RETURNS TABLE 
    AS 
     RETURN (SELECT [Value] FROM 
      ( 
      SELECT 
       [Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number], 
       CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number]))) 
      FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name) 
       FROM sys.all_objects) AS x 
       WHERE Number <= LEN(@List) 
       AND SUBSTRING(@Delim + @List, [Number], LEN(@Delim)) = @Delim 
     ) AS y 
     ); 

Подробнее о расщепленных функциях, почему (и доказательстве того, что) в то время как петля и рекурсивный, CTE не масштабируются, и лучшими альтернатив, если расщепление строк, поступающие от Прикладной уровень:

http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings

http://www.sqlperformance.com/2012/08/t-sql-queries/splitting-strings-now-with-less-t-sql

http://sqlblog.com/blogs/aaron_bertrand/archive/2010/07/07/splitting-a-list-of-integers-another-roundup.aspx

0

Рекурсивный решение КТР с болью сервера, test it

сервера Настройка MS SQL 2008 схемы:

create table Course(Courses varchar(100)); 
insert into Course values ('Hello John Smith'); 

Запрос 1:

with cte as 
    (select 
     left(Courses, charindex(' ' , Courses)) as a_l, 
     cast(substring(Courses, 
         charindex(' ' , Courses) + 1 , 
         len(Courses)) + ' ' 
       as varchar(100)) as a_r, 
     Courses as a, 
     0 as n 
    from Course t 
    union all 
     select 
     left(a_r, charindex(' ' , a_r)) as a_l, 
     substring(a_r, charindex(' ' , a_r) + 1 , len(a_R)) as a_r, 
     cte.a, 
     cte.n + 1 as n 
    from Course t inner join cte 
     on t.Courses = cte.a and len(a_r) > 0 

    ) 
select a_l, n from cte 
--where N = 1 

Results:

| A_L | N | 
|--------|---| 
| Hello | 0 | 
| John | 1 | 
| Smith | 2 | 
-1

Вот SQL UDF, который может разделить строку и захватить только определенную часть.

create FUNCTION [dbo].[udf_SplitParseOut] 
(
    @List nvarchar(MAX), 
    @SplitOn nvarchar(5), 
    @GetIndex smallint 
) 
returns varchar(1000) 
AS 

BEGIN 

DECLARE @RtnValue table 
(

    Id int identity(0,1), 
    Value nvarchar(MAX) 
) 


    DECLARE @result varchar(1000) 

    While (Charindex(@SplitOn,@List)>0) 
    Begin 
     Insert Into @RtnValue (value) 
     Select Value = ltrim(rtrim(Substring(@List,1,Charindex(@SplitOn,@List)-1))) 
     Set @List = Substring(@List,Charindex(@SplitOn,@List)+len(@SplitOn),len(@List)) 
    End 

    Insert Into @RtnValue (Value) 
    Select Value = ltrim(rtrim(@List)) 

    select @result = value from @RtnValue where ID = @GetIndex 

    Return @result 
END 
-1

Простой оптимизированный алгоритм:

ALTER FUNCTION [dbo].[Split](@Text NVARCHAR(200),@Splitor CHAR(1)) 
RETURNS @Result TABLE (value NVARCHAR(50)) 
AS 
BEGIN 
    DECLARE @PathInd INT 
    Set @[email protected] 
    WHILE LEN(@Text) > 0 
    BEGIN 
     SET @PathInd=PATINDEX('%'[email protected]+'%',@Text) 
     INSERT INTO @Result VALUES(SUBSTRING(@Text, 0, @PathInd)) 
     SET @Text= SUBSTRING(@Text, @PathInd+1, LEN(@Text)) 
    END 
     RETURN 
END 
-1

Я использовал ответ vzczc, используя рекурсивное ОТВ в течение некоторого времени, но хотел, чтобы обновить его обработать переменную разделитель длины, а также для обработки строк с ведущими и отстающими «разделители», такие как, когда у вас есть CSV-файл с записями, такие как:

«Боб», «Смит», «Саннивейл», «CA»

или когда вы имеете дело с шестью частями fqn, как показано ниже. Я использую их широко для регистрации в subject_fqn для аудита, обработки ошибок и т.д., и ParseName обрабатывает только четыре части:

[netbios_name].[machine_name].[instance].[database].[schema].[table].[column] 

Вот моя обновленная версия, и благодаря vzczc за его оригинальный пост!

select * from [utility].[split_string](N'"this"."string"."gets"."split"."and"."removes"."leading"."and"."trailing"."quotes"', N'"."', N'"', N'"'); 

select * from [utility].[split_string](N'"this"."string"."gets"."split"."but"."leaves"."leading"."and"."trailing"."quotes"', N'"."', null, null); 

select * from [utility].[split_string](N'[netbios_name].[machine_name].[instance].[database].[schema].[table].[column]', N'].[', N'[', N']'); 

create function [utility].[split_string] ( 
    @input  [nvarchar](max) 
    , @separator [sysname] 
    , @lead  [sysname] 
    , @lag  [sysname]) 
returns @node_list table ( 
    [index] [int] 
    , [node] [nvarchar](max)) 
    begin 
     declare @separator_length [int]= len(@separator) 
       , @lead_length [int] = isnull(len(@lead), 0) 
       , @lag_length  [int] = isnull(len(@lag), 0); 
     -- 
     set @input = right(@input, len(@input) - @lead_length); 
     set @input = left(@input, len(@input) - @lag_length); 
     -- 
     with [splitter]([index], [starting_position], [start_location]) 
      as (select cast(@separator_length as [bigint]) 
         , cast(1 as [bigint]) 
         , charindex(@separator, @input) 
       union all 
       select [index] + 1 
         , [start_location] + @separator_length 
         , charindex(@separator, @input, [start_location] + @separator_length) 
       from [splitter] 
       where [start_location] > 0) 
     -- 
     insert into @node_list 
        ([index],[node]) 
     select [index] - @separator_length     as [index] 
       , substring(@input, [starting_position], case 
                  when [start_location] > 0 
                   then 
                   [start_location] - [starting_position] 
                  else 
                   len(@input) 
                 end) as [node] 
     from [splitter]; 
     -- 
     return; 
    end; 
go 
2

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

Я охватывают гораздо лучший способ сделать строку раскол здесь: http://www.digitalruby.com/split-string-sql-server/

Вот код:

SET NOCOUNT ON 

-- You will want to change nvarchar(MAX) to nvarchar(50), varchar(50) or whatever matches exactly with the string column you will be searching against 
DECLARE @SplitStringTable TABLE (Value nvarchar(MAX) NOT NULL) 
DECLARE @StringToSplit nvarchar(MAX) = 'your|string|to|split|here' 
DECLARE @SplitEndPos int 
DECLARE @SplitValue nvarchar(MAX) 
DECLARE @SplitDelim nvarchar(1) = '|' 
DECLARE @SplitStartPos int = 1 

SET @SplitEndPos = CHARINDEX(@SplitDelim, @StringToSplit, @SplitStartPos) 

WHILE @SplitEndPos > 0 
BEGIN 
    SET @SplitValue = SUBSTRING(@StringToSplit, @SplitStartPos, (@SplitEndPos - @SplitStartPos)) 
    INSERT @SplitStringTable (Value) VALUES (@SplitValue) 
    SET @SplitStartPos = @SplitEndPos + 1 
    SET @SplitEndPos = CHARINDEX(@SplitDelim, @StringToSplit, @SplitStartPos) 
END 

SET @SplitValue = SUBSTRING(@StringToSplit, @SplitStartPos, 2147483647) 
INSERT @SplitStringTable (Value) VALUES(@SplitValue) 

SET NOCOUNT OFF 

-- You can select or join with the values in @SplitStringTable at this point. 
7

Эта модель хорошо работает, и вы можете обобщать

Convert(xml,'<n>'+Replace(FIELD,'.','</n><n>')+'</n>').value('(/n[INDEX])','TYPE') 
          ^^^^^         ^^^^^  ^^^^ 

сведению FIELD, ИНДЕКС и TYP E.

Пусть некоторая таблица с идентификаторами как

sys.message.1234.warning.A45 
sys.message.1235.error.O98 
.... 

Затем вы можете написать

SELECT Source   = q.value('(/n[1])', 'varchar(10)'), 
     RecordType  = q.value('(/n[2])', 'varchar(20)'), 
     RecordNumber = q.value('(/n[3])', 'int'), 
     Status   = q.value('(/n[4])', 'varchar(5)') 
FROM (
     SELECT q = Convert(xml,'<n>'+Replace(fieldName,'.','</n><n>')+'</n>') 
     FROM  some_TABLE 
     ) Q 

расщеплению и литье все детали.

0

пока аналогично ответу на основе XML с помощью josejuan, я обнаружил, что обработка путь XML только один раз, а затем поворачиваясь умеренно более эффективным:

select ID, 
    [3] as PathProvidingID, 
    [4] as PathProvider, 
    [5] as ComponentProvidingID, 
    [6] as ComponentProviding, 
    [7] as InputRecievingID, 
    [8] as InputRecieving, 
    [9] as RowsPassed, 
    [10] as InputRecieving2 
    from 
    (
    select id,message,d.* from sysssislog cross apply  ( 
      SELECT Item = y.i.value('(./text())[1]', 'varchar(200)'), 
       row_number() over(order by y.i) as rn 
      FROM 
      ( 
      SELECT x = CONVERT(XML, '<i>' + REPLACE(Message, ':', '</i><i>') + '</i>').query('.') 
     ) AS a CROSS APPLY x.nodes('i') AS y(i) 
     ) d 
     WHERE event 
     = 
     'OnPipelineRowsSent' 
    ) as tokens 
    pivot 
    (max(item) for [rn] in ([3],[4],[5],[6],[7],[8],[9],[10]) 
    ) as data 

побежал в 8.30

select id, 
tokens.value('(/n[3])', 'varchar(100)')as PathProvidingID, 
tokens.value('(/n[4])', 'varchar(100)') as PathProvider, 
tokens.value('(/n[5])', 'varchar(100)') as ComponentProvidingID, 
tokens.value('(/n[6])', 'varchar(100)') as ComponentProviding, 
tokens.value('(/n[7])', 'varchar(100)') as InputRecievingID, 
tokens.value('(/n[8])', 'varchar(100)') as InputRecieving, 
tokens.value('(/n[9])', 'varchar(100)') as RowsPassed 
from 
(
    select id, Convert(xml,'<n>'+Replace(message,'.','</n><n>')+'</n>') tokens 
     from sysssislog 
     WHERE event 
     = 
     'OnPipelineRowsSent' 
    ) as data 

побежал в 9:20

0
CREATE FUNCTION [dbo].[fnSplitString] 
( 
    @string NVARCHAR(MAX), 
    @delimiter CHAR(1) 
) 
RETURNS @output TABLE(splitdata NVARCHAR(MAX) 
) 
BEGIN 
    DECLARE @start INT, @end INT 
    SELECT @start = 1, @end = CHARINDEX(@delimiter, @string) 
    WHILE @start < LEN(@string) + 1 BEGIN 
     IF @end = 0 
      SET @end = LEN(@string) + 1 

     INSERT INTO @output (splitdata) 
     VALUES(SUBSTRING(@string, @start, @end - @start)) 
     SET @start = @end + 1 
     SET @end = CHARINDEX(@delimiter, @string, @start) 

    END 
    RETURN 
END 

и использовать его

select *from dbo.fnSplitString('Querying SQL Server','') 
1

Pure set-based solution with TVF с рекурсивным CTE. Вы можете JOIN и APPLY эту функцию для любого набора данных.

create function [dbo].[SplitStringToResultSet] (@value varchar(max), @separator char(1)) 
returns table 
as return 
with r as (
    select value, cast(null as varchar(max)) [x], -1 [no] from (select rtrim(cast(@value as varchar(max))) [value]) as j 
    union all 
    select right(value, len(value)-case charindex(@separator, value) when 0 then len(value) else charindex(@separator, value) end) [value] 
    , left(r.[value], case charindex(@separator, r.value) when 0 then len(r.value) else abs(charindex(@separator, r.[value])-1) end) [x] 
    , [no] + 1 [no] 
    from r where value > '') 

select ltrim(x) [value], [no] [index] from r where x is not null; 
go 

Использование:

select * 
from [dbo].[SplitStringToResultSet]('Hello John Smith', ' ') 
where [index] = 1; 

Результат:

value index 
------------- 
John 1 
0

если кто-то хочет получить только одну часть seperatured текста можно использовать этот

выберите * из fromSplitStringSep ('Word1 wordr2 word3', '')

CREATE function [dbo].[SplitStringSep] 
(
    @str nvarchar(4000), 
    @separator char(1) 
) 
returns table 
AS 
return (
    with tokens(p, a, b) AS (
     select 
     1, 
     1, 
     charindex(@separator, @str) 
     union all 
     select 
      p + 1, 
      b + 1, 
      charindex(@separator, @str, b + 1) 
     from tokens 
     where b > 0 
     ) 
     select 
      p-1 zeroBasedOccurance, 
      substring(
       @str, 
       a, 
       case when b > 0 then b-a ELSE 4000 end) 
      AS s 
     from tokens 
) 
0

Я devoloped это,

declare @x nvarchar(Max) = 'ali.veli.deli.'; 
declare @item nvarchar(Max); 
declare @splitter char='.'; 

while CHARINDEX(@splitter,@x) != 0 
begin 
    set @item = LEFT(@x,CHARINDEX(@splitter,@x)) 
    set @x = RIGHT(@x,len(@x)-len(@item)) 
    select @item as item, @x as x; 
end 

только внимание вы должны это точка '' этот конец @x всегда должен быть там.

2

Вы можете разделить строку в SQL без необходимости функции:

DECLARE @bla varchar(MAX) 
SET @bla = 'BED40DFC-F468-46DD-8017-00EF2FA3E4A4,64B59FC5-3F4D-4B0E-9A48-01F3D4F220B0,A611A108-97CA-42F3-A2E1-057165339719,E72D95EA-578F-45FC-88E5-075F66FD726C' 

-- http://stackoverflow.com/questions/14712864/how-to-query-values-from-xml-nodes 
SELECT 
    x.XmlCol.value('.', 'varchar(36)') AS val 
FROM 
(
    SELECT 
    CAST('<e>' + REPLACE(@bla, ',', '</e><e>') + '</e>' AS xml) AS RawXml 
) AS b 
CROSS APPLY b.RawXml.nodes('e') x(XmlCol); 

Если вам необходимо поддерживать произвольные строки (с XML специальные символы)

DECLARE @bla NVARCHAR(MAX) 
SET @bla = '<html>unsafe & safe Utf8CharsDon''tGetEncoded ÄöÜ - "Conex"<html>,Barnes & Noble,abc,def,ghi' 

-- http://stackoverflow.com/questions/14712864/how-to-query-values-from-xml-nodes 
SELECT 
    x.XmlCol.value('.', 'nvarchar(MAX)') AS val 
FROM 
(
    SELECT 
    CAST('<e>' + REPLACE((SELECT @bla FOR XML PATH('')), ',', '</e><e>') + '</e>' AS xml) AS RawXml 
) AS b 
CROSS APPLY b.RawXml.nodes('e') x(XmlCol); 
6

Еще одна часть получить n-й строки по разделители функции:

create function GetStringPartByDelimeter (
    @value as nvarchar(max), 
    @delimeter as nvarchar(max), 
    @position as int 
) returns NVARCHAR(MAX) 
AS BEGIN 
    declare @startPos as int 
    declare @endPos as int 
    set @endPos = -1 
    while (@position > 0 and @endPos != 0) begin 
     set @startPos = @endPos + 1 
     set @endPos = charindex(@delimeter, @value, @startPos) 

     if(@position = 1) begin 
      if(@endPos = 0) 
       set @endPos = len(@value) + 1 

      return substring(@value, @startPos, @endPos - @startPos) 
     end 

     set @position = @position - 1 
    end 

    return null 
end 

и использования:

select dbo.GetStringPartByDelimeter ('a;b;c;d;e', ';', 3) 

, которая возвращает:

c 
9

Этот вопрос не о струнном разделенном подходе, но о как получить п-й элемента.

Все ответы здесь делают какие-то строки расщепления с помощью рекурсии, CTE с, многократный CHARINDEX, REVERSE и PATINDEX, изобретая функции, вызов методов CLR, количество таблиц, CROSS APPLY ы ... Большинство ответов охватывают множество строк кода ,

Но - если вы действительно ничего не хочу больше, чем подход, чтобы получить п-й элемент - это может быть сделано, как реального однострочника, не UDF, даже суб-выбора ... И как дополнительное преимущество: типа сейфа

Получить часть 2 разделенных пробелами:

DECLARE @input NVARCHAR(100)=N'part1 part2 part3'; 
SELECT CAST(N'<x>' + REPLACE(@input,N' ',N'</x><x>') + N'</x>' AS XML).value('/x[2]','nvarchar(max)') 

конечно вы можете использовать переменные для разделителей и положения (используйте sql:column, чтобы получить позицию непосредственно из значения запроса, в):

DECLARE @dlmt NVARCHAR(10)=N' '; 
DECLARE @pos INT = 2; 
SELECT CAST(N'<x>' + REPLACE(@input,@dlmt,N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)') 

Если строка может включать запрещенные символы (особенно один из &><), вы можете сделать это таким образом. Просто используйте FOR XML PATH в своей строке, чтобы заменить все запрещенные символы неявно.

Это особый случай, если - дополнительно - Ваш разделитель - это точка с запятой. В этом случае я заменить разделитель первым на «# DLMT #», и заменить это теги XML, наконец:

SET @input=N'Some <, > and &;Other äöü@€;One more'; 
SET @dlmt=N';'; 
SELECT CAST(N'<x>' + REPLACE((SELECT REPLACE(@input,@dlmt,'#DLMT#') AS [*] FOR XML PATH('')),N'#DLMT#',N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)'); 
0
declare @strng varchar(max)='hello john smith' 
select (
    substring(
     @strng, 
     charindex(' ', @strng) + 1, 
     (
      (charindex(' ', @strng, charindex(' ', @strng) + 1)) 
      - charindex(' ',@strng) 
     ) 
    )) 
0

здание на @NothingsImpossible растворе, или, скорее, комментарий на самый голосовавшие ответ (чуть ниже принятого), я нашел следующее быстро и грязно. Решение удовлетворяет моим собственным потребностям - оно имеет преимущество только в пределах домена SQL.

для строки «первая, вторая, третья, четвертая, пятая», скажем, я хочу получить третий токен. это работает только в том случае, если мы знаем, сколько жетонов будет иметь строка - в этом случае это 5.поэтому мой способ действий состоит в том, чтобы вырезать последние два токена (внутренний запрос), а затем отрубить первые два токена (внешний запрос)

Я знаю, что это уродливо и покрывает определенные условия, в которых я был, но я отправляю его на всякий случай, если кто-то сочтет это полезным. веселит

select 
    REVERSE(
     SUBSTRING(
      reverse_substring, 
      0, 
      CHARINDEX(';', reverse_substring) 
     ) 
    ) 
from 
(
    select 
     msg, 
     SUBSTRING(
      REVERSE(msg), 
      CHARINDEX(
       ';', 
       REVERSE(msg), 
       CHARINDEX(
        ';', 
        REVERSE(msg) 
       )+1 
      )+1, 
      1000 
     ) reverse_substring 
    from 
    (
     select 'first;second;third;fourth;fifth' msg 
    ) a 
) b 
1

Начиная с SQL Server 2016 мы string_split

DECLARE @string varchar(100) = 'Richard, Mike, Mark' 

SELECT value FROM string_split(@string, ',') 
0

Современный подход с использованием STRING_SPLIT, требует SQL Server 2016 и выше.

DECLARE @string varchar(100) = 'Hello John Smith' 

SELECT 
    ROW_NUMBER() OVER (ORDER BY value) AS RowNr, 
    value 
FROM string_split(@string, ' ') 

Результат:

RowNr value 
1  Hello 
2  John 
3  Smith 

Теперь можно получить й п-го элемента из числа строк.

0

Вы можете использовать функцию STRING_SPLIT, доступную в SQL Server 2016 или более поздней версии. Следует иметь в виду, что нет гарантии, что подстроки будут возвращены в любом конкретном порядке.

WITH testdata(id, string) AS (
    SELECT 1, NULL UNION ALL 
    SELECT 2, 'a' UNION ALL 
    SELECT 3, 'a b' UNION ALL 
    SELECT 4, 'a b c' UNION ALL 
    SELECT 5, 'a b c d' 
) 
SELECT testdata.id, testdata.string, (
    SELECT value AS substr FROM STRING_SPLIT(testdata.string, ' ') FOR XML PATH(''), TYPE 
).value('substr[2]', 'VARCHAR(100)') AS [2nd_substr] 
FROM testdata 

Где:

  • STRING_SPLIT возвращает таблицу с одной колонке под названием value
  • FOR XML PATH('') преобразует строки в <substr>a</substr><substr>b</substr>...
  • TYPE преобразует выше, чтобы XML тип данных
  • value('substr[2]', 'VARCHAR(100)') работает XPATH expressio п на выше и возвращает VARCHAR тип данных

Результат:

| id | string | 2nd_substr | 
|----|---------|------------| 
| 1 | NULL | NULL  | 
| 2 | a  | NULL  | 
| 3 | a b  | b   | 
| 4 | a b c | b   | 
| 5 | a b c d | b   | 

 Смежные вопросы

  • Нет связанных вопросов^_^