Πώς μπορώ να χωρίσει μια σειρά, έτσι μπορώ να έχω πρόσβαση αντικείμενο x;

ψήφοι
442

Χρησιμοποιώντας τον SQL Server, πώς μπορώ να χωρίσει μια σειρά, έτσι μπορώ να έχω πρόσβαση αντικείμενο x;

Πάρτε μια σειρά «Γεια John Smith». Πώς μπορώ να χωρίσει το string από το χώρο και πρόσβαση στο στοιχείο στο δείκτη 1, η οποία θα πρέπει να επιστρέψει «John»;

Δημοσιεύθηκε 05/08/2008 στις 19:15
πηγή χρήστη
Σε άλλες γλώσσες...                            


43 απαντήσεις

ψήφοι
335

Δεν πιστεύω ότι ο SQL Server έχει ένα ενσωματωμένο διάσπαση λειτουργίας, έτσι ώστε εκτός από ένα UDF, η μόνη άλλη απάντηση που ξέρω είναι να επισκιάσουν τη λειτουργία PARSENAME:

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

PARSENAME παίρνει μια κλωστή και χωρίζει το στο χαρακτήρα περιόδου. Παίρνει ένα αριθμό ως δεύτερο επιχείρημα της, και ότι ο αριθμός καθορίζει ποια τμήμα της συμβολοσειράς να επιστρέψει (εργάζονται από πίσω προς τα εμπρός).

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

Προφανές πρόβλημα είναι όταν η σειρά περιέχει ήδη ένα χρονικό διάστημα. Εξακολουθώ να πιστεύω χρησιμοποιώντας ένα UDF είναι ο καλύτερος τρόπος για ... κάθε άλλη πρόταση;

Απαντήθηκε 05/08/2008 στις 19:45
πηγή χρήστη

ψήφοι
177

Μπορείτε να βρείτε τη λύση σε SQL Ορίζεται από το χρήστη λειτουργία για να αναλύσει ένα οριοθετημένο String χρήσιμο (από το Σχέδιο Κώδικα ).

Μπορείτε να χρησιμοποιήσετε αυτήν την απλή λογική:

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
Απαντήθηκε 05/08/2008 στις 19:28
πηγή χρήστη

ψήφοι
106

Πρώτον, να δημιουργήσει μια λειτουργία (χρησιμοποιώντας ΣΤΕ, η έκφραση κοινό τραπέζι καταργεί την ανάγκη για έναν πίνακα temp)

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

Στη συνέχεια, χρησιμοποιήστε το κάθε πίνακα (ή να το τροποποιήσετε ώστε να ταιριάζει στο πλαίσιο των υφιστάμενων αποθηκεύονται proc σας) όπως αυτό.

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

Εκσυγχρονίζω

Προηγούμενη έκδοση θα αποτύχει για συμβολοσειρά εισόδου περισσότερο από 4000 χαρακτήρες. Αυτή η έκδοση φροντίζει για τον περιορισμό:

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

GO

Χρήση παραμένει η ίδια.

Απαντήθηκε 05/08/2008 στις 19:57
πηγή χρήστη

ψήφοι
51

Οι περισσότερες από τις λύσεις εδώ χρησιμοποιούν, ενώ βρόχους ή αναδρομικές ΣΤΕ. Μια προσέγγιση που βασίζεται σε θα είναι ανώτερη, υπόσχομαι:

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

Περισσότερα για διάσπαση λειτουργίες, γιατί (και απόδειξη ότι), ενώ βρόχους και αναδρομικοί ΣΤΕ δεν κλίμακα, και καλύτερες εναλλακτικές λύσεις, αν χορδές διάσπαση που προέρχονται από το στρώμα εφαρμογής:

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

Απαντήθηκε 12/11/2013 στις 18:16
πηγή χρήστη

ψήφοι
37

Μπορείτε να αξιοποιήσουν έναν πίνακα Αριθμός για να κάνει την ανάλυση της συμβολοσειράς.

Δημιουργήστε μια φυσική πίνακα αριθμούς:

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

Δημιουργία πίνακα δοκιμής με 1000000 σειρές

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

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

Δημιουργήστε τη λειτουργία

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

Χρήση (έξοδοι 3mil σειρές στη δεκαετία του '40 για το laptop μου)

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

καθάρισε

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

Απόδοση εδώ δεν είναι καταπληκτικό, αλλά καλώντας μια λειτουργία πάνω από ένα τραπέζι εκατομμύρια σειρά δεν είναι η καλύτερη ιδέα. Αν εκτέλεση μια σειρά χωρίζεται σε πολλές σειρές, θα αποφύγετε τη λειτουργία.

Απαντήθηκε 27/10/2008 στις 17:48
πηγή χρήστη

ψήφοι
20

Εδώ είναι ένα UDF που θα το κάνει. Θα επιστρέψει έναν πίνακα των περιορισμένων αξίες, δεν έχουν δοκιμάσει όλα τα σενάρια σχετικά με αυτό, αλλά το παράδειγμά σας δουλεύει μια χαρά.


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

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

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

            Insert Into @ReturnTable(part)
            Select @part

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


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

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

    RETURN 
END
GO

Θα το ονομάσουμε κάπως έτσι:


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

Επεξεργασία: Ενημέρωση λύση για να χειριστεί delimters με τζαμάκι> 1, όπως σε:


select * From SplitString('Hello**John**Smith','**')
Απαντήθηκε 05/08/2008 στις 19:39
πηγή χρήστη

ψήφοι
16

Όχι κώδικα, αλλά διαβάστε το οριστικό άρθρο σχετικά με αυτό. Όλες οι λύσεις σε άλλες απαντήσεις είναι γεύσεις από αυτές που αναφέρονται σε αυτό το άρθρο: Πίνακες και λίστες στον SQL Server 2005 και μετέπειτα

Προσωπικά, έχω χρησιμοποιήσει μια λύση Αριθμοί πίνακα πιο συχνά, επειδή ταιριάζει αυτό που πρέπει να κάνω ...

Απαντήθηκε 26/09/2010 στις 14:44
πηγή χρήστη

ψήφοι
15

Εδώ προσθέτω ένα απλό τρόπο της λύσης

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

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


Εκτελέστε τη λειτουργία, όπως αυτό

  select * from dbo.split('Hello John Smith',' ')
Απαντήθηκε 30/01/2013 στις 10:41
πηγή χρήστη

ψήφοι
12

Αυτή η ερώτηση είναι όχι για μια διάσπαση προσέγγιση εγχόρδων , αλλά για το πώς να πάρει το νιοστό στοιχείο .

Όλες οι απαντήσεις εδώ κάνει κάποιο είδος της διάσπασης της συμβολοσειράς χρησιμοποιώντας αναδρομή, CTEs, πολλαπλές CHARINDEX, REVERSEκαι PATINDEX, εφευρίσκοντας λειτουργίες, απαιτούν μεθόδους CLR, τον αριθμό πίνακες, CROSS APPLYs ... Οι περισσότερες απαντήσεις καλύπτουν πολλές γραμμές κώδικα.

Αλλά - αν πραγματικά δεν θέλουν τίποτα περισσότερο από μια προσέγγιση για να πάρει το νιοστό στοιχείο - αυτό μπορεί να γίνει ως πραγματική-επένδυση , χωρίς UDF, ούτε καν μια υπο-επιλογή ... Και ως ένα επιπλέον όφελος: Τύπος ασφαλή

Πάρτε μέρος 2 οριοθετείται από ένα διάστημα:

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

Φυσικά μπορείτε να χρησιμοποιήσετε μεταβλητές για διαχωριστικό και τη θέση (χρήση sql:columnγια να ανακτήσει τη θέση απ 'ευθείας από την αξία ενός ερωτήματος):

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

Αν εγχόρδων σας μπορεί να περιλαμβάνει απαγορευμένο χαρακτήρες (ειδικά ένας από &><), μπορείτε να το κάνετε με αυτόν τον τρόπο. Απλά χρησιμοποιήστε FOR XML PATHστη χορδή σας πρώτα για να αντικαταστήσει όλα τα απαγορευμένα χαρακτήρες με την τοποθέτηση ακολουθία διαφυγής σιωπηρά.

Είναι μια πολύ ειδική περίπτωση - επιπλέον - διαχωριστικό σας είναι το ερωτηματικό . Σε αυτή την περίπτωση θα αντικαταστήσει το διαχωριστικό πρώτος που θα «# DLMT #», και να αντικαταστήσει αυτό με τις ετικέτες XML τελικά:

SET @input=N'Some <, > and &;Other äöü@€;One more';
SET @dlmt=N';';
SELECT CAST(N'<x>' + REPLACE((SELECT REPLACE(@input,@dlmt,'#DLMT#') AS [*] FOR XML PATH('')),N'#DLMT#',N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)');
Απαντήθηκε 08/07/2016 στις 20:41
πηγή χρήστη

ψήφοι
10

Τι γίνεται με τη χρήση stringκαι values()τη δήλωση;

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

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

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

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

INSERT IGNORE  INTO @Splited
EXEC(@str)

SELECT * FROM @Splited

Αποτέλεσμα-set επιτευχθεί.

id  item
1   Hello
2   John
3   Smith
Απαντήθηκε 01/03/2013 στις 17:26
πηγή χρήστη

ψήφοι
10

Κατά τη γνώμη μου, εσείς που καθιστά πάρα πολύ περίπλοκο. Απλά δημιουργήστε ένα UDF CLR και να τελειώνουμε με αυτό.

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

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

    return new SqlString(string.Join(" OR ", SearchWords.ToArray()));
  }
};
Απαντήθηκε 19/07/2012 στις 22:46
πηγή χρήστη

ψήφοι
8

Αυτό το πρότυπο λειτουργεί καλά και μπορείτε να γενικεύσει

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

Σημειώστε ΠΕΔΙΟ , INDEX και TYPE .

Ας κάποιο τραπέζι με αναγνωριστικά, όπως

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

Στη συνέχεια, μπορείτε να γράψετε

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

διάσπαση και χύτευση όλα τα μέρη.

Απαντήθηκε 11/11/2014 στις 14:31
πηγή χρήστη

ψήφοι
8

Μπορώ να χρησιμοποιήσω την απάντηση του Frederic, αλλά αυτό δεν λειτούργησε στον SQL Server 2005

Μου τροποποιηθεί και είμαι με τη χρήση selectμε union allκαι λειτουργεί

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

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

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

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

INSERT IGNORE  INTO @Splited
EXEC(@str)

SELECT * FROM @Splited

Και το αποτέλεσμα-σετ είναι:

id  item
1   Hello
2   John
3   Smith
4   how
5   are
6   you
Απαντήθηκε 13/08/2013 στις 16:11
πηγή χρήστη

ψήφοι
6

Ακόμα ένας πάρετε-οστό μέρος της συμβολοσειράς από τη λειτουργία delimeter:

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

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

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

        set @position = @position - 1
    end

    return null
end

και η χρήση:

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

η οποία επιστρέφει:

c
Απαντήθηκε 08/01/2016 στις 14:30
πηγή χρήστη

ψήφοι
6

Έψαχνα για τη λύση για την καθαρή και τα παρακάτω έργα για μένα. Κωδ .

Και μπορείτε να καλέσετε τη λειτουργία ως εξής:

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
Απαντήθηκε 20/11/2011 στις 07:40
πηγή χρήστη

ψήφοι
5

Το ακόλουθο παράδειγμα χρησιμοποιεί ένα αναδρομικό CTE

Ενημέρωση 09/18/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 για SQLFiddle

Απαντήθηκε 14/03/2013 στις 11:18
πηγή χρήστη

ψήφοι
5

Δοκιμάστε αυτό:

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

Δοκιμάστε το όπως αυτό:

select * from SplitWordList('Hello John Smith')
Απαντήθηκε 05/08/2008 στις 19:41
πηγή χρήστη

ψήφοι
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

Απαντήθηκε 05/11/2013 στις 01:12
πηγή χρήστη

ψήφοι
2

Εάν η βάση δεδομένων σας έχει επίπεδο συμβατότητας των 130 ή υψηλότερη, τότε μπορείτε να χρησιμοποιήσετε το STRING_SPLIT λειτουργία μαζί με OFFSET FETCH ρήτρες για να πάρει το συγκεκριμένο στοιχείο από το δείκτη.

Για να λάβετε το στοιχείο σε δείκτη 1, μπορείτε να χρησιμοποιήσετε τον ακόλουθο κώδικα

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

Για να ελέγξετε το επίπεδο τη συμβατότητα της βάσης δεδομένων σας , να εκτελέσει αυτόν τον κώδικα:

SELECT compatibility_level  
FROM sys.databases WHERE name = 'YourDBName';
Απαντήθηκε 05/04/2018 στις 10:23
πηγή χρήστη

ψήφοι
2

Μπορείτε να χωρίσετε μια σειρά σε SQL, χωρίς να χρειάζεται μια λειτουργία:

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

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

Εάν πρέπει να υποστηρίξει αυθαίρετη χορδές (με xml ειδικούς χαρακτήρες)

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

-- http://stackoverflow.com/questions/14712864/how-to-query-values-from-xml-nodes
SELECT 
    x.XmlCol.value('.', 'nvarchar(MAX)') AS val 
FROM 
(
    SELECT 
    CAST('<e>' + REPLACE((SELECT @bla FOR XML PATH('')), ',', '</e><e>') + '</e>' AS xml) AS RawXml
) AS b 
CROSS APPLY b.RawXml.nodes('e') x(XmlCol); 
Απαντήθηκε 23/10/2015 στις 10:07
πηγή χρήστη

ψήφοι
2

Σχεδόν όλες οι άλλες απαντήσεις χωρίζονται κωδικό αντικαθιστούν το string διάσπασης που σπαταλά τους κύκλους της CPU και εκτελεί περιττές εκχωρήσεις μνήμης.

Θα καλύψει ένα πολύ καλύτερο τρόπο για να κάνετε μια διάσπαση κορδόνι εδώ: http://www.digitalruby.com/split-string-sql-server/

Εδώ είναι ο κώδικας:

SET NOCOUNT ON

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

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

WHILE @SplitEndPos > 0
BEGIN
    SET @SplitValue = SUBSTRING(@StringToSplit, @SplitStartPos, (@SplitEndPos - @SplitStartPos))
    INSERT 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.
Απαντήθηκε 26/08/2014 στις 17:50
πηγή χρήστη

ψήφοι
2

Ξέρω ότι είναι μια παλιά ερώτηση, αλλά νομίζω ότι κάποιος μπορεί να επωφεληθεί από τη λύση μου.

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

SQL FIDDLE

Πλεονεκτήματα:

  • Χωρίζει όλες τις 3 υπο-strings deliminator από «».
  • Κάποιος δεν πρέπει να χρησιμοποιούν βρόχο while, καθώς μειώνει την απόδοση.
  • Δεν χρειάζεται να στρέφεται και όλες τις προκύπτουσες υπο-string θα εμφανιστεί σε μία σειρά

περιορισμοί:

  • Κάποιος πρέπει να γνωρίζει το συνολικό όχι. των χώρων (υπο-συμβολοσειρά).

Σημείωση : το διάλυμα μπορεί να δώσει υπο-συμβολοσειρά μέχρι να N.

Για να ξεπέρασε τον περιορισμό μπορούμε να χρησιμοποιήσουμε την ακόλουθη ref .

Αλλά και πάλι η παραπάνω λύση δεν μπορεί να χρησιμοποιηθεί σε έναν πίνακα (actaully δεν ήμουν σε θέση να το χρησιμοποιήσετε).

Και πάλι ελπίζω ότι αυτή η λύση μπορεί να βοηθήσει κάποια-ένα.

Ενημέρωση: Σε περίπτωση Records> 50000 δεν είναι σκόπιμο να χρησιμοποιήσει LOOPS, καθώς θα υποβαθμίσει την Απόδοση

Απαντήθηκε 24/01/2013 στις 07:43
πηγή χρήστη

ψήφοι
1

Ξέρω ότι αργά, αλλά είχα πρόσφατα την απαίτηση αυτή και ήρθε με τον παρακάτω κωδικό. Δεν έχω την επιλογή να χρησιμοποιήσετε χρήστη καθορισμένη λειτουργία. Η ελπίδα αυτό βοηθά.

SELECT 
    SUBSTRING(
                SUBSTRING('Hello John Smith' ,0,CHARINDEX(' ','Hello John Smith',CHARINDEX(' ','Hello John Smith')+1)
                        ),CHARINDEX(' ','Hello John Smith'),LEN('Hello John Smith')
            )
Απαντήθηκε 17/09/2018 στις 21:07
πηγή χρήστη

ψήφοι
1

Απλή λύση για την ανάλυση ΟΝΟΜΑΤΕΠΩΝΥΜΟ

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.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
Απαντήθηκε 20/08/2018 στις 18:59
πηγή χρήστη

ψήφοι
1

Εδώ είναι μια λειτουργία που θα επιτευχθεί ο στόχος της διάσπασης μια σειρά και την πρόσβαση σε σημείο Χ της ερώτησης:

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

Χρήση:

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

Αποτέλεσμα:

John
Απαντήθηκε 26/04/2018 στις 21:16
πηγή χρήστη

ψήφοι
1

απάντηση Aaron Bertrand είναι μεγάλη, αλλά λανθασμένη. Αυτό δεν χειρίζεται με ακρίβεια ένα χώρο σαν οριοθέτη (όπως ήταν η παράδειγμα στο αρχικό ερώτημα), δεδομένου ότι οι λωρίδες λειτουργία μήκος τελικά διαστήματα.

Το παρακάτω είναι ο κώδικας του, με μια μικρή προσαρμογή για να επιτρέψει για μια θέση οριοθέτη:

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
    );
Απαντήθηκε 22/03/2018 στις 14:38
πηγή χρήστη

ψήφοι
1

Ξεκινώντας με τον SQL Server 2016 που string_split

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

SELECT value FROM string_split(@string, ',')
Απαντήθηκε 04/09/2017 στις 21:52
πηγή χρήστη

ψήφοι
1

Καθαρό διάλυμα παύσης που βασίζεται χρήση TVFμε αναδρομική CTE. Μπορείτε JOINκαι APPLYαυτή η λειτουργία σε κάθε σύνολο δεδομένων.

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

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

Χρήση:

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

Αποτέλεσμα:

value   index
-------------
John    1
Απαντήθηκε 13/01/2015 στις 06:37
πηγή χρήστη

ψήφοι
0

Μπορείτε να χρησιμοποιήσετε STRING_SPLITτη λειτουργία διαθέσιμη σε SQL Server 2016 ή αργότερα. Να ενημερώνουμε ότι δεν υπάρχει καμία εγγύηση ότι οι συμβολοσειρές θα επιστραφούν με κάποια συγκεκριμένη σειρά.

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

Οπου:

  • STRING_SPLIT επιστρέφει έναν πίνακα με μια στήλη που ονομάζεται value
  • FOR XML PATH('') μετατρέπει τις σειρές προς <substr>a</substr><substr>b</substr>...
  • TYPEμετατρέπει το παραπάνω για να XMLτύπος δεδομένων
  • value('substr[2]', 'VARCHAR(100)')τρέχει έκφραση XPath για το ανωτέρω και επιστρέφει VARCHARdatatype

Αποτέλεσμα:

| 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          |
Απαντήθηκε 24/01/2018 στις 12:27
πηγή χρήστη

ψήφοι
0

Μια σύγχρονη προσέγγιση χρησιμοποιώντας STRING_SPLIT , απαιτεί SQL Server 2016 και πάνω.

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

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

Αποτέλεσμα:

RowNr   value
1       Hello
2       John
3       Smith

Τώρα είναι δυνατόν να πάρει ο νιοστή στοιχείο από τον αριθμό σειράς.

Απαντήθηκε 02/01/2018 στις 15:02
πηγή χρήστη

ψήφοι
0

με βάση @NothingsImpossible λύση, ή, μάλλον, σχολιάζει το πιο ψήφισε απάντηση (ακριβώς κάτω από την αποδεκτή μία), βρήκα το παρακάτω γρήγορο-και-βρώμικο λύση εκπληρώσει τις δικές μου ανάγκες - έχει ένα πλεονέκτημα να είναι αποκλειστικά και μόνο μέσα SQL τομέα.

δίνεται μια σειρά «πρώτη? δευτερόλεπτο? τρίτο? τέταρτο? πέμπτη», ας πούμε, θέλω να πάρω το τρίτο κουπόνι. αυτό λειτουργεί μόνο αν γνωρίζουμε πόσες μάρκες η σειρά θα έχει - σε αυτή την περίπτωση είναι 5. τόσο ο τρόπος μου δράσης είναι να κόψουν τα τελευταία δύο μάρκες μακριά (εσωτερική ερώτημα), και στη συνέχεια να τεμαχίσει τις δύο πρώτες μάρκες μακριά ( εξωτερική επερώτηση)

Ξέρω ότι αυτό είναι άσχημο και καλύπτει τις ειδικές συνθήκες ήμουν μέσα, αλλά είμαι το απόσπαση μόνο στην περίπτωση που κάποιος θεωρεί χρήσιμη. Στην υγειά σας

select 
    REVERSE(
        SUBSTRING(
            reverse_substring, 
            0, 
            CHARINDEX(';', reverse_substring)
        )
    ) 
from 
(
    select 
        msg,
        SUBSTRING(
            REVERSE(msg), 
            CHARINDEX(
                ';', 
                REVERSE(msg), 
                CHARINDEX(
                    ';',
                    REVERSE(msg)
                )+1
            )+1,
            1000
        ) reverse_substring
    from 
    (
        select 'first;second;third;fourth;fifth' msg
    ) a
) b
Απαντήθηκε 31/10/2016 στις 14:18
πηγή χρήστη

ψήφοι
0
declare @strng varchar(max)='hello john smith'
select (
    substring(
        @strng,
        charindex(' ', @strng) + 1,
        (
          (charindex(' ', @strng, charindex(' ', @strng) + 1))
          - charindex(' ',@strng)
        )
    ))
Απαντήθηκε 14/07/2016 στις 05:29
πηγή χρήστη

ψήφοι
0

Θα devoloped αυτό,

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

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

η μόνη προσοχή που πρέπει να είναι τελεία «» ότι τέλος του @x πάντα θα πρέπει να υπάρχει.

Απαντήθηκε 15/10/2015 στις 10:50
πηγή χρήστη

ψήφοι
0

αν κάποιος θέλει να πάρει μόνο ένα μέρος του seperatured κειμένου μπορεί να χρησιμοποιήσει αυτό το

επιλέξτε * από fromSplitStringSep ( 'word1 wordr2 λέξη3',»«)

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
  )
Απαντήθηκε 13/02/2015 στις 09:14
πηγή χρήστη

ψήφοι
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

Και να το χρησιμοποιήσετε

select *from dbo.fnSplitString('Querying SQL Server','')
Απαντήθηκε 20/12/2014 στις 11:58
πηγή χρήστη

ψήφοι
0

ενώ παρόμοια με τη βάση απάντηση xml από josejuan, βρήκα ότι η επεξεργασία της διαδρομής xml μόνο μία φορά, στη συνέχεια, περιστρέφοντας ήταν μετρίως πιο αποτελεσματική:

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

έτρεξε στο 8:30

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

έτρεξε στο 9:20

Απαντήθηκε 08/12/2014 στις 03:59
πηγή χρήστη

ψήφοι
0

Αναδρομική λύση ΣΤΕ με τον πόνο του server, να το δοκιμάσετε

MS SQL Server 2008 Schema εγκατάστασης :

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

Ερώτημα 1 :

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

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

αποτελέσματα :

|    A_L | N |
|--------|---|
| Hello  | 0 |
|  John  | 1 |
| Smith  | 2 |
Απαντήθηκε 16/01/2014 στις 11:38
πηγή χρήστη

ψήφοι
0

Αυτό είναι κάτι που έκανα για να πάρετε μια συγκεκριμένη λογική σε μια σειρά. (Δοκιμασμένο σε MSSQL 2008)

Κατ 'αρχάς, δημιουργώντας τις ακόλουθες λειτουργίες: (που βρίσκεται στο: εδώ

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

και

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

τότε μπορείτε να το χρησιμοποιήσετε σαν αυτό:

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

που επιστρέφουν 1111

Απαντήθηκε 25/07/2013 στις 12:07
πηγή χρήστη

ψήφοι
0

Λοιπόν, η δική μου δεν είναι και τόσο απλή, αλλά εδώ είναι ο κώδικας που χρησιμοποιώ για να χωρίσει ένα οριοθετημένο με κόμματα μεταβλητών εισόδου σε μεμονωμένες τιμές, και το βάζουμε σε μια μεταβλητή πίνακα. Είμαι βέβαιος ότι θα μπορούσατε να τροποποιήσετε αυτό το λίγο να χωρίσει βασίζεται σε ένα χώρο και στη συνέχεια να κάνουμε ένα βασικό ερώτημα SELECT κατά της εν λόγω πίνακα μεταβλητών για να πάρετε τα αποτελέσματα σας.

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

DECLARE @vchAccountingCycle varchar(10)
DECLARE @intPosition int

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

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

Η έννοια είναι λίγο πολύ το ίδιο. Μια άλλη εναλλακτική λύση είναι να αξιοποιήσει τη συμβατότητα .NET μέσα σε SQL Server 2005 η ίδια. Μπορείτε ουσιαστικά να γράψετε στον εαυτό σας μια απλή μέθοδο σε .NET που θα χωρίσει το string και στη συνέχεια εκθέτουν ότι μια αποθηκευμένη διαδικασία / λειτουργία.

Απαντήθηκε 05/08/2008 στις 19:36
πηγή χρήστη

ψήφοι
-1

Έχω χρησιμοποιήσει απάντηση vzczc χρησιμοποιώντας αναδρομική ΕΕΠ για κάποιο χρονικό διάστημα, αλλά ήθελε να το ενημερώσετε για να χειριστεί ένα διαχωριστικό μεταβλητού μήκους, αλλά και να χειριστεί χορδές με κορυφαίους και υστερούν «διαχωριστικά», όπως όταν έχετε ένα αρχείο csv με τα αρχεία, όπως :

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

ή όταν έχουμε να κάνουμε με έξι μέρος fqn, όπως φαίνεται παρακάτω. Μπορώ να χρησιμοποιήσω αυτά εκτενώς για την καταγραφή της subject_fqn για τον έλεγχο, την αντιμετώπιση των λαθών, κλπ και parsename χειρίζεται μόνο τέσσερα μέρη:

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

Εδώ είναι ενημερωμένη έκδοση μου, και χάρη στην vzczc για την αρχική του θέση!

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

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

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

create function [utility].[split_string] ( 
  @input       [nvarchar](max) 
  , @separator [sysname] 
  , @lead      [sysname] 
  , @lag       [sysname]) 
returns @node_list table ( 
  [index]  [int] 
  , [node] [nvarchar](max)) 
  begin 
      declare @separator_length [int]= len(@separator) 
              , @lead_length    [int] = isnull(len(@lead), 0) 
              , @lag_length     [int] = isnull(len(@lag), 0); 
      -- 
      set @input = right(@input, len(@input) - @lead_length); 
      set @input = left(@input, len(@input) - @lag_length); 
      -- 
      with [splitter]([index], [starting_position], [start_location]) 
           as (select cast(@separator_length as [bigint]) 
                      , cast(1 as [bigint]) 
                      , charindex(@separator, @input) 
               union all 
               select [index] + 1 
                      , [start_location] + @separator_length 
                      , charindex(@separator, @input, [start_location] + @separator_length) 
               from   [splitter] 
               where  [start_location] > 0) 
      -- 
      insert into @node_list 
                  ([index],[node]) 
        select [index] - @separator_length                   as [index] 
               , substring(@input, [starting_position], case 
                                                            when [start_location] > 0 
                                                                then 
                                                              [start_location] - [starting_position] 
                                                            else 
                                                              len(@input) 
                                                        end) as [node] 
        from   [splitter]; 
      -- 
      return; 
  end; 
go 
Απαντήθηκε 19/08/2014 στις 20:45
πηγή χρήστη

ψήφοι
-1

Μια απλή βελτιστοποιημένο αλγόριθμο:

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
Απαντήθηκε 01/05/2014 στις 07:26
πηγή χρήστη

ψήφοι
-1

Εδώ είναι μια SQL UDF που μπορεί να χωρίσει μια σειρά και να αρπάξει μόνο ένα συγκεκριμένο κομμάτι.

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

BEGIN

DECLARE @RtnValue table 
(

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


    DECLARE @result varchar(1000)

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

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

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

    Return @result
END
Απαντήθηκε 20/03/2014 στις 15:41
πηγή χρήστη

ψήφοι
-1

Εδώ είναι η λύση μου που μπορεί να βοηθήσει κάποιος. Τροποποίηση της απάντησης Jonesinator του παραπάνω.

Αν έχω μια σειρά από οριοθετημένο τιμές INT και θέλουν έναν πίνακα του Ints επέστρεψε (η οποία στη συνέχεια θα μπορούν να ενταχθούν σε). π.χ. «1,20,3,343,44,6,8765»

Δημιουργήστε ένα UDF:

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

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

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

WHILE LEN(@String) > 0
    BEGIN
        IF PATINDEX(@Pattern, @String) > 0
        BEGIN
            SET @Value = SUBSTRING(@String, 0, PATINDEX(@Pattern, @String))
            INSERT 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

Στη συνέχεια, να πάρει τα αποτελέσματα πίνακα:

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

1
20
3
343
44
6
8765

Και σε ένα σύνδεσμο δήλωση:

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

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

Αν θέλετε να επιστρέψετε μια λίστα NVARCHARs αντί Ints τότε απλά αλλάξτε τον ορισμό πίνακα:

RETURNS @table TABLE 
(
    Value NVARCHAR(MAX) NOT NULL
)
Απαντήθηκε 20/06/2013 στις 00:42
πηγή χρήστη

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