Hvordan kan jeg dele en streng slik at jeg kan få tilgang element x?

stemmer
453

Ved hjelp av SQL Server, hvordan kan jeg dele en streng slik at jeg kan få tilgang element x?

Ta en streng Hei John Smith. Hvordan kan jeg dele strengen med mellomrom og få tilgang til elementet på indeks 1 som skal returnere John?

Publisert på 05/08/2008 klokken 18:15
kilden bruker
På andre språk...                            


43 svar

stemmer
341

Jeg tror ikke SQL Server har en innebygd i split-funksjon, slik at andre enn en UDF, den eneste andre svaret jeg vet er å kapre PARSENAME funksjon:

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

PARSENAME tar en streng og deler den på perioden karakter. Det tar et tall som sin andre argument, og at antallet spesifiserer hvilket segment av strengen for å returnere (arbeids fra baksiden til fronten).

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

Åpenbart problem er når strengen allerede inneholder en periode. Jeg tror fortsatt bruker en UDF er den beste måten ... noen andre forslag?

Svarte 05/08/2008 kl. 18:45
kilden bruker

stemmer
180

Du kan finne løsningen i SQL brukerdefinerte funksjonen for å analysere et skilletegn String nyttig (fra The Code-prosjektet ).

Du kan bruke denne enkle logikk:

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
Svarte 05/08/2008 kl. 18:28
kilden bruker

stemmer
107

Først oppretter en funksjon (ved hjelp av CTE, gjør felles bord uttrykk avskaffe behovet for en temp tabell)

 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

Deretter bruker den som et bord (eller endre det til å passe i din eksisterende lagrede proc) som dette.

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

Oppdater

Forrige versjon ville mislykkes for innspill strengen lengre enn 4000 tegn. Denne versjonen tar seg av begrensning:

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

Bruk forblir den samme.

Svarte 05/08/2008 kl. 18:57
kilden bruker

stemmer
53

De fleste av løsningene her bruke mens sløyfer eller rekursive CTEs. Et sett basert tilnærming vil være overlegen, jeg lover:

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

Mer på delt funksjoner, hvorfor (og bevis på at) mens sløyfer og rekursive CTEs ikke skalerer og bedre alternativer, hvis splitte strenger som kommer fra applikasjonslaget:

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

Svarte 12/11/2013 kl. 17:16
kilden bruker

stemmer
37

Du kan benytte en talltabell til å gjøre det streng tolking.

Lag en fysisk tall tabell:

    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

Lag test bord med 1000000 rader

    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

Lag funksjonen

    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

Bruk (utganger 3mil rader i 40-årene på min laptop)

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

rydde opp

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

Forestilling her er ikke fantastisk, men å kalle en funksjon over en million rad tabellen er ikke den beste ideen. Hvis du utfører en streng delt over mange rader jeg ville unngå funksjonen.

Svarte 27/10/2008 kl. 16:48
kilden bruker

stemmer
20

Her er en UDF som vil gjøre det. Det vil returnere en tabell over avgrensede verdier, har ikke prøvd alle scenarier på det, men ditt eksempel fungerer fint.


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

Du vil kalle det slik:


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

Edit: Oppdatert løsning for å håndtere delimters med et len> 1 som i:


select * From SplitString('Hello**John**Smith','**')
Svarte 05/08/2008 kl. 18:39
kilden bruker

stemmer
16

Ingen kode, men les den definitive artikkel om dette. Alle løsninger i andre svarene er varianter av de som er nevnt i denne artikkelen: Arrays og lister i SQL Server 2005 og Beyond

Personlig har jeg brukt en Numbers-tabell løsning oftest fordi det passer hva jeg har å gjøre ...

Svarte 26/09/2010 kl. 13:44
kilden bruker

stemmer
15

Her jeg legger en enkel måte å løsning

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

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


Utfør funksjonen som dette

  select * from dbo.split('Hello John Smith',' ')
Svarte 30/01/2013 kl. 09:41
kilden bruker

stemmer
13

Dette spørsmålet er ikke om en streng delt tilnærming , men om hvordan du får n'te element .

Alle svar her er å gjøre noen form for streng splitting bruke rekursjon, CTEs, multiple CHARINDEX, REVERSEog PATINDEX, oppfinne funksjoner, ring for CLR metoder, antall tabeller, CROSS APPLYs ... De fleste svarene dekker mange linjer med kode.

Men - hvis du virkelig vil ha noe mer enn en tilnærming for å få den n'te element - dette kan gjøres som real one-liner , ingen UDF, ikke engang en sub-velger ... Og som en ekstra fordel: typen trygt

Få del 2 avgrenset av en plass:

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

Selvfølgelig kan du bruke variabler for skilletegn og posisjon (bruk sql:columnfor å hente posisjon direkte fra en spørring verdi):

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

Hvis strengen kan inneholde forbudte tegn (spesielt en blant &><), du kan fortsatt gjøre det på denne måten. Bare bruk FOR XML PATHpå strengen først å erstatte alle forbudte tegn med montering escape-sekvens implisitt.

Det er en veldig spesiell sak om - i tillegg - din delimiter er semikolon . I dette tilfellet bytter jeg skille første til '# DLMT #', og erstatte dette til XML-koder til slutt:

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)');
Svarte 08/07/2016 kl. 20:41
kilden bruker

stemmer
10

Hva med å bruke stringog values()uttalelsen?

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

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

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

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

INSERT INTO @Splited
EXEC(@str)

SELECT * FROM @Splited

Resultat-set oppnås.

id  item
1   Hello
2   John
3   Smith
Svarte 01/03/2013 kl. 16:26
kilden bruker

stemmer
10

Etter min mening er dere som gjør det altfor komplisert. Bare lage en CLR UDF og bli ferdig med det.

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()));
  }
};
Svarte 19/07/2012 kl. 21:46
kilden bruker

stemmer
8

Dette mønsteret fungerer fint, og du kan general

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

oppmerksom FIELD , INDEX og TYPE .

La noen bord med identifikatorer som

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

Deretter kan du skrive

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

splitting og støping av alle deler.

Svarte 11/11/2014 kl. 14:31
kilden bruker

stemmer
8

Jeg bruker svar på Frederic men dette fungerte ikke i SQL Server 2005

Jeg endret det, og jeg bruker selectmed union allog det fungerer

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

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

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

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

INSERT INTO @Splited
EXEC(@str)

SELECT * FROM @Splited

Og resultatet-settet er:

id  item
1   Hello
2   John
3   Smith
4   how
5   are
6   you
Svarte 13/08/2013 kl. 15:11
kilden bruker

stemmer
6

Enda en får n'te del av streng ved treff funnet funksjon:

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

og bruk:

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

som returnerer:

c
Svarte 08/01/2016 kl. 14:30
kilden bruker

stemmer
6

Jeg var på utkikk etter løsningen på nettet og nedenfor fungerer for meg. Ref .

Og du kaller funksjonen som dette:

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

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE FUNCTION [dbo].[Split](@String VARCHAR(8000), @Delimiter CHAR(1))       
RETURNS @temptable TABLE (items VARCHAR(8000))       
AS       
BEGIN       
    DECLARE @idx INT       
    DECLARE @slice VARCHAR(8000)        
    SELECT @idx = 1       
    IF len(@String)<1 OR @String IS NULL  RETURN       
    WHILE @idx!= 0       
    BEGIN       
        SET @idx = charindex(@Delimiter,@String)       
        IF @idx!=0       
            SET @slice = LEFT(@String,@idx - 1)       
        ELSE       
            SET @slice = @String       
        IF(len(@slice)>0)  
            INSERT INTO @temptable(Items) VALUES(@slice)       
        SET @String = RIGHT(@String,len(@String) - @idx)       
        IF len(@String) = 0 break       
    END   
    RETURN       
END
Svarte 20/11/2011 kl. 06:40
kilden bruker

stemmer
5

Følgende eksempel bruker en rekursiv CTE

oppdatering 18.09.2013

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

Demo på SQLFiddle

Svarte 14/03/2013 kl. 10:18
kilden bruker

stemmer
5

Prøv dette:

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

Test det ut som dette:

select * from SplitWordList('Hello John Smith')
Svarte 05/08/2008 kl. 18:41
kilden bruker

stemmer
3

Hvis databasen har kompatibilitet nivå på 130 eller høyere så kan du bruke STRING_SPLIT fungere sammen med OFFSET HENT klausuler for å få bestemt element ved indeks.

For å få varen på indeksen N (null-basert), kan du bruke følgende kode

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

For å sjekke kompatibiliteten nivå av databasen , utføre denne koden:

SELECT compatibility_level  
FROM sys.databases WHERE name = 'YourDBName';
Svarte 05/04/2018 kl. 10:23
kilden bruker

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

Svarte 05/11/2013 kl. 00:12
kilden bruker

stemmer
2

Du kan dele en streng i SQL uten en funksjon:

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

Hvis du trenger å støtte vilkårlige strenger (med xml spesialtegn)

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); 
Svarte 23/10/2015 kl. 10:07
kilden bruker

stemmer
2

Nesten alle de andre svarene delt kode erstatter strengen blir splittet som avfall CPU-sykluser og utfører unødvendige minnetildelinger.

Jeg dekker et mye bedre måte å gjøre en streng delt her: http://www.digitalruby.com/split-string-sql-server/

Her er koden:

SET NOCOUNT ON

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

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

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

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

SET NOCOUNT OFF

-- You can select or join with the values in @SplitStringTable at this point.
Svarte 26/08/2014 kl. 16:50
kilden bruker

stemmer
2

Jeg vet det er en gammel spørsmål, men jeg tror noen kan ha nytte av min løsning.

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 fele

Fordeler:

  • Det skiller hele 3 under strenger deliminator av ''.
  • Man må ikke brukes under sløyfe, som det reduserer ytelsen.
  • Ingen grunn til å svinge som alle de resulterende understreng vil bli vist i en rad

begrensninger:

  • Man må vite den totale no. mellomrom (sub-streng).

Merk : løsningen kan gi sub-string opp til N.

Å vant begrensningen vi kan bruke følgende ref .

Men igjen det ovennevnte løsning kan ikke være bruk i en tabell (Actaully jeg var ikke i stand til å bruke det).

Igjen Jeg håper denne løsningen kan hjelpe noen-en.

Oppdatering: Ved Records> 50000 er det ikke tilrådelig å bruke LOOPSsom det vil forringe ytelsen

Svarte 24/01/2013 kl. 06:43
kilden bruker

stemmer
1

Jeg vet det sent, men jeg har nylig hatt dette kravet, og kom opp med under kode. Jeg har ikke noe valg å bruke brukerdefinerte funksjonen. Håper dette hjelper.

SELECT 
    SUBSTRING(
                SUBSTRING('Hello John Smith' ,0,CHARINDEX(' ','Hello John Smith',CHARINDEX(' ','Hello John Smith')+1)
                        ),CHARINDEX(' ','Hello John Smith'),LEN('Hello John Smith')
            )
Svarte 17/09/2018 kl. 21:07
kilden bruker

stemmer
1

ENKEL LØSNING FOR PARSING fornavn og etternavn

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

I mitt tilfelle (og i mange andre synes det ...), jeg har en liste med fornavn og etternavn atskilt med et enkelt mellomrom. Dette kan brukes direkte i en utvalgt uttalelse analysere for- og etternavn.

-- 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
Svarte 20/08/2018 kl. 18:59
kilden bruker

stemmer
1

Her er en funksjon som vil oppnå spørsmålet mål om å splitte en streng og tilgang element 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

bruk:

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

Resultat:

John
Svarte 26/04/2018 kl. 21:16
kilden bruker

stemmer
1

Aaron Bertrand svar er flott, men feil. Det er ikke en nøyaktig håndtere en plass som skilletegn (som var eksemplet i det opprinnelige spørsmålet) Da lengden funksjons strimler etterfølgende mellomrom.

Det følgende er hans kode, med en liten justering for å tillate en plass skilletegn:

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
    );
Svarte 22/03/2018 kl. 14:38
kilden bruker

stemmer
1

En moderne tilnærming ved hjelp STRING_SPLIT krever SQL Server 2016 og nyere.

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

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

Resultat:

RowNr   value
1       Hello
2       John
3       Smith

Nå er det mulig å få th n'te element fra radnummer.

Svarte 02/01/2018 kl. 15:02
kilden bruker

stemmer
1

Fra og med SQL Server 2016 vi string_split

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

SELECT value FROM string_split(@string, ',')
Svarte 04/09/2017 kl. 21:52
kilden bruker

stemmer
1

Pure set-basert løsning med TVFmed rekursiv CTE. Du kan JOINog APPLYdenne funksjonen til noen datasett.

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

bruk:

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

Resultat:

value   index
-------------
John    1
Svarte 13/01/2015 kl. 06:37
kilden bruker

stemmer
0

Du kan bruke STRING_SPLITfunksjonen tilgjengelig i SQL Server 2016 eller senere. Vær oppmerksom på at det er ingen garanti for at dels vil bli returnert i noen spesiell rekkefølge.

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

Hvor:

  • STRING_SPLIT returnerer en tabell med en kolonne som heter value
  • FOR XML PATH('') forvandler radene til <substr>a</substr><substr>b</substr>...
  • TYPEomdanner ovenfor til XMLdatatype
  • value('substr[2]', 'VARCHAR(100)')kjører XPath-uttrykk på det ovennevnte og returnerer VARCHARdatatype

Resultat:

| 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          |
Svarte 24/01/2018 kl. 12:27
kilden bruker

stemmer
0

bygning på @NothingsImpossible løsning, eller snarere kommentere mest var svaret (like under den aksepterte en), jeg fant følgende quick-and-dirty løsning oppfylle mine egne behov - det har en fordel av å være utelukkende innenfor SQL domene.

gitt en streng "første, andre, tredje, fjerde, femte", si, jeg ønsker å få den tredje token. Dette fungerer bare hvis vi vet hvor mange tokens strengen er nødt til - i dette tilfellet er det 5. så min måte av handlingen er å hogge de siste to symbolene unna (indre spørring), og deretter å hogge de to første tokens unna ( ytre spørring)

Jeg vet at dette er stygge og dekker de spesifikke forholdene jeg var i, men jeg legger det bare i tilfelle noen finner det nyttig. jubel

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
Svarte 31/10/2016 kl. 14:18
kilden bruker

stemmer
0
declare @strng varchar(max)='hello john smith'
select (
    substring(
        @strng,
        charindex(' ', @strng) + 1,
        (
          (charindex(' ', @strng, charindex(' ', @strng) + 1))
          - charindex(' ',@strng)
        )
    ))
Svarte 14/07/2016 kl. 05:29
kilden bruker

stemmer
0

Jeg devoloped dette,

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

den eneste oppmerksomheten du bør er dot '' den enden av @x alltid skal være der.

Svarte 15/10/2015 kl. 10:50
kilden bruker

stemmer
0

hvis noen ønsker å få bare en del av seperatured teksten kan bruke denne

select * from fromSplitStringSep ( 'WORD1 wordr2 søkeord3',' ')

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
  )
Svarte 13/02/2015 kl. 09:14
kilden bruker

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

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

    END 
    RETURN 
END

Og bruke den

select *from dbo.fnSplitString('Querying SQL Server','')
Svarte 20/12/2014 kl. 11:58
kilden bruker

stemmer
0

mens tilsvarende xml baserte svaret ved josejuan, fant jeg at behandlingen av xml banen bare én gang, da sving var moderat mer effektiv:

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

løp i 08: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

løp i 09:20

Svarte 08/12/2014 kl. 03:59
kilden bruker

stemmer
0

Rekursiv CTE løsning med serveren smerte, teste det

MS SQL Server 2008-skjema oppsett :

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

Spørring 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

resultater :

|    A_L | N |
|--------|---|
| Hello  | 0 |
|  John  | 1 |
| Smith  | 2 |
Svarte 16/01/2014 kl. 10:38
kilden bruker

stemmer
0

Dette er noe jeg gjorde for å få en bestemt token i en streng. (Testet i MSSQL 2008)

Først oppretter følgende funksjoner: (finnes i: her

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;

og

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

så kan du bruke det sånn:

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

som returnerer 1111

Svarte 25/07/2013 kl. 11:07
kilden bruker

stemmer
0

Vel, er min ikke alt enklere, men her er koden jeg bruker for å dele en kommaseparert innspill variabel i individuelle verdier, og sette det inn i en tabell variabel. Jeg er sikker på at du kan endre dette litt å splitte basert på en plass og deretter å gjøre en grunnleggende SELECT spørring mot tabellen variabel for å få resultater.

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

DECLARE @vchAccountingCycle varchar(10)
DECLARE @intPosition int

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

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

Konseptet er ganske mye det samme. En annen alternativ er å utnytte .NET kompatibilitet innen SQL Server 2005 selv. Du kan faktisk skrive deg en enkel metode i .NET som ville splitte strengen og deretter avsløre at som en lagret prosedyre / funksjon.

Svarte 05/08/2008 kl. 18:36
kilden bruker

stemmer
-1

Jeg har brukt vzczc svar ved hjelp av rekursiv CTE er i noen tid, men har lyst til å oppdatere den til å håndtere en variabel lengde separator og også å håndtere strenger med ledende og lagging "separatorer" som når du har en CSV-fil med poster som :

"Bob", "Smith", "Sunnyvale", "Oslo"

eller når du arbeider med seks del fqn er som vist nedenfor. Jeg bruker disse mye for logging av subject_fqn for revisjon, feilhåndtering, etc. og parsename behandler kun fire deler:

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

Her er min oppdatert versjon, og takket være vzczc er for hans opprinnelige innlegget!

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 
Svarte 19/08/2014 kl. 19:45
kilden bruker

stemmer
-1

En enkel optimalisert algoritme:

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 INTO  @Result VALUES(SUBSTRING(@Text, 0, @PathInd))
        SET @Text= SUBSTRING(@Text, @PathInd+1, LEN(@Text))
    END
        RETURN 
END
Svarte 01/05/2014 kl. 06:26
kilden bruker

stemmer
-1

Her er en SQL UDF som kan splitte en streng og ta bare en viss del.

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
Svarte 20/03/2014 kl. 14:41
kilden bruker

stemmer
-1

Her er min løsning som kan hjelpe noen. Endring av Jonesinator svar ovenfor.

Hvis jeg har en rekke avgrensede INT verdier og ønsker en tabell over ints tilbake (som jeg kan deretter bli med på). f.eks '1,20,3,343,44,6,8765'

Opprett en UDF:

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

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

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

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

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

RETURN
END
GO

Så får tabellresultatene:

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

1
20
3
343
44
6
8765

Og i et delta uttalelse:

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

Hvis du ønsker å returnere en liste over NVARCHARs stedet for ints så bare endre tabellen definisjon:

RETURNS @table TABLE 
(
    Value NVARCHAR(MAX) NOT NULL
)
Svarte 19/06/2013 kl. 23:42
kilden bruker

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