Ben madde x erişebilmesi için nasıl bir dize bölmek mi?

oy
442

Ben madde x erişebilir yüzden bir dize bölmek, nasıl SQL Server kullanarak?

bir dize Merhaba John Smith atın. Nasıl boşluk dize bölmek ve John dönmelidir dizin 1'de öğeye erişebilir?

Oluştur 05/08/2008 saat 19:15
kaynak kullanıcı
Diğer dillerde...                            


43 cevaplar

oy
335

Ben SQL Server bir UDF yani dışında yerleşik bir bölme işlevi vardır inanmıyorum, biliyorum sadece diğer cevap PARSENAME fonksiyonunu ele geçirmektir:

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

PARSENAME bir dize alır ve dönem karakteri üzerine böler. Onun ikinci argüman olarak bir sayı alır ve bu sayı dize segmenti (arkadan öne doğru çalışma) dönmek olduğunu belirler.

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

dize zaten bir dönemi içerdiğinde Apaçık sorundur. Hala UDF kullanarak en iyi yolu ... başka öneri olduğunu düşünüyorum?

Cevap 05/08/2008 saat 19:45
kaynak kullanıcı

oy
177

Sen de çözüm bulabilir bir Ayrılmış dize ayrıştırma için SQL Kullanıcı Tanımlı Fonksiyon (dan yararlı Kod Projesi ).

Bu basit mantığı kullanabilirsiniz:

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
Cevap 05/08/2008 saat 19:28
kaynak kullanıcı

oy
106

İlk olarak, bir işlevi oluşturmak (CTE kullanılarak ortak tablo sentezleme bir geçici tablo için ihtiyacı ortadan kaldıran)

 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

Sonra, herhangi bir tablo olarak kullanmak (veya mevcut depolanmış yordam sığacak şekilde değiştirmek) böyle.

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

Güncelleştirme

Önceki sürüm 4000 karakter daha uzun giriş dizesi başarısız olur. Bu sürüm sınırlaması ilgilenir:

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

Kullanımı aynı kalır.

Cevap 05/08/2008 saat 19:57
kaynak kullanıcı

oy
51

Burada çözümlerin çoğu döngüler veya özyinelemeli CTEs iken kullanın. Bir dizi temelli yaklaşım üstün olacak, söz veriyorum:

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

bölme işlevleri, neden (ve ispat) döngüler ve özyinelemeli CTEs ölçekli değil iken ve daha iyi alternatifler Daha, eğer uygulama katmanından gelen bölme dizeleri:

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

Cevap 12/11/2013 saat 18:16
kaynak kullanıcı

oy
37

Sen dize ayrıştırma yapmak için Numara tablosunu yararlanabilir.

Fiziksel numaralar tablo oluşturun:

    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 satırlarla Test tablo oluşturun

    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

işlev oluşturun

    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

Kullanımı (çıkışlar benim laptop 40'lı satırları 3mil)

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

Temizlemek

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

Burada Performans şaşırtıcı değil, ama bir milyon satır masanın üzerinde bir işlevi çağıran iyi bir fikir değildir. bir dize gerçekleştiren sayıda satır üzerinde bölünmüş ben işlevini önleyeceğini.

Cevap 27/10/2008 saat 17:48
kaynak kullanıcı

oy
20

İşte yapacak UDF olduğunu. Bu sınırlandırılmış değerler tablosu dönecektir, üzerinde tüm senaryolar çalıştı ama senin örneğin gayet iyi çalışıyor değil.


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

Böyle çağırır:


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

Düzenleme: Güncelleme çözüm gibi bir len> 1 ile delimters işlemek için:


select * From SplitString('Hello**John**Smith','**')
Cevap 05/08/2008 saat 19:39
kaynak kullanıcı

oy
16

Herhangi bir kod, ama bu konuda kesin bir yazı okudum. Tüm : diğer yanıtlar çözümler bu makalede listelenen olanlardan tatlar vardır SQL Server 2005 ve Ötesinde Diziler ve Listelerini

Yapmam gerekeni uygun çünkü Şahsen ben en sık Sayılar masa çözüm kullandım ...

Cevap 26/09/2010 saat 14:44
kaynak kullanıcı

oy
15

Burada çözümün basit bir yol sonrası

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


Böyle işlevi yürütme

  select * from dbo.split('Hello John Smith',' ')
Cevap 30/01/2013 saat 10:41
kaynak kullanıcı

oy
12

Bu soru bir dize bölünmüş yaklaşımı hakkında değil ama yaklaşık, inci elemanını nasıl .

Buradaki tüm cevaplar özyinelemeye kullanarak dize bölünme çeşit yapıyoruz CTEs, çoklu CHARINDEX, REVERSEve PATINDEXişlevleri icat, CLR yöntemlerle, sayı tabloları, için çağrı CROSS APPLYs ... En cevapları satır sayısı oldukça fazla kapsamaktadır.

Ama - Gerçekten eğer bir yaklaşım başka bir şey inci elemanını almak istiyorum bu şekilde yapılabilir - Gerçek bir-liner , hiçbir UDF, hatta bir alt select ... Ve ekstra fayda olarak: Güvenli türü

boşlukla ayrılmış bölüm 2 alın:

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

Tabii sen değişkenleri kullanabilirsiniz sınırlayıcı ve pozisyon için (kullanmak sql:columnbir sorgunun değerinden doğrudan pozisyon almak için):

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

Dize içerebilir Eğer izin verilmeyen karakterler (özellikle bir arasında &><), yine bu şekilde yapabiliriz. Sadece kullanmak FOR XML PATHörtük uydurma kaçış dizisi ile tüm yasak karakterleri değiştirmek için öncelikle ipi.

Ayrıca - - Bu eğer çok özel bir durum sizin ayırıcı noktalı virgül olduğunu . Bu durumda ben '# DLMT #' ilk sınırlayıcı yerini ve son olarak XML etiketleri için bu değiştirin:

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)');
Cevap 08/07/2016 saat 20:41
kaynak kullanıcı

oy
10

Ne kullanımı hakkında stringve values()deyimi?

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

Sonuç kümesi elde etti.

id  item
1   Hello
2   John
3   Smith
Cevap 01/03/2013 saat 17:26
kaynak kullanıcı

oy
10

Bence siz bu yol çok karmaşık yapıyoruz. Sadece bir CLR UDF oluşturmak ve onunla yapılabilir.

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()));
  }
};
Cevap 19/07/2012 saat 22:46
kaynak kullanıcı

oy
8

Bu model gayet iyi çalışıyor ve siz genelleme yapabiliriz

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

Not ALAN , INDEX ve TYPE .

gibi künyeleri ile bazı tabloyu edelim

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

Ardından, yazabilir

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

bölme ve tüm parçaları döküm.

Cevap 11/11/2014 saat 14:31
kaynak kullanıcı

oy
8

Ben francymungedi cevabını kullanmak ancak bu SQL Server 2005'te işe yaramadı

Onu modifiye ve ben kullanıyorum selectile union allve işe yarıyor

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

Ve sonuç grubu olduğu:

id  item
1   Hello
2   John
3   Smith
4   how
5   are
6   you
Cevap 13/08/2013 saat 16:11
kaynak kullanıcı

oy
6

Henüz başka delimeter işlev tarafından dize n'inci kısmını alıyorum:

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

ve kullanımı:

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

ki verir:

c
Cevap 08/01/2016 saat 14:30
kaynak kullanıcı

oy
6

Ben net çözüm ve benim için aşağıda işler arıyordu. Ref .

Ve böyle işlevini çağırır:

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
Cevap 20/11/2011 saat 07:40
kaynak kullanıcı

oy
5

Aşağıdaki örnek, bir özyinelemeli CTE kullanır

Güncelleme 2013/09/18

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

Üzerinde Demo SQLFiddle

Cevap 14/03/2013 saat 11:18
kaynak kullanıcı

oy
5

Bunu dene:

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

Bu şekilde test edin:

select * from SplitWordList('Hello John Smith')
Cevap 05/08/2008 saat 19:41
kaynak kullanıcı

oy
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

Cevap 05/11/2013 saat 01:12
kaynak kullanıcı

oy
2

Veritabanı uyumluluğu 130 seviyesini veya kullanabilirsiniz daha yüksek sahipse STRING_SPLIT birlikte işlevini FETCH OFFSET dizine göre belirli öğeyi almak için maddeler.

Dizin 1'deki öğeyi almak için aşağıdaki kodu kullanabilirsiniz

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

Kontrol etmek için veritabanı uyumluluk düzeyini , bu kodu çalıştırmak:

SELECT compatibility_level  
FROM sys.databases WHERE name = 'YourDBName';
Cevap 05/04/2018 saat 10:23
kaynak kullanıcı

oy
2

Sen bir işlev gerek kalmadan SQL bir dize bölebilirsiniz:

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

Eğer (xml özel karakterlerle) keyfi dizeleri desteklemek için gerekirse

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); 
Cevap 23/10/2015 saat 10:07
kaynak kullanıcı

oy
2

Hemen hemen tüm diğer cevaplar bölünmüş kod İşlemci döngülerini tüketir ve gereksiz bellek ayırmalarını gerçekleştirir Bölünmüş dize yerini almaktadır.

Burada bir dize Bacak açmayı çok daha iyi bir şekilde kapsamaktadır: http://www.digitalruby.com/split-string-sql-server/

İşte kod:

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.
Cevap 26/08/2014 saat 17:50
kaynak kullanıcı

oy
2

Ben eski bir soru olduğunu biliyorum ama ben bazı biri benim çözümü yararlanabilir düşünüyorum.

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

Avantajları:

  • Bu '' bütün 3 alt dizeleri deliminator ayırır.
  • performansı azaldıkça bir döngü sırasında kullanmak gerekir.
  • tüm çıkan alt dize olarak döndürün gerek yok tek Row görüntülenecektir

Sınırlamalar:

  • Bir toplam hayır bilmesi gerekir. alanlarda (alt dizesi) arasında.

Not : Çözüm N'ye kadar alt dize verebilir

Sınırlama üstesinden için aşağıdaki kullanabilirsiniz ref .

Ama yine yukarıdaki çözüm bir tabloda kullanılması olamaz (actaully ı kullanmak mümkün değildi).

Yine ben bu çözüm bazı-one yardımcı olabilir umuyoruz.

Güncelleme: Kayıt durumunda> 50000 değil mi tavsiye kullanmak LOOPS, azalmaması gibi Performans

Cevap 24/01/2013 saat 07:43
kaynak kullanıcı

oy
1

Ben onun geç biliyorum ama son zamanlarda bu gereksinimi vardı ve aşağıdaki kodu ile geldi. Ben Kullanıcı tanımlı işlevi kullanmak için bir seçenek yok. Bu yardımcı olur umarım.

SELECT 
    SUBSTRING(
                SUBSTRING('Hello John Smith' ,0,CHARINDEX(' ','Hello John Smith',CHARINDEX(' ','Hello John Smith')+1)
                        ),CHARINDEX(' ','Hello John Smith'),LEN('Hello John Smith')
            )
Cevap 17/09/2018 saat 21:07
kaynak kullanıcı

oy
1

Çözümleme Ad ve soyadı İÇİN BASİT ÇÖZÜM

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

Benim durumumda (ve öyle görünüyor diğerleri ... lütfen), ben tek bir boşlukla ayrılmış ilk ve son isim listesini var. Bu ad ve soyadı ayrıştırmak için bir select deyimi içinde doğrudan kullanılabilir.

-- 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
Cevap 20/08/2018 saat 18:59
kaynak kullanıcı

oy
1

İşte bir dize bölme ve madde X ulaşma Sorunun amacı gerçekleştirmek olacak bir fonksiyondur:

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

Kullanımı:

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

Sonuç:

John
Cevap 26/04/2018 saat 21:16
kaynak kullanıcı

oy
1

Aaron Bertrand'ın cevabı harika ama kusurlu. sonunda boşluk uzunluğu işlevi şeritler yana (orijinal Söz konusu örnek, olarak) doğru olarak sınırlayıcı olarak bir boşluk işlemez.

Aşağıdaki bir uzay sınırlayıcı sağlamak için küçük bir ayarlama ile, onun kodudur:

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
    );
Cevap 22/03/2018 saat 14:38
kaynak kullanıcı

oy
1

Ile başlayan SQL Server 2016 biz string_split

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

SELECT value FROM string_split(@string, ',')
Cevap 04/09/2017 saat 21:52
kaynak kullanıcı

oy
1

Kullanılarak Saf seti tabanlı çözüm TVFözyinelemeli ile CTE. Şunları yapabilirsiniz JOINve APPLYherhangi veri kümesi için bu işlevi.

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

Kullanımı:

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

Sonuç:

value   index
-------------
John    1
Cevap 13/01/2015 saat 06:37
kaynak kullanıcı

oy
0

Sen kullanabilirsiniz STRING_SPLITSQL Server 2016 veya sonrası mevcut fonksiyonunu. Altdizgelerin belirli bir sırayla iade edilecektir garantisi yoktur tavsiye edilebilir.

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

Nerede:

  • STRING_SPLIT adlı bir sütun ile bir tablo geri value
  • FOR XML PATH('') satır dönüşümleri <substr>a</substr><substr>b</substr>...
  • TYPEYukarıdaki dönüştürür XMLveri türü
  • value('substr[2]', 'VARCHAR(100)')Yukarıda üzerinde XPATH ifadesini çalıştırır ve döner VARCHARveri türü

Sonuç:

| 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          |
Cevap 24/01/2018 saat 12:27
kaynak kullanıcı

oy
0

Kullanarak modern bir yaklaşım STRING_SPLIT , SQL Server 2016 ve üstü gerektirir.

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

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

Sonuç:

RowNr   value
1       Hello
2       John
3       Smith

Şimdi satır numarasından n'inci elemanı inci elde etmek mümkündür.

Cevap 02/01/2018 saat 15:02
kaynak kullanıcı

oy
0

@NothingsImpossible solüsyon veya üzerinde bina yerine, (sadece kabul birinin altında) en olarak cevap üzerine yorum i şu buldum kirli hızlı ve- çözüm kendi ihtiyaçlarını karşılamak - bu yalnızca SQL etki alanı içinde olmanın bir yararı vardır.

bir dize verilen "birinci, ikinci, üçüncü, dördüncü, beşinci", diyelim ki, ben üçüncü jetonu almak istiyorum. biz dize sahip oluyor kaç belirteçleri biliyorsanız, bu sadece çalışır - bu durumda 5. yüzden eylem benim yol uzakta (iç sorgu) son iki belirteçleri doğrayın etmektir, ve sonra (uzak ilk iki belirteçleri kesmek için dış sorgu)

ben bu çirkin ve ben oldu özgü şartları kapsadığını biliyorum ama durum birilerini kullanışlı bulduğu sadece bunu ilanıyla. şerefe

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
Cevap 31/10/2016 saat 14:18
kaynak kullanıcı

oy
0
declare @strng varchar(max)='hello john smith'
select (
    substring(
        @strng,
        charindex(' ', @strng) + 1,
        (
          (charindex(' ', @strng, charindex(' ', @strng) + 1))
          - charindex(' ',@strng)
        )
    ))
Cevap 14/07/2016 saat 05:29
kaynak kullanıcı

oy
0

Ben, bu geliştiği

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

sadece şunu dikkat noktadır. '' @x o ucu her zaman var olmalıdır edilmektedir.

Cevap 15/10/2015 saat 10:50
kaynak kullanıcı

oy
0

Herkes almak istiyorsa seperatured metnin sadece bir parçası bunu kullanabilirsiniz

fromSplitStringSep dan * seçin ( 'kelime1 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
  )
Cevap 13/02/2015 saat 09:14
kaynak kullanıcı

oy
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

VE ONU KULLANIN

select *from dbo.fnSplitString('Querying SQL Server','')
Cevap 20/12/2014 saat 11:58
kaynak kullanıcı

oy
0

josejuan tarafından xml tabanlı cevaba benzer iken, ben sadece bir kez xml yolunu işleme, daha sonra dönme orta daha verimli olduğu bulundu:

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 koştu

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 koştu

Cevap 08/12/2014 saat 03:59
kaynak kullanıcı

oy
0

Sunucu ağrısı olan özyinelemeli CTE çözümü, bunu test

MS SQL Server 2008 Şema Kur :

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

Sorgu 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

Sonuçlar :

|    A_L | N |
|--------|---|
| Hello  | 0 |
|  John  | 1 |
| Smith  | 2 |
Cevap 16/01/2014 saat 11:38
kaynak kullanıcı

oy
0

Bu bir dizede belirli jetonu almak için yaptığı bir şeydir. (2008 MSSQL test edilmiştir)

(Bulundu: Birincisi, aşağıdaki işlevleri oluşturarak burada

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;

ve

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

o zaman bunu böyle kullanabilirsiniz:

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

1111 geri dönme

Cevap 25/07/2013 saat 12:07
kaynak kullanıcı

oy
0

Benimki o kadar basit değil, ama burada bireysel değerlere virgülle ayrılmış giriş değişkeni bölmek ve bir tablo değişkeni koymak için kullanın koddur. Ben senin sonuç almak için bu tablo değişkeni karşı temel bir SELECT sorgusu yapmak o zaman biraz bu değiştirebilir emin bir alana göre yarılmış ve benim.

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

kavram hemen hemen aynıdır. Bir diğer alternatif SQL Server 2005 kendi içinde .NET uyumluluğu ve yükseltmektir. Sen aslında kendinize dize bölmek ve sonra bir saklı yordam / işlev olarak bu ifşa edeceği NET'te basit bir yöntem yazabilirsiniz.

Cevap 05/08/2008 saat 19:36
kaynak kullanıcı

oy
-1

Bir süredir özyinelemeli CTE en kullanarak vzczc cevabını kullanıyorum, ama bir değişken uzunluk ayırıcı işlemek için güncellemek istedim ve aynı zamanda önde gelen ve bu aşağıdaki gibi kayıtları ile bir csv dosyası var olduğu gibi "ayırıcılar" kalmış dizelerle işlemek için :

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

Altı kısım FQN yıllardan verilerle çalışıyorken veya aşağıda gösterildiği gibi. I vb denetim subject_fqn günlük kaydı hata işleme için, yaygın olarak kullanan ve parsename sadece dört parça ele alır:

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

İşte benim güncellenmiş versiyonudur ve onun özgün yazı için vzczc yıllardan sayesinde!

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 
Cevap 19/08/2014 saat 20:45
kaynak kullanıcı

oy
-1

Basit optimize algoritması:

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
Cevap 01/05/2014 saat 07:26
kaynak kullanıcı

oy
-1

İşte bir dize bölmek ve sadece belli bir parça kapmak bir SQL UDF olduğunu.

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
Cevap 20/03/2014 saat 15:41
kaynak kullanıcı

oy
-1

İşte birisi yardımcı olabilir benim çözüm. Yukarıdaki Jonesinator cevabı Modifikasyonu.

Ben sınırlandırılmış INT değerlerinin bir dizesi var ve (o zaman üzerinde katılabilir Hangi) IntS bir tablo döndü istiyorum. mesela '1,20,3,343,44,6,8765'

Bir UDF oluşturun:

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

Sonra masa sonuçlar elde:

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

1
20
3
343
44
6
8765

Ve bir de bildiri katılmak:

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

yerine ints NVARCHARs listesini dönmek isterseniz o zaman sadece masa tanımını değiştirin:

RETURNS @table TABLE 
(
    Value NVARCHAR(MAX) NOT NULL
)
Cevap 20/06/2013 saat 00:42
kaynak kullanıcı

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