Jak mohu rozdělit řetězec, abych mohl přistupovat Položka X?

hlasů
442

Používání SQL Server, jak mohu rozdělit řetězec, abych mohl přistupovat Položka X?

Pak se řetězec „Dobrý den, John Smith“. Jak mohu rozdělit řetězec prostorem a získat přístup k položce na indexu 1, která by měla vrátit „John“?

Položena 05/08/2008 v 19:15
zdroj uživatelem
V jiných jazycích...                            


46 odpovědí

hlasů
335

Nevěřím, že SQL Server má vestavěný rozdělení funkcí, tak jiný než UDF, jen jiná odpověď, co vím, je unést funkci PARSENAME:

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

PARSENAME trvá řetězec a rozděluje ji na období charakter. Trvá číslo jako druhý argument, a toto číslo určuje, které segment řetězce vrátit (pracovní odzadu dopředu).

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

Zřejmý problém je, když řetězec již obsahuje tečku. Stále si myslím, pomocí UDF je nejlepší způsob, jak ... nějaké další návrhy?

Odpovězeno 05/08/2008 v 19:45
zdroj uživatelem

hlasů
177

Můžete najít řešení v SQL uživatelem definované funkce analyzovat oddělovači řetězec užitečné (z Projektu Code ).

Můžete použít tuto jednoduchou logiku:

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
Odpovězeno 05/08/2008 v 19:28
zdroj uživatelem

hlasů
106

Za prvé, vytvořit funkci (pomocí CTE, společné tabulka výraz odstraňuje potřebu temp tabulky)

 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

Poté jej použít jako libovolné tabulky (nebo upravit tak, aby vyhovoval v rámci vaší stávající uložené proc) takhle.

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

Aktualizace

Předchozí verze by selhat pro vstup řetězce delší než 4000 znaků. Tato verze se stará o omezení:

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

Využití zůstává stejný.

Odpovězeno 05/08/2008 v 19:57
zdroj uživatelem

hlasů
51

Většina řešení zde použít while nebo rekurzivní CTE. Přístup Sada na bázi bude lepší, slibuju:

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
        );

Více informací o rozdělených funkcí, proč (a) důkaz o tom, zatímco smyčky a rekurzivní CTE nemají měřítku a lepšími alternativami, pokud štípací struny pocházející z aplikační vrstvě:

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

Odpovězeno 12/11/2013 v 18:16
zdroj uživatelem

hlasů
37

Můžete využít tabulku Číslo dělat řetězec parsování.

Vytvářet fyzickou čísla tabulky:

    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

Vytvořit testovací tabulku s 1000000 řádků

    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

Vytvoření funkce

    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

Využití (výstupy 3mil řádky v 40. letech na mém notebooku)

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

úklid

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

Výkon zde není úžasné, ale volání funkce přes milion řádků tabulku, není nejlepší nápad. Při provádění řetězec rozdělen na mnoho řádků bych vyhnout funkci.

Odpovězeno 27/10/2008 v 17:48
zdroj uživatelem

hlasů
20

Zde je UDF, který bude dělat. To vrátí tabulku vymezených hodnot, jsem se snažil všechny scénáře o tom, ale váš příklad funguje.


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

Vy byste to nazvat takhle:


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

Edit: Aktualizováno řešení zvládnout delimters s len> 1 jako v:


select * From SplitString('Hello**John**Smith','**')
Odpovězeno 05/08/2008 v 19:39
zdroj uživatelem

hlasů
16

Žádný kód, ale přečetl definitivní článek na toto téma. Všechna řešení v další odpovědi jsou chutě těch uvedených v tomto článku: Pole a seznamy v SQL Server 2005 a další léta

Osobně jsem použil řešení tabulkových počtů nejčastěji proto, že se to hodí, co mám dělat ...

Odpovězeno 26/09/2010 v 14:44
zdroj uživatelem

hlasů
15

Tady jsem psát jednoduchý způsob řešení

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 IGNORE  INTO @t(val)
          SELECT  r.value('.','varchar(MAX)') as item
          FROM  @xml.nodes('/t') as records(r)
          RETURN
        END


Spustit funkci takhle

  select * from dbo.split('Hello John Smith',' ')
Odpovězeno 30/01/2013 v 10:41
zdroj uživatelem

hlasů
12

Tato otázka není o rozdělení přístupu řetězce , ale o tom , jak se dostat na n-tý prvek .

Všechny odpovědi jsou zde dělá nějaký druh řetězce rozštěpení pomocí rekurze, CTEs, více CHARINDEX, REVERSEa PATINDEX, vynalézat funkce, volání metod CLR, počet tabulek, CROSS APPLYto ... Většinu odpovědí zahrnovat mnoho řádků kódu.

Ale - pokud opravdu chcete, nic víc, než přístup k získání n-tý prvek - to lze provést v reálném jednořádkový , ne UDF, ani sub-select ... A jako další výhodu: typ bezpečného

Získat část 2 vymezený prostor:

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)')

Samozřejmě můžete použít proměnné pro oddělovače a poloze (použijte sql:columnnačíst pozice přímo z hodnoty dané dotazu):

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)')

Pokud váš řetězec může obsahovat zakázané znaky (zejména jedním z &><), stále můžete udělat to takhle. Stačí použít FOR XML PATHna provázku první nahradit všechny zakázané znaky montážní posloupnosti implicitně.

Je to velmi zvláštní případ - dodatečně - vaše oddělovač středník . V tomto případě jsem se nahradit oddělovač první ‚# DLMT #‘, a nahradit to s tagy XML na závěr:

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)');
Odpovězeno 08/07/2016 v 20:41
zdroj uživatelem

hlasů
10

A co používání stringa values()prohlášení?

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 IGNORE  INTO @Splited
EXEC(@str)

SELECT * FROM @Splited

Výsledek-set dosaženo.

id  item
1   Hello
2   John
3   Smith
Odpovězeno 01/03/2013 v 17:26
zdroj uživatelem

hlasů
10

Podle mého názoru vy se dělat to příliš komplikované. Stačí vytvořit CLR UDF a hotovo.

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()));
  }
};
Odpovězeno 19/07/2012 v 22:46
zdroj uživatelem

hlasů
8

Tento model funguje a můžete zobecnit

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

Všimněte FIELD , INDEX a TYPE .

Nechte nějaký tabulku s identifikátory, jako je

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

Potom můžete psát

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

Dělení a odlévání všechny díly.

Odpovězeno 11/11/2014 v 14:31
zdroj uživatelem

hlasů
8

Používám odpověď na Frederic ale to nefunguje v SQL Server 2005

To jsem upravil a já jsem s použitím selectse union alla funguje to

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 IGNORE  INTO @Splited
EXEC(@str)

SELECT * FROM @Splited

A výsledek-set je:

id  item
1   Hello
2   John
3   Smith
4   how
5   are
6   you
Odpovězeno 13/08/2013 v 16:11
zdroj uživatelem

hlasů
6

Ještě další dostat vícenásobná radost část řetězce pomocí funkce oddělovač:

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

a využití:

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

který se vrací:

c
Odpovězeno 08/01/2016 v 14:30
zdroj uživatelem

hlasů
6

Hledal jsem řešení na internetu a pod pracuje pro mě. Ref .

A volání funkce, jako je tento:

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 IGNORE  INTO @temptable(Items) VALUES(@slice)       
        SET @String = RIGHT(@String,len(@String) - @idx)       
        IF len(@String) = 0 break       
    END   
    RETURN       
END
Odpovězeno 20/11/2011 v 07:40
zdroj uživatelem

hlasů
5

V následujícím příkladu je rekurzivní CTE

aktualizace 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 IGNORE  @returns
  SELECT REPLACE(val, ' ','' ) AS val, [level]
  FROM cte
  WHERE val > ''
  RETURN
END

Demo na SQLFiddle

Odpovězeno 14/03/2013 v 11:18
zdroj uživatelem

hlasů
5

Zkuste to:

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

Otestujte to takhle:

select * from SplitWordList('Hello John Smith')
Odpovězeno 05/08/2008 v 19:41
zdroj uživatelem

hlasů
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)-@Start+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><fn_Split>'
       -- And convert it to XML so we can select from it
       SET
          @X = Cast('<fn_Split>' +
                    Replace(@Expression, @Delimiter, '</fn_Split><fn_Split>') +
                    '</fn_Split>' as xml)

       -- Insert into our returnable table replacing '|||***|||' back to @Delimiter
       INSERT IGNORE  @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

Odpovězeno 05/11/2013 v 01:12
zdroj uživatelem

hlasů
2

Pokud databáze má úroveň kompatibility 130 nebo vyšší, pak můžete použít STRING_SPLIT funkci spolu s POSUN NAČTENÍ klauzule získat konkrétní položku indexu.

Chcete-li získat položku na indexu 1, můžete použít následující kód

SELECT value
FROM STRING_SPLIT('Hello John Smith',' ')
ORDER BY (SELECT NULL)
OFFSET 1 ROWS
FETCH NEXT 1 ROWS ONLY

Chcete-li zjistit úroveň kompatibility databáze , spuštění tohoto kódu:

SELECT compatibility_level  
FROM sys.databases WHERE name = 'YourDBName';
Odpovězeno 05/04/2018 v 10:23
zdroj uživatelem

hlasů
2

Můžete rozdělit řetězec v SQL bez nutnosti funkce:

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);

Pokud potřebujete podporu libovolné řetězce (s xml speciální znaky)

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); 
Odpovězeno 23/10/2015 v 10:07
zdroj uživatelem

hlasů
2

Téměř všechny ostatní odpovědi rozdělit kód výměně řetězci právě dělené, které odpady cykly CPU a provádí zbytečné přidělení paměti.

I pokrývají mnohem lepší způsob, jak dělat rozkol řetězec zde: http://www.digitalruby.com/split-string-sql-server/

Zde je kód:

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 IGNORE  @SplitStringTable (Value) VALUES (@SplitValue)
    SET @SplitStartPos = @SplitEndPos + 1
    SET @SplitEndPos = CHARINDEX(@SplitDelim, @StringToSplit, @SplitStartPos)
END

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

SET NOCOUNT OFF

-- You can select or join with the values in @SplitStringTable at this point.
Odpovězeno 26/08/2014 v 17:50
zdroj uživatelem

hlasů
2

Vím, že je to stará otázka, ale myslím, že někdo může mít prospěch z mé řešení.

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

Výhody:

  • Odděluje všechny 3 sub-Strings deliminator pomocí '' na.
  • Jeden nesmí používat, zatímco smyčky, protože snižuje výkon.
  • Není třeba otáčet jako všechny výsledné sub-string budou zobrazeny v jednom řádku

Omezení:

  • Člověk musí znát celkový počet. míst (sub-string).

Poznámka : řešení může dát sub-string až do N.

Aby překonal omezení můžeme použít následující ref .

Ale opět výše uvedené řešení nelze používat v tabulce (actaully jsem nebyl schopen ji použít).

Opět doufám, že toto řešení může pomoci některé-one.

Aktualizace: V případě Records> 50000 není vhodné používat LOOPS, jak to bude degradovat výkon

Odpovězeno 24/01/2013 v 07:43
zdroj uživatelem

hlasů
1

Vím, že jeho pozdě, ale v poslední době jsem měl tento požadavek a přišel s následující kód. Nemám na výběr použít uživatelem definované funkce. Snad to pomůže.

SELECT 
    SUBSTRING(
                SUBSTRING('Hello John Smith' ,0,CHARINDEX(' ','Hello John Smith',CHARINDEX(' ','Hello John Smith')+1)
                        ),CHARINDEX(' ','Hello John Smith'),LEN('Hello John Smith')
            )
Odpovězeno 17/09/2018 v 21:07
zdroj uživatelem

hlasů
1

Jednoduché řešení pro analýzu jméno a příjmení

DECLARE @Name varchar(10) = 'John Smith'

-- Get First Name
SELECT SUBSTRING(@Name, 0, (SELECT CHARINDEX(' ', @Name)))

-- Get Last Name
SELECT SUBSTRING(@Name, (SELECT CHARINDEX(' ', @Name)) + 1, LEN(@Name))

V mém případě (av mnoha dalších se zdá, ...), mám seznam jména a příjmení odděleny jednou mezerou. To může být použit přímo uvnitř select analyzovat křestní jméno a příjmení.

-- i.e. Get First and Last Name from a table of Full Names
SELECT SUBSTRING(FullName, 0, (SELECT CHARINDEX(' ', FullName))) as FirstName,
SUBSTRING(FullName, (SELECT CHARINDEX(' ', FullName)) + 1, LEN(FullName)) as LastName,
From FullNameTable
Odpovězeno 20/08/2018 v 18:59
zdroj uživatelem

hlasů
1

Zde je funkce, která bude plnit cíle Otázkou je rozštěpení řetězce a přístupu k položky X:

CREATE FUNCTION [dbo].[SplitString]
(
   @List       VARCHAR(MAX),
   @Delimiter  VARCHAR(255),
   @ElementNumber INT
)
RETURNS VARCHAR(MAX)
AS
BEGIN

       DECLARE @inp VARCHAR(MAX)
       SET @inp = (SELECT REPLACE(@List,@Delimiter,'_DELMTR_') FOR XML PATH(''))

       DECLARE @xml XML
       SET @xml = '<split><el>' + REPLACE(@inp,'_DELMTR_','</el><el>') + '</el></split>'

       DECLARE @ret VARCHAR(MAX)
       SET @ret = (SELECT
              el = split.el.value('.','varchar(max)')
       FROM  @xml.nodes('/split/el[string-length(.)>0][position() = sql:variable("@elementnumber")]') split(el))

       RETURN @ret

END

Používání:

SELECT dbo.SplitString('Hello John Smith', ' ', 2)

Výsledek:

John
Odpovězeno 26/04/2018 v 21:16
zdroj uživatelem

hlasů
1

Aaron Bertrand odpověď je skvělé, ale vadný. Není přesně zpracovat mezeru jako oddělovač (jak tomu bylo v příkladu na původní otázce), protože funkce délky proužků koncové mezery.

Vkládá je jeho kód, s malou úpravou, aby bylo možné vesmírné oddělovač:

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+'x')-1) = @Delim
      ) AS y
    );
Odpovězeno 22/03/2018 v 14:38
zdroj uživatelem

hlasů
1

Počínaje SQL Server 2016 jsme string_split

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

SELECT value FROM string_split(@string, ',')
Odpovězeno 04/09/2017 v 21:52
zdroj uživatelem

hlasů
1

Čistý set řešení založené na použití TVFs rekurzivní CTE. Můžete JOINi APPLYtuto funkci pro jakékoliv datové sady.

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

Používání:

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

Výsledek:

value   index
-------------
John    1
Odpovězeno 13/01/2015 v 06:37
zdroj uživatelem

hlasů
0

Počínaje SQL Server 2016, jsou funkce pro analýzu dat JSON. Chcete-li otevřít položku v určitém indexu vymezené řetězce, použijte JSON_VALUEfunkci. Správně je nutná data ve formátu JSON, nicméně: Řetězce musí být uzavřeny v uvozovkách "a oddělovač musí být čárka ,, přičemž celý řetězec v hranatých závorkách [].

DECLARE @SampleString NVARCHAR(MAX) = '"Hello John Smith"';
--Format as JSON data.
SET @SampleString = '[' + REPLACE(@SampleString, ' ', '","') + ']';
SELECT 
    JSON_VALUE(@SampleString, '$[0]') AS Element1Value,
    JSON_VALUE(@SampleString, '$[1]') AS Element2Value,
    JSON_VALUE(@SampleString, '$[2]') AS Element3Value;

Výstup

Element1Value         Element2Value       Element3Value
--------------------- ------------------- ------------------------------
Hello                 John                Smith

(1 row affected)
Odpovězeno 07/05/2019 v 05:54
zdroj uživatelem

hlasů
0

Ten je založen na provázku, postavení a oddělovač

CREATE FUNCTION fnx_splitstring (@stringToSplit VARCHAR (MAX), @Position int, @SpecialChar char (1))
RETURNS @returnList stolu ([Název] [nvarchar] (500))
AS
BEGIN
SET @stringToSplit = @stringToSplit + @SpecialChar
DECLARE @ jméno nvarchar (255)
PROHLÁSIT @pos INT
DECLARE @i int
SET @i = 0
PŘI CHARINDEX (@SpecialChar, @stringToSplit)> 0
BEGIN
SET @i = @i + 1
SELECT @pos = CHARINDEX (@SpecialChar, @stringToSplit)
SELECT @NAME = SUBSTRING (@stringToSplit, 1, 'pos-1),
v případě, @i = @Position
BEGIN
vložit do @returnList
SELECT @NAME
RETURN
END
SELECT @stringToSplit = SUBSTRING (@stringToSplit,' pos + 1, LEN (@stringToSplit ) - @ pos)
END
RETURN
END

Otestovat takto SELECT * z fnx_splitstring ( 'V4686 / V4686-H-AW-60,25', 2, '-')

Odpovězeno 01/05/2019 v 19:46
zdroj uživatelem

hlasů
0

V případě, že substrings neobsahují duplikáty pak můžete použít následující:

WITH testdata(string) AS (
    SELECT 'a' UNION ALL
    SELECT 'a b' UNION ALL
    SELECT 'a b c' UNION ALL
    SELECT 'a b c d'
)
SELECT *
FROM testdata
CROSS APPLY (
    SELECT value AS substring
         , ROW_NUMBER() OVER(ORDER BY CHARINDEX(' ' + value + ' ', ' ' + string + ' ')) AS n
    FROM STRING_SPLIT(string, ' ')
) AS substrings
WHERE n = 1

STRING_SPLITGeneruje dílčí řetězce, ale neposkytuje index tohoto dílčího. Můžete použít CHARINDEXpro generování pořadové číslo, a to bude správné, pokud se substrings jsou jedinečné. Bude selže a b b c, a b c c d eatd

Odpovězeno 27/01/2019 v 15:27
zdroj uživatelem

hlasů
0

Můžete použít STRING_SPLITfunkci k dispozici v SQL Server 2016 nebo novější. Vezměte na vědomí, že neexistuje žádná záruka, že substrings budou vráceny v libovolném pořadí.

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

Kde:

  • STRING_SPLIT vrací tabulku s jedním sloupcem s názvem value
  • FOR XML PATH('') transformuje do řádků <substr>a</substr><substr>b</substr>...
  • TYPEpřevádí výše XMLdatový typ
  • value('substr[2]', 'VARCHAR(100)')běží XPath Na základě výše uvedeného a vrátí VARCHARdatový typ

Výsledek:

| 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          |
Odpovězeno 24/01/2018 v 12:27
zdroj uživatelem

hlasů
0

Moderní přístup pomocí STRING_SPLIT , vyžaduje SQL Server 2016 a vyšší.

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

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

Výsledek:

RowNr   value
1       Hello
2       John
3       Smith

Nyní je možné získat th n-tého prvku z počtu řádků.

Odpovězeno 02/01/2018 v 15:02
zdroj uživatelem

hlasů
0

Budova na @NothingsImpossible řešení, či spíše vyjádřit k většině hlasovali odpověď (těsně pod přijal jeden), jsem našel následující quick-and-špinavý roztok naplnit své vlastní potřeby - má výhodu v tom, že pouze v rámci SQL domény.

daný řetězec „První, druhý, třetí, čtvrtý, pátý“, řekněme, Chci se dostat na třetí token. to funguje pouze tehdy, když budeme vědět, kolik žetonů řetězec bude mít - v tomto případě je to 5. takže můj způsob akce je sekat poslední dva žetony pryč (vnitřní dotaz), a pak nakrájejte na první dva žetony pryč ( vnější dotaz)

Vím, že je to ošklivé a pokrývá specifické podmínky jsem byl, ale jsem vyvěšením jen v případě, někdo považuje za užitečné. Na zdraví

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
Odpovězeno 31/10/2016 v 14:18
zdroj uživatelem

hlasů
0
declare @strng varchar(max)='hello john smith'
select (
    substring(
        @strng,
        charindex(' ', @strng) + 1,
        (
          (charindex(' ', @strng, charindex(' ', @strng) + 1))
          - charindex(' ',@strng)
        )
    ))
Odpovězeno 14/07/2016 v 05:29
zdroj uživatelem

hlasů
0

devoloped jsem to,

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

jediná pozornost byste měli je tečka ‚‘ že konec @x je vždy tam měl být.

Odpovězeno 15/10/2015 v 10:50
zdroj uživatelem

hlasů
0

pokud někdo chce získat pouze jednou částí seperatured textu lze použít

select * from fromSplitStringSep ( 'slovo1 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
  )
Odpovězeno 13/02/2015 v 09:14
zdroj uživatelem

hlasů
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 IGNORE  INTO @output (splitdata)  
        VALUES(SUBSTRING(@string, @start, @end - @start)) 
        SET @start = @end + 1 
        SET @end = CHARINDEX(@delimiter, @string, @start)

    END 
    RETURN 
END

A použít jej

select *from dbo.fnSplitString('Querying SQL Server','')
Odpovězeno 20/12/2014 v 11:58
zdroj uživatelem

hlasů
0

zatímco podobné bázi odpovědi na XML josejuan, jsem zjistil, že zpracování cestu xml pouze jednou, pak otočení byl mírně účinnější:

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

běžel v 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

běžel v 9:20

Odpovězeno 08/12/2014 v 03:59
zdroj uživatelem

hlasů
0

Rekurzivní řešení CTE s bolestí serveru otestovat

MS SQL Server 2008 Schema Setup :

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

Dotaz 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

výsledky :

|    A_L | N |
|--------|---|
| Hello  | 0 |
|  John  | 1 |
| Smith  | 2 |
Odpovězeno 16/01/2014 v 11:38
zdroj uživatelem

hlasů
0

To je něco, co jsem udělal s cílem získat konkrétní tokenu v řetězci. (Testováno v MSSQL 2008)

Za prvé, vytvořit následující funkce: (nachází se v: zde

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;

a

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

pak jej můžete použít takhle:

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

která vrátí 1111

Odpovězeno 25/07/2013 v 12:07
zdroj uživatelem

hlasů
0

No, moje není všechno, že jednodušší, ale tady je kód, který jsem použít k rozdělení vstupní proměnnou oddělený čárkami do jednotlivých hodnot, a dát ji do proměnné tabulky. Jsem si jistý, že by mohla mírně pozměnit toto rozchodu vychází z vesmíru a pak dělat si základní SELECT dotazu proti tomuto tabulky proměnné, aby si své výsledky.

-- 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 IGNORE  INTO @tblAccountingCycles (AccountingCycle) VALUES (@vchAccountingCycle)
        END
        SET @vchAccountingCycleIDs = RIGHT(@vchAccountingCycleIDs, LEN(@vchAccountingCycleIDs) - @intPosition)
        SET @intPosition = CHARINDEX(',', @vchAccountingCycleIDs, 1)
    END
END

Tento koncept je skoro stejný. Jednou z dalších možností je využít kompatibilitu .NET v rámci SQL Server 2005 sám. Můžete v podstatě napsat sami jednoduchou metodu .NET, který by rozděloval řetězec a pak vystavit, že jako uložené procedury / funkce.

Odpovězeno 05/08/2008 v 19:36
zdroj uživatelem

hlasů
-1

Byl jsem pomocí vzczc je odpověď pomocí rekurzivní CTE je na nějakou dobu, ale chtěl ji aktualizovat zvládnout separátor s proměnnou délkou a také zvládnout řetězce s přední a zaostávání „oddělovače“, jako když máte soubor csv se záznamy, jako je :

"Bob", "Smith", "Sunnyvale", "CA"

nebo když máte co do činění s šesti dílčích fqn let, jak je uvedeno níže. I použít tyto značně pro logování na subject_fqn pro audit, zpracování chyb, atd a parsename zpracovává pouze ze čtyř částí:

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

Tady je můj aktualizovaná verze, a to díky vzczc pro své původní místo!

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 
Odpovězeno 19/08/2014 v 20:45
zdroj uživatelem

hlasů
-1

Jednoduchý optimalizovaný algoritmus:

ALTER FUNCTION [dbo].[Split]( @Text NVARCHAR(200),@Splitor CHAR(1) )
RETURNS @Result TABLE ( value NVARCHAR(50)) 
AS
BEGIN
    DECLARE @PathInd INT
    Set @Text+=@Splitor
    WHILE LEN(@Text) > 0
    BEGIN
        SET @PathInd=PATINDEX('%'+@Splitor+'%',@Text)
        INSERT IGNORE  INTO  @Result VALUES(SUBSTRING(@Text, 0, @PathInd))
        SET @Text= SUBSTRING(@Text, @PathInd+1, LEN(@Text))
    END
        RETURN 
END
Odpovězeno 01/05/2014 v 07:26
zdroj uživatelem

hlasů
-1

Zde je SQL UDF, který lze rozdělit řetězec a chytit jen určitý kus.

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
Odpovězeno 20/03/2014 v 15:41
zdroj uživatelem

hlasů
-1

Tady je moje řešení, které může pomoci někoho jiného. Modifikace Jonesinator své odpovědi výše.

Mám-li řetězec vymezených hodnot INT a chcete tabulku INT vrátil (Což jsem pak mohou připojit k). například ‚1,20,3,343,44,6,8765‘

Vytvořte 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 IGNORE  INTO @table (Value) VALUES (@Value)

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

RETURN
END
GO

Pak se výsledky tabulky:

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

1
20
3
343
44
6
8765

A spojit prohlášení:

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

Chcete-li se vrátit seznam NVARCHARs namísto INT pak stačí změnit definici tabulky:

RETURNS @table TABLE 
(
    Value NVARCHAR(MAX) NOT NULL
)
Odpovězeno 20/06/2013 v 00:42
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more