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

ψήφοι
442

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

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

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


47 απαντήσεις

ψήφοι
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
πηγή χρήστη

ψήφοι
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
πηγή χρήστη

ψήφοι
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
πηγή χρήστη

ψήφοι
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
πηγή χρήστη

ψήφοι
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
πηγή χρήστη

ψήφοι
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
πηγή χρήστη

ψήφοι
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
πηγή χρήστη

ψήφοι
16

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

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

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

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