Cara membagi nilai yang dipisahkan koma menjadi kolom

141

Saya punya meja seperti ini

Value   String
-------------------
1       Cleo, Smith

Saya ingin memisahkan string yang dipisahkan koma menjadi dua kolom

Value  Name Surname
-------------------
1      Cleo   Smith

Saya hanya perlu dua kolom tambahan tetap

Gurru
sumber
Dari String_Split: "Baris keluaran mungkin dalam urutan apa pun. Urutan tidak dijamin sesuai dengan urutan substring dalam string masukan." Itu ditambahkan di SQL Server 2016.
HABO
@HABO Dan dengan demikian tidak ada gunanya untuk pertanyaan tentang bagaimana melakukannya di SQL Server 2008 :-)
TylerH

Jawaban:

12
CREATE FUNCTION [dbo].[fn_split_string_to_column] (
    @string NVARCHAR(MAX),
    @delimiter CHAR(1)
    )
RETURNS @out_put TABLE (
    [column_id] INT IDENTITY(1, 1) NOT NULL,
    [value] NVARCHAR(MAX)
    )
AS
BEGIN
    DECLARE @value NVARCHAR(MAX),
        @pos INT = 0,
        @len INT = 0

    SET @string = CASE 
            WHEN RIGHT(@string, 1) != @delimiter
                THEN @string + @delimiter
            ELSE @string
            END

    WHILE CHARINDEX(@delimiter, @string, @pos + 1) > 0
    BEGIN
        SET @len = CHARINDEX(@delimiter, @string, @pos + 1) - @pos
        SET @value = SUBSTRING(@string, @pos, @len)

        INSERT INTO @out_put ([value])
        SELECT LTRIM(RTRIM(@value)) AS [column]

        SET @pos = CHARINDEX(@delimiter, @string, @pos + @len) + 1
    END

    RETURN
END
Blixter
sumber
3
Ini seharusnya bukan jawaban yang diterima ... TVF multi-statement (sangat buruk!) Dan WHILEloop (bahkan lebih buruk) bersama-sama akan berkinerja buruk. Selain itu, ini adalah jawaban hanya kode dan bahkan tidak menyelesaikan masalah Ada pendekatan yang jauh lebih baik di sekitar! Untuk pencarian SQL-Server 2016+ STRING_SPLIT()(yang tidak membawa posisi fragmen, gagal besar!) Atau JSON-hack yang sangat cepat . Untuk versi yang lebih lama, cari XML-hack yang terkenal (detail json dan xml di sini ). Atau cari salah satu dari iTVFs berdasarkan CTE rekursif.
Shnugo
SQL 2016 ke atas:SELECT * FROM STRING_SPLIT('John,Jeremy,Jack',',')
Alaa
Setuju dengan solusi yang diberikan. Namun, jika Anda adalah SQL Server 2016, Anda dapat menggunakan fungsi string_split .. Anda juga dapat menemukan penggunaan fungsi bawaan ini di sini tecloger.com/string-split-function-in-sql-server
Khatri
4
Semua orang menyarankan STRING_SPLIT, bagaimana fungsi ini dapat membagi string menjadi kolom (bukan baris seperti yang dimaksudkan)?
geominded
132

Tujuan Anda dapat diselesaikan menggunakan kueri berikut -

Select Value  , Substring(FullName, 1,Charindex(',', FullName)-1) as Name,
Substring(FullName, Charindex(',', FullName)+1, LEN(FullName)) as  Surname
from Table1

Tidak ada fungsi Split readymade di sql server, jadi kita perlu membuat fungsi yang ditentukan pengguna.

CREATE FUNCTION Split (
      @InputString                  VARCHAR(8000),
      @Delimiter                    VARCHAR(50)
)

RETURNS @Items TABLE (
      Item                          VARCHAR(8000)
)

AS
BEGIN
      IF @Delimiter = ' '
      BEGIN
            SET @Delimiter = ','
            SET @InputString = REPLACE(@InputString, ' ', @Delimiter)
      END

      IF (@Delimiter IS NULL OR @Delimiter = '')
            SET @Delimiter = ','

--INSERT INTO @Items VALUES (@Delimiter) -- Diagnostic
--INSERT INTO @Items VALUES (@InputString) -- Diagnostic

      DECLARE @Item           VARCHAR(8000)
      DECLARE @ItemList       VARCHAR(8000)
      DECLARE @DelimIndex     INT

      SET @ItemList = @InputString
      SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
      WHILE (@DelimIndex != 0)
      BEGIN
            SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex)
            INSERT INTO @Items VALUES (@Item)

            -- Set @ItemList = @ItemList minus one less item
            SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+1, LEN(@ItemList)-@DelimIndex)
            SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
      END -- End WHILE

      IF @Item IS NOT NULL -- At least one delimiter was encountered in @InputString
      BEGIN
            SET @Item = @ItemList
            INSERT INTO @Items VALUES (@Item)
      END

      -- No delimiters were encountered in @InputString, so just return @InputString
      ELSE INSERT INTO @Items VALUES (@InputString)

      RETURN

END -- End Function
GO

---- Set Permissions
--GRANT SELECT ON Split TO UserRole1
--GRANT SELECT ON Split TO UserRole2
--GO
Romil Kumar Jain
sumber
1
Lihatlah solusi tabel angka DelimitedSplit8K oleh Jeff Moden dalam jawaban @ughai di bawah ini juga.
Ruskin
2
SQL 2016 sekarang hadir dengan fungsi split
tvanharp
SQL 2016 ke atas:SELECT * FROM STRING_SPLIT('John,Jeremy,Jack',',')
Alaa
54
;WITH Split_Names (Value,Name, xmlname)
AS
(
    SELECT Value,
    Name,
    CONVERT(XML,'<Names><name>'  
    + REPLACE(Name,',', '</name><name>') + '</name></Names>') AS xmlname
      FROM tblnames
)

 SELECT Value,      
 xmlname.value('/Names[1]/name[1]','varchar(100)') AS Name,    
 xmlname.value('/Names[1]/name[2]','varchar(100)') AS Surname
 FROM Split_Names

dan juga periksa tautan di bawah untuk referensi

http://jahaines.blogspot.in/2009/06/converting-delimited-string-of-values.html

bvr
sumber
4
Ini lebih baik .. sederhana dan pendek.
Kimchi Man
4
Saya sangat suka cara ini. CHARINDEX dan SUBSTRING berantakan jika Anda memiliki lebih dari 2 nilai untuk dibagi (Misalnya 1,2,3). Terima kasih banyak
jotapdiez
2
Ide yang hebat. Tiga kali lebih lambat dari kekacauan CHARINDEXplus SUBSTRING, setidaknya untuk saya. :-(
Michel de Ruiter
5
Solusi hebat namun beberapa karakter ilegal dalam XML (misalnya '&') jadi saya harus membungkus setiap bidang dalam tag CDATA ...CONVERT(XML,'<Names><name><![CDATA[' + REPLACE(Name,',', ']]></name><name><![CDATA[') + ']]></name></name>') AS xmlname
Tony
2
@Tony perlu memperbarui kode dari Tony ke CONVERT(XML,'<Names><name><![CDATA[' + REPLACE(address1,',', ']]></name><name><![CDATA[') + ']]></name></Names>') AS xmlname(Missing the final s on </Names>)
Ryan Buddicom
46

jawaban dasar xml sederhana dan bersih

lihat ini

DECLARE @S varchar(max),
        @Split char(1),
        @X xml

SELECT @S = 'ab,cd,ef,gh,ij',
       @Split = ','

SELECT @X = CONVERT(xml,' <root> <myvalue>' +
REPLACE(@S,@Split,'</myvalue> <myvalue>') + '</myvalue>   </root> ')

SELECT  T.c.value('.','varchar(20)'),              --retrieve ALL values at once
  T.c.value('(/root/myvalue)[1]','VARCHAR(20)')  , --retrieve index 1 only, which is the 'ab'
  T.c.value('(/root/myvalue)[2]','VARCHAR(20)')
 FROM @X.nodes('/root/myvalue') T(c)
aads
sumber
2
Ini sangat keren. Fitur seperti array sangat berguna dan saya tidak tahu. Terima kasih!
Vnge
34

Saya pikir ini keren

SELECT value,
    PARSENAME(REPLACE(String,',','.'),2) 'Name' ,
    PARSENAME(REPLACE(String,',','.'),1) 'Sur Name'
FROM table WITH (NOLOCK)
Azar
sumber
3
Persyaratan Anda hanya untuk nama dan nama keluarga saja na
Azar
1
Anda juga perlu menyadari bahwa PARSENAME akan mengembalikan NULL untuk item yang lebih panjang dari 128 karakter.
Luis Cazares
Bagus. Berfungsi dengan baik untuk dataset saya juga!
glass_kites
30

Dengan CROSS APPLY

select ParsedData.* 
from MyTable mt
cross apply ( select str = mt.String + ',,' ) f1
cross apply ( select p1 = charindex( ',', str ) ) ap1
cross apply ( select p2 = charindex( ',', str, p1 + 1 ) ) ap2
cross apply ( select Nmame = substring( str, 1, p1-1 )                   
                 , Surname = substring( str, p1+1, p2-p1-1 )
          ) ParsedData
Lavisa
sumber
5
Saya tidak bisa menjelaskan mengapa Anda perlu menambahkan 2 koma di akhir string asli agar ini berfungsi. Mengapa tidak berhasil tanpa tanda "+ ',,'"?
tomat
@ developer.ejay apakah karena fungsi Left / SubString tidak dapat mengambil nilai 0?
Waller
Bagus! Anda dapat dengan mudah menyalin / menempelkan 2 baris untuk setiap kolom tambahan yang Anda inginkan - lalu tambahkan saja angkanya misalnya: pilih ParsedData. * Dari MyTable mt cross apply (pilih str = mt.String + ',,') f1 cross apply (pilih p1 = charindex (',', str)) ap1 cross apply (pilih p2 = charindex (',', str, p1 + 1)) ap2 cross apply (pilih p3 = charindex (',', str, p2 + 1)) ap3 lintas berlaku (pilih FName = substring (str, 1, p1-1), LName = substring (str, p1 + 1, p2-p1-1), Age = substring (str, p2 + 1, p3-p2-1 )) ParsedData
Mike
23

Ada banyak cara untuk menyelesaikan ini dan banyak cara berbeda telah diusulkan. Paling sederhana adalah dengan menggunakan LEFT/ SUBSTRINGdan fungsi string lainnya untuk mencapai hasil yang diinginkan.

Contoh data

DECLARE @tbl1 TABLE (Value INT,String VARCHAR(MAX))

INSERT INTO @tbl1 VALUES(1,'Cleo, Smith');
INSERT INTO @tbl1 VALUES(2,'John, Mathew');

Menggunakan Fungsi String seperti LEFT

SELECT
    Value,
    LEFT(String,CHARINDEX(',',String)-1) as Fname,
    LTRIM(RIGHT(String,LEN(String) - CHARINDEX(',',String) )) AS Lname
FROM @tbl1

Pendekatan ini gagal jika ada lebih dari 2 item dalam sebuah String. Dalam skenario seperti itu, kita dapat menggunakan pemisah dan kemudian menggunakan PIVOTatau mengubah string menjadi XMLdan digunakan .nodesuntuk mendapatkan item string. XMLsolusi berbasis telah dirinci oleh aads dan bvr dalam solusi mereka.

Jawaban untuk pertanyaan ini yang menggunakan splitter, semua penggunaan WHILEyang tidak efisien untuk pemisahan. Periksa perbandingan kinerja ini . Salah satu splitter terbaik adalah DelimitedSplit8K, dibuat oleh Jeff Moden. Anda dapat membaca lebih lanjut di sini

Splitter dengan PIVOT

DECLARE @tbl1 TABLE (Value INT,String VARCHAR(MAX))

INSERT INTO @tbl1 VALUES(1,'Cleo, Smith');
INSERT INTO @tbl1 VALUES(2,'John, Mathew');


SELECT t3.Value,[1] as Fname,[2] as Lname
FROM @tbl1 as t1
CROSS APPLY [dbo].[DelimitedSplit8K](String,',') as t2
PIVOT(MAX(Item) FOR ItemNumber IN ([1],[2])) as t3

Keluaran

Value   Fname   Lname
1   Cleo    Smith
2   John    Mathew

DelimitedSplit8K oleh Jeff Moden

CREATE FUNCTION [dbo].[DelimitedSplit8K]
/**********************************************************************************************************************
 Purpose:
 Split a given string at a given delimiter and return a list of the split elements (items).

 Notes:
 1.  Leading a trailing delimiters are treated as if an empty string element were present.
 2.  Consecutive delimiters are treated as if an empty string element were present between them.
 3.  Except when spaces are used as a delimiter, all spaces present in each element are preserved.

 Returns:
 iTVF containing the following:
 ItemNumber = Element position of Item as a BIGINT (not converted to INT to eliminate a CAST)
 Item       = Element value as a VARCHAR(8000)

 Statistics on this function may be found at the following URL:
 http://www.sqlservercentral.com/Forums/Topic1101315-203-4.aspx

 CROSS APPLY Usage Examples and Tests:
--=====================================================================================================================
-- TEST 1:
-- This tests for various possible conditions in a string using a comma as the delimiter.  The expected results are
-- laid out in the comments
--=====================================================================================================================
--===== Conditionally drop the test tables to make reruns easier for testing.
     -- (this is NOT a part of the solution)
     IF OBJECT_ID('tempdb..#JBMTest') IS NOT NULL DROP TABLE #JBMTest
;
--===== Create and populate a test table on the fly (this is NOT a part of the solution).
     -- In the following comments, "b" is a blank and "E" is an element in the left to right order.
     -- Double Quotes are used to encapsulate the output of "Item" so that you can see that all blanks
     -- are preserved no matter where they may appear.
 SELECT *
   INTO #JBMTest
   FROM (                                               --# & type of Return Row(s)
         SELECT  0, NULL                      UNION ALL --1 NULL
         SELECT  1, SPACE(0)                  UNION ALL --1 b (Empty String)
         SELECT  2, SPACE(1)                  UNION ALL --1 b (1 space)
         SELECT  3, SPACE(5)                  UNION ALL --1 b (5 spaces)
         SELECT  4, ','                       UNION ALL --2 b b (both are empty strings)
         SELECT  5, '55555'                   UNION ALL --1 E
         SELECT  6, ',55555'                  UNION ALL --2 b E
         SELECT  7, ',55555,'                 UNION ALL --3 b E b
         SELECT  8, '55555,'                  UNION ALL --2 b B
         SELECT  9, '55555,1'                 UNION ALL --2 E E
         SELECT 10, '1,55555'                 UNION ALL --2 E E
         SELECT 11, '55555,4444,333,22,1'     UNION ALL --5 E E E E E 
         SELECT 12, '55555,4444,,333,22,1'    UNION ALL --6 E E b E E E
         SELECT 13, ',55555,4444,,333,22,1,'  UNION ALL --8 b E E b E E E b
         SELECT 14, ',55555,4444,,,333,22,1,' UNION ALL --9 b E E b b E E E b
         SELECT 15, ' 4444,55555 '            UNION ALL --2 E (w/Leading Space) E (w/Trailing Space)
         SELECT 16, 'This,is,a,test.'                   --E E E E
        ) d (SomeID, SomeValue)
;
--===== Split the CSV column for the whole table using CROSS APPLY (this is the solution)
 SELECT test.SomeID, test.SomeValue, split.ItemNumber, Item = QUOTENAME(split.Item,'"')
   FROM #JBMTest test
  CROSS APPLY dbo.DelimitedSplit8K(test.SomeValue,',') split
;
--=====================================================================================================================
-- TEST 2:
-- This tests for various "alpha" splits and COLLATION using all ASCII characters from 0 to 255 as a delimiter against
-- a given string.  Note that not all of the delimiters will be visible and some will show up as tiny squares because
-- they are "control" characters.  More specifically, this test will show you what happens to various non-accented 
-- letters for your given collation depending on the delimiter you chose.
--=====================================================================================================================
WITH 
cteBuildAllCharacters (String,Delimiter) AS 
(
 SELECT TOP 256 
        'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
        CHAR(ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1)
   FROM master.sys.all_columns
)
 SELECT ASCII_Value = ASCII(c.Delimiter), c.Delimiter, split.ItemNumber, Item = QUOTENAME(split.Item,'"')
   FROM cteBuildAllCharacters c
  CROSS APPLY dbo.DelimitedSplit8K(c.String,c.Delimiter) split
  ORDER BY ASCII_Value, split.ItemNumber
;
-----------------------------------------------------------------------------------------------------------------------
 Other Notes:
 1. Optimized for VARCHAR(8000) or less.  No testing or error reporting for truncation at 8000 characters is done.
 2. Optimized for single character delimiter.  Multi-character delimiters should be resolvedexternally from this 
    function.
 3. Optimized for use with CROSS APPLY.
 4. Does not "trim" elements just in case leading or trailing blanks are intended.
 5. If you don't know how a Tally table can be used to replace loops, please see the following...
    http://www.sqlservercentral.com/articles/T-SQL/62867/
 6. Changing this function to use NVARCHAR(MAX) will cause it to run twice as slow.  It's just the nature of 
    VARCHAR(MAX) whether it fits in-row or not.
 7. Multi-machine testing for the method of using UNPIVOT instead of 10 SELECT/UNION ALLs shows that the UNPIVOT method
    is quite machine dependent and can slow things down quite a bit.
-----------------------------------------------------------------------------------------------------------------------
 Credits:
 This code is the product of many people's efforts including but not limited to the following:
 cteTally concept originally by Iztek Ben Gan and "decimalized" by Lynn Pettis (and others) for a bit of extra speed
 and finally redacted by Jeff Moden for a different slant on readability and compactness. Hat's off to Paul White for
 his simple explanations of CROSS APPLY and for his detailed testing efforts. Last but not least, thanks to
 Ron "BitBucket" McCullough and Wayne Sheffield for their extreme performance testing across multiple machines and
 versions of SQL Server.  The latest improvement brought an additional 15-20% improvement over Rev 05.  Special thanks
 to "Nadrek" and "peter-757102" (aka Peter de Heer) for bringing such improvements to light.  Nadrek's original
 improvement brought about a 10% performance gain and Peter followed that up with the content of Rev 07.  

 I also thank whoever wrote the first article I ever saw on "numbers tables" which is located at the following URL
 and to Adam Machanic for leading me to it many years ago.
 http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-numbers-table.html
-----------------------------------------------------------------------------------------------------------------------
 Revision History:
 Rev 00 - 20 Jan 2010 - Concept for inline cteTally: Lynn Pettis and others.
                        Redaction/Implementation: Jeff Moden 
        - Base 10 redaction and reduction for CTE.  (Total rewrite)

 Rev 01 - 13 Mar 2010 - Jeff Moden
        - Removed one additional concatenation and one subtraction from the SUBSTRING in the SELECT List for that tiny
          bit of extra speed.

 Rev 02 - 14 Apr 2010 - Jeff Moden
        - No code changes.  Added CROSS APPLY usage example to the header, some additional credits, and extra 
          documentation.

 Rev 03 - 18 Apr 2010 - Jeff Moden
        - No code changes.  Added notes 7, 8, and 9 about certain "optimizations" that don't actually work for this
          type of function.

 Rev 04 - 29 Jun 2010 - Jeff Moden
        - Added WITH SCHEMABINDING thanks to a note by Paul White.  This prevents an unnecessary "Table Spool" when the
          function is used in an UPDATE statement even though the function makes no external references.

 Rev 05 - 02 Apr 2011 - Jeff Moden
        - Rewritten for extreme performance improvement especially for larger strings approaching the 8K boundary and
          for strings that have wider elements.  The redaction of this code involved removing ALL concatenation of 
          delimiters, optimization of the maximum "N" value by using TOP instead of including it in the WHERE clause,
          and the reduction of all previous calculations (thanks to the switch to a "zero based" cteTally) to just one 
          instance of one add and one instance of a subtract. The length calculation for the final element (not 
          followed by a delimiter) in the string to be split has been greatly simplified by using the ISNULL/NULLIF 
          combination to determine when the CHARINDEX returned a 0 which indicates there are no more delimiters to be
          had or to start with. Depending on the width of the elements, this code is between 4 and 8 times faster on a
          single CPU box than the original code especially near the 8K boundary.
        - Modified comments to include more sanity checks on the usage example, etc.
        - Removed "other" notes 8 and 9 as they were no longer applicable.

 Rev 06 - 12 Apr 2011 - Jeff Moden
        - Based on a suggestion by Ron "Bitbucket" McCullough, additional test rows were added to the sample code and
          the code was changed to encapsulate the output in pipes so that spaces and empty strings could be perceived 
          in the output.  The first "Notes" section was added.  Finally, an extra test was added to the comments above.

 Rev 07 - 06 May 2011 - Peter de Heer, a further 15-20% performance enhancement has been discovered and incorporated 
          into this code which also eliminated the need for a "zero" position in the cteTally table. 
**********************************************************************************************************************/
--===== Define I/O parameters
        (@pString VARCHAR(8000), @pDelimiter CHAR(1))
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 0 up to 10,000...
     -- enough to cover NVARCHAR(4000)
  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
                ),                          --10E+1 or 10 rows
       E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
       E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
 cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
                     -- for both a performance gain and prevention of accidental "overruns"
                 SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
                ),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
                 SELECT 1 UNION ALL
                 SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
                ),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
                 SELECT s.N1,
                        ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
                   FROM cteStart s
                )
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
 SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
        Item       = SUBSTRING(@pString, l.N1, l.L1)
   FROM cteLen l
;

GO
ughai
sumber
15

Dengan SQL Server 2016 kita dapat menggunakan string_split untuk mencapai ini:

create table commasep (
 id int identity(1,1)
 ,string nvarchar(100) )

insert into commasep (string) values ('John, Adam'), ('test1,test2,test3')

select id, [value] as String from commasep 
 cross apply string_split(string,',')
Kannan Kandasamy
sumber
Saya menggunakan SQL Server 2016 tetapi memberikan kesalahanInvalid object name 'string_split'
ibiza
2
Bisakah Anda memeriksa tingkat kompatibilitas database Anda? Harus 130 yang merupakan sql server 2016. Anda dapat menggunakan kueri ini pilih * dari sys.databases
Kannan Kandasamy
benar, saya melihat 120 jadi pasti hanya klien (Microsoft SQL Server Management Studio) yang 2016 dan bukan server database itu sendiri karena jika saya pergi ke Bantuan -> Tentang, saya melihat SQL Server 2016 Management Studio v13.0.15000. 23. Terima kasih
ibiza
Bisa terjadi bahwa level disetel ke nilai yang lebih rendah oleh db devs untuk menjaga db kompatibel, bahkan jika versi aktual yang diinstal lebih tinggi. Gunakan ini untuk menyetel level setinggi yang diperlukan selama db mendukung ini:DECLARE @cl TINYINT; SELECT @cl = compatibility_level FROM [sys].[databases] WHERE name = 'mydb'; IF @cl < 130 BEGIN ALTER DATABASE myDb SET COMPATIBILITY_LEVEL = 130 END;
Joerg Krause
ini tidak berguna kecuali Anda memutarnya kembali dari baris ke kolom.
Guy Manova
15

Coba ini (ubah contoh '' menjadi ',' atau pembatas apa pun yang ingin Anda gunakan)

CREATE FUNCTION dbo.Wordparser
(
  @multiwordstring VARCHAR(255),
  @wordnumber      NUMERIC
)
returns VARCHAR(255)
AS
  BEGIN
      DECLARE @remainingstring VARCHAR(255)
      SET @remainingstring=@multiwordstring

      DECLARE @numberofwords NUMERIC
      SET @numberofwords=(LEN(@remainingstring) - LEN(REPLACE(@remainingstring, ' ', '')) + 1)

      DECLARE @word VARCHAR(50)
      DECLARE @parsedwords TABLE
      (
         line NUMERIC IDENTITY(1, 1),
         word VARCHAR(255)
      )

      WHILE @numberofwords > 1
        BEGIN
            SET @word=LEFT(@remainingstring, CHARINDEX(' ', @remainingstring) - 1)

            INSERT INTO @parsedwords(word)
            SELECT @word

            SET @remainingstring= REPLACE(@remainingstring, Concat(@word, ' '), '')
            SET @numberofwords=(LEN(@remainingstring) - LEN(REPLACE(@remainingstring, ' ', '')) + 1)

            IF @numberofwords = 1
              BREAK

            ELSE
              CONTINUE
        END

      IF @numberofwords = 1
        SELECT @word = @remainingstring
      INSERT INTO @parsedwords(word)
      SELECT @word

      RETURN
        (SELECT word
         FROM   @parsedwords
         WHERE  line = @wordnumber)

  END

Contoh penggunaan:

SELECT dbo.Wordparser(COLUMN, 1),
       dbo.Wordparser(COLUMN, 2),
       dbo.Wordparser(COLUMN, 3)
FROM   TABLE
pengguna7347410
sumber
Gagal bagi saya jika nilai identik di baris yang sama.
Pete Alvin
12

Saya pikir PARSENAME adalah fungsi rapi untuk digunakan untuk contoh ini, seperti yang dijelaskan dalam artikel ini: http://www.sqlshack.com/parsing-and-rotating-delimited-data-in-sql-server-2012/

Fungsi PARSENAME dirancang secara logis untuk mengurai nama objek empat bagian. Hal yang menyenangkan tentang PARSENAME adalah bahwa ini tidak terbatas pada parsing hanya nama objek empat bagian SQL Server - ini akan mengurai semua fungsi atau data string yang dibatasi oleh titik.

Parameter pertama adalah objek yang akan diurai, dan yang kedua adalah nilai integer dari potongan objek yang akan dikembalikan. Artikel ini membahas penguraian dan perputaran data yang dibatasi - nomor telepon perusahaan, tetapi juga dapat digunakan untuk mengurai data nama / nama keluarga.

Contoh:

USE COMPANY;
SELECT PARSENAME('Whatever.you.want.parsed',3) AS 'ReturnValue';

Artikel ini juga menjelaskan penggunaan Common Table Expression (CTE) yang disebut 'replaceChars', untuk menjalankan PARSENAME terhadap nilai yang diganti pembatas. CTE berguna untuk mengembalikan tampilan sementara atau kumpulan hasil.

Setelah itu, fungsi UNPIVOT telah digunakan untuk mengubah beberapa kolom menjadi baris; Fungsi SUBSTRING dan CHARINDEX telah digunakan untuk membersihkan ketidakkonsistenan dalam data, dan fungsi LAG (baru untuk SQL Server 2012) telah digunakan pada akhirnya, karena memungkinkan referensi catatan sebelumnya.

JasonP
sumber
12
SELECT id,
       Substring(NAME, 0, Charindex(',', NAME))             AS firstname,
       Substring(NAME, Charindex(',', NAME), Len(NAME) + 1) AS lastname
FROM   spilt  
anonim
sumber
6
Akan berguna jika Anda dapat memperluas jawaban Anda, dan menggunakan alat pemformatan kode juga.
Politank-Z
Tutup, ini akan menyertakan koma di nama belakang. Mendapat +1 di tempat yang salah. Harus Substring (NAME, Charindex (',', NAME) +1, Len (NAME)) AS lastname
LarryBud
10

Kita bisa membuat fungsi seperti ini

CREATE Function [dbo].[fn_CSVToTable] 
(
    @CSVList Varchar(max)
)
RETURNS @Table TABLE (ColumnData VARCHAR(100))
AS
BEGIN
    IF RIGHT(@CSVList, 1) <> ','
    SELECT @CSVList = @CSVList + ','

    DECLARE @Pos    BIGINT,
            @OldPos BIGINT
    SELECT  @Pos    = 1,
            @OldPos = 1

    WHILE   @Pos < LEN(@CSVList)
        BEGIN
            SELECT  @Pos = CHARINDEX(',', @CSVList, @OldPos)
            INSERT INTO @Table
            SELECT  LTRIM(RTRIM(SUBSTRING(@CSVList, @OldPos, @Pos - @OldPos))) Col001

            SELECT  @OldPos = @Pos + 1
        END

    RETURN
END

Kami kemudian dapat memisahkan nilai CSV ke dalam kolom masing-masing menggunakan pernyataan SELECT

Himansz
sumber
8

Saya pikir fungsi berikut akan bekerja untuk Anda:

Anda harus membuat fungsi di SQL terlebih dahulu. Seperti ini

CREATE FUNCTION [dbo].[fn_split](
@str VARCHAR(MAX),
@delimiter CHAR(1)
)
RETURNS @returnTable TABLE (idx INT PRIMARY KEY IDENTITY, item VARCHAR(8000))
AS
BEGIN
DECLARE @pos INT
SELECT @str = @str + @delimiter
WHILE LEN(@str) > 0 
    BEGIN
        SELECT @pos = CHARINDEX(@delimiter,@str)
        IF @pos = 1
            INSERT @returnTable (item)
                VALUES (NULL)
        ELSE
            INSERT @returnTable (item)
                VALUES (SUBSTRING(@str, 1, @pos-1))
        SELECT @str = SUBSTRING(@str, @pos+1, LEN(@str)-@pos)       
    END
RETURN
END

Anda dapat memanggil fungsi ini, seperti ini:

select * from fn_split('1,24,5',',')

Penerapan:

Declare @test TABLE (
ID VARCHAR(200),
Data VARCHAR(200)
)

insert into @test 
(ID, Data)
Values
('1','Cleo,Smith')


insert into @test 
(ID, Data)
Values
('2','Paul,Grim')

select ID,
(select item from fn_split(Data,',') where idx in (1)) as Name ,
(select item from fn_split(Data,',') where idx in (2)) as Surname
 from @test

Hasilnya akan seperti ini:

masukkan deskripsi gambar di sini

Muhammad Awais
sumber
Menggunakan loop untuk memisahkan string sangat tidak efisien. Berikut beberapa opsi yang lebih baik untuk fungsi pemisahan itu. sqlperformance.com/2012/07/t-sql-queries/split-strings
Sean Lange
7

Gunakan fungsi Parsename ()

with cte as(
    select 'Aria,Karimi' as FullName
    Union
    select 'Joe,Karimi' as FullName
    Union
    select 'Bab,Karimi' as FullName
)

SELECT PARSENAME(REPLACE(FullName,',','.'),2) as Name, 
       PARSENAME(REPLACE(FullName,',','.'),1) as Family
    FROM cte

Hasil

Name    Family
-----   ------
Aria    Karimi
Bab     Karimi
Joe     Karimi
Mohammad Karimi
sumber
7

Anda dapat menggunakan file fungsi nilai tabelSTRING_SPLIT , yang hanya tersedia di bawah tingkat kompatibilitas 130. Jika tingkat kompatibilitas database Anda lebih rendah dari 130, SQL Server tidak akan dapat menemukan dan menjalankan STRING_SPLITfungsi tersebut. Anda dapat mengubah tingkat kompatibilitas database menggunakan perintah berikut:

ALTER DATABASE DatabaseName SET COMPATIBILITY_LEVEL = 130

Sintaksis

SELECT * FROM STRING_SPLIT ( string, separator )

lihat dokumentasi di sini

bwanamaina
sumber
Bagus. Tapi itu tidak berlaku untuk SQL Server kurang dari 2016
Lokesh
Benar, dalam jawaban saya, saya menunjukkan bahwa itu hanya akan tersedia di tingkat kompatibilitas 130 dan yang lebih baru.
bwanamaina
3
Tetapi STRING_SPLIT dibagi menjadi beberapa baris, bukan beberapa kolom untuk setiap pemisahan. OP bertanya tentang membagi menjadi beberapa kolom kan?
geominded
6

Coba ini:

declare @csv varchar(100) ='aaa,bb,csda,daass';
set @csv = @csv+',';

with cte as
(
    select SUBSTRING(@csv,1,charindex(',',@csv,1)-1) as val, SUBSTRING(@csv,charindex(',',@csv,1)+1,len(@csv)) as rem 
    UNION ALL
    select SUBSTRING(a.rem,1,charindex(',',a.rem,1)-1)as val, SUBSTRING(a.rem,charindex(',',a.rem,1)+1,len(A.rem)) 
    from cte a where LEN(a.rem)>=1
    ) select val from cte
Rangani
sumber
Bekerja seperti pesona!
yu yang Jian
6

Fungsi ini paling cepat:

CREATE FUNCTION dbo.F_ExtractSubString
(
  @String VARCHAR(MAX),
  @NroSubString INT,
  @Separator VARCHAR(5)
)
RETURNS VARCHAR(MAX) AS
BEGIN
    DECLARE @St INT = 0, @End INT = 0, @Ret VARCHAR(MAX)
    SET @String = @String + @Separator
    WHILE CHARINDEX(@Separator, @String, @End + 1) > 0 AND @NroSubString > 0
    BEGIN
        SET @St = @End + 1
        SET @End = CHARINDEX(@Separator, @String, @End + 1)
        SET @NroSubString = @NroSubString - 1
    END
    IF @NroSubString > 0
        SET @Ret = ''
    ELSE
        SET @Ret = SUBSTRING(@String, @St, @End - @St)
    RETURN @Ret
END
GO

Contoh penggunaan:

SELECT dbo.F_ExtractSubString(COLUMN, 1, ', '),
       dbo.F_ExtractSubString(COLUMN, 2, ', '),
       dbo.F_ExtractSubString(COLUMN, 3, ', ')
FROM   TABLE
Mariano Sedano
sumber
3
Terima kasih atas cuplikan kode ini, yang mungkin memberikan bantuan terbatas dan langsung. Penjelasan yang tepat akan sangat meningkatkan nilai jangka panjangnya dengan menunjukkan mengapa ini adalah solusi yang baik untuk masalah tersebut, dan akan membuatnya lebih berguna bagi pembaca di masa mendatang dengan pertanyaan serupa lainnya. Mohon edit jawaban Anda untuk menambahkan penjelasan, termasuk asumsi yang Anda buat.
Toby Speight
5

Saya mengalami masalah yang serupa tetapi yang rumit dan karena ini adalah utas pertama yang saya temukan mengenai masalah itu, saya memutuskan untuk memposting temuan saya. Saya tahu ini adalah solusi kompleks untuk masalah sederhana tetapi saya berharap dapat membantu orang lain yang membuka utas ini untuk mencari solusi yang lebih kompleks. saya harus membagi string yang berisi 5 nomor (nama kolom: levelFeed) dan untuk menampilkan setiap nomor di kolom terpisah. Misalnya: 8,1,2,2,2 harus ditampilkan sebagai:

1  2  3  4  5
-------------
8  1  2  2  2

Solusi 1: Menggunakan Fungsi XML: Solusi ini untuk solusi paling lambat sejauh ini

SELECT Distinct FeedbackID, 
, S.a.value('(/H/r)[1]', 'INT') AS level1
, S.a.value('(/H/r)[2]', 'INT') AS level2
, S.a.value('(/H/r)[3]', 'INT') AS level3
, S.a.value('(/H/r)[4]', 'INT') AS level4
, S.a.value('(/H/r)[5]', 'INT') AS level5
FROM (            
    SELECT *,CAST (N'<H><r>' + REPLACE(levelsFeed, ',', '</r><r>')  + '</r> </H>' AS XML) AS [vals]
    FROM Feedbacks 
)  as d
CROSS APPLY d.[vals].nodes('/H/r') S(a)

Solusi 2: Menggunakan fungsi Split dan poros. (fungsi pemisahan memisahkan string menjadi baris dengan data nama kolom)

SELECT FeedbackID, [1],[2],[3],[4],[5]
FROM (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY feedbackID ORDER BY (SELECT  null)) as rn 
FROM (
    SELECT FeedbackID, levelsFeed
    FROM Feedbacks 
) as a
CROSS APPLY dbo.Split(levelsFeed, ',')
) as SourceTable
PIVOT
(
    MAX(data)
    FOR rn IN ([1],[2],[3],[4],[5])
)as pivotTable

Solusi 3: Menggunakan fungsi manipulasi string - tercepat dengan margin kecil di atas solusi 2

SELECT FeedbackID,
SUBSTRING(levelsFeed,0,CHARINDEX(',',levelsFeed)) AS level1,
PARSENAME(REPLACE(SUBSTRING(levelsFeed,CHARINDEX(',',levelsFeed)+1,LEN(levelsFeed)),',','.'),4) AS level2,
PARSENAME(REPLACE(SUBSTRING(levelsFeed,CHARINDEX(',',levelsFeed)+1,LEN(levelsFeed)),',','.'),3) AS level3,
PARSENAME(REPLACE(SUBSTRING(levelsFeed,CHARINDEX(',',levelsFeed)+1,LEN(levelsFeed)),',','.'),2) AS level4,
PARSENAME(REPLACE(SUBSTRING(levelsFeed,CHARINDEX(',',levelsFeed)+1,LEN(levelsFeed)),',','.'),1) AS level5
FROM Feedbacks

karena levelFeed berisi 5 nilai string yang saya butuhkan untuk menggunakan fungsi substring untuk string pertama.

Saya berharap solusi saya akan membantu orang lain yang sampai ke utas ini mencari metode perpecahan ke kolom yang lebih kompleks

Yossi
sumber
5

Menggunakan fungsi instring :)

select Value, 
       substring(String,1,instr(String," ") -1) Fname,  
       substring(String,instr(String,",") +1) Sname 
from tablename;

Menggunakan dua fungsi,
1. substring(string, position, length) ==> mengembalikan string dari posisi ke panjang
2.instr(string,pattern) ==> mengembalikan posisi pola.

Jika kami tidak memberikan argumen panjang dalam substring, ia mengembalikan hingga akhir string

WoodChopper
sumber
1
Tidak yakin dialek SQL apa yang Anda gunakan, tetapi di SQL Server kami harus menggunakan sesuatu seperti substring(@str, 1, charindex(@sep, @str) - 1)diikuti oleh substring(@str, charindex(@sep, @str) + 1, len(@str)).
Peter B
4

Ini berhasil untuk saya

CREATE FUNCTION [dbo].[SplitString](
    @delimited NVARCHAR(MAX),
    @delimiter NVARCHAR(100)
) RETURNS @t TABLE ( 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
Krishna
sumber
apakah Anda tahu cara menangani karakter khusus xml?
Zach Smith
3

mytable:

Value  ColOne
--------------------
1      Cleo, Smith

Berikut ini akan bekerja jika tidak terlalu banyak kolom

ALTER TABLE mytable ADD ColTwo nvarchar(256);
UPDATE mytable SET ColTwo = LEFT(ColOne, Charindex(',', ColOne) - 1);
--'Cleo' = LEFT('Cleo, Smith', Charindex(',', 'Cleo, Smith') - 1)
UPDATE mytable SET ColTwo = REPLACE(ColOne, ColTwo + ',', '');
--' Smith' = REPLACE('Cleo, Smith', 'Cleo' + ',')
UPDATE mytable SET ColOne = REPLACE(ColOne, ',' + ColTwo, ''), ColTwo = LTRIM(ColTwo);
--'Cleo' = REPLACE('Cleo, Smith', ',' + ' Smith', '') 

Hasil:

Value  ColOne ColTwo
--------------------
1      Cleo   Smith
kolunar
sumber
3

sangat mudah, Anda bisa menerimanya dengan query di bawah ini:

DECLARE @str NVARCHAR(MAX)='ControlID_05436b78-04ba-9667-fa01-9ff8c1b7c235,3'
SELECT LEFT(@str, CHARINDEX(',',@str)-1),RIGHT(@str,LEN(@str)-(CHARINDEX(',',@str)))
Mehdi najafian
sumber
3
DECLARE @INPUT VARCHAR (MAX)='N,A,R,E,N,D,R,A'
DECLARE @ELIMINATE_CHAR CHAR (1)=','
DECLARE @L_START INT=1
DECLARE @L_END INT=(SELECT LEN (@INPUT))
DECLARE @OUTPUT CHAR (1)

WHILE @L_START <=@L_END
BEGIN
    SET @OUTPUT=(SUBSTRING (@INPUT,@L_START,1))
    IF @OUTPUT!=@ELIMINATE_CHAR
    BEGIN
        PRINT @OUTPUT
    END
    SET @L_START=@L_START+1
END
Narendra gudapati
sumber
Saya menggunakan kode Anda, sederhana tetapi ada kesalahan ejaan dalam ELIMINATE_CHAT seharusnya ELIMINATE_CHAR dan MULAI DI akhir skrip harus L_START. Terima kasih.
Wessam El Mahdy
3

Anda mungkin menemukan solusi dalam SQL User Defined Function untuk Parse Delimited String bermanfaat (dari The Code Project ).

Ini adalah bagian kode dari halaman ini:

CREATE FUNCTION [fn_ParseText2Table]
  (@p_SourceText VARCHAR(MAX)
  ,@p_Delimeter VARCHAR(100)=',' --default to comma delimited.
  )
 RETURNS @retTable
  TABLE([Position] INT IDENTITY(1,1)
   ,[Int_Value] INT
   ,[Num_Value] NUMERIC(18,3)
   ,[Txt_Value] VARCHAR(MAX)
   ,[Date_value] DATETIME
   )
AS
/*
********************************************************************************
Purpose: Parse values from a delimited string
  & return the result as an indexed table
Copyright 1996, 1997, 2000, 2003 Clayton Groom (<A href="mailto:[email protected]">[email protected]</A>)
Posted to the public domain Aug, 2004
2003-06-17 Rewritten as SQL 2000 function.
 Reworked to allow for delimiters > 1 character in length
 and to convert Text values to numbers
2016-04-05 Added logic for date values based on "new" ISDATE() function, Updated to use XML approach, which is more efficient.
********************************************************************************
*/


BEGIN
 DECLARE @w_xml xml;
 SET @w_xml = N'<root><i>' + replace(@p_SourceText, @p_Delimeter,'</i><i>') + '</i></root>';


 INSERT INTO @retTable
     ([Int_Value]
    , [Num_Value]
    , [Txt_Value]
    , [Date_value]
     )
     SELECT CASE
       WHEN ISNUMERIC([i].value('.', 'VARCHAR(MAX)')) = 1
       THEN CAST(CAST([i].value('.', 'VARCHAR(MAX)') AS NUMERIC) AS INT)
      END AS [Int_Value]
    , CASE
       WHEN ISNUMERIC([i].value('.', 'VARCHAR(MAX)')) = 1
       THEN CAST([i].value('.', 'VARCHAR(MAX)') AS NUMERIC(18, 3))
      END AS [Num_Value]
    , [i].value('.', 'VARCHAR(MAX)') AS [txt_Value]
    , CASE
       WHEN ISDATE([i].value('.', 'VARCHAR(MAX)')) = 1
       THEN CAST([i].value('.', 'VARCHAR(MAX)') AS DATETIME)
      END AS [Num_Value]
     FROM @w_xml.nodes('//root/i') AS [Items]([i]);
 RETURN;
END;
GO
Michael Schnerring
sumber
11
Adakah kemungkinan Anda dapat meringkas solusi di sini untuk memastikan jawabannya tidak menjadi usang jika tautannya pernah mati?
Adam Lear
3
ALTER function get_occurance_index(@delimiter varchar(1),@occurence int,@String varchar(100))
returns int
AS Begin
--Declare @delimiter varchar(1)=',',@occurence int=2,@String varchar(100)='a,b,c'
Declare @result int
 ;with T as (
    select 1 Rno,0 as row, charindex(@delimiter, @String) pos,@String st
    union all
    select Rno+1,pos + 1, charindex(@delimiter, @String, pos + 1), @String
    from T
    where pos > 0
)
select  @result=pos 
from T 
where pos > 0   and rno = @occurence 
return isnull(@result,0)
ENd


declare @data as table (data varchar(100))
insert into @data values('1,2,3') 
insert into @data values('aaa,bbbbb,cccc') 
select top  3 Substring (data,0,dbo.get_occurance_index( ',',1,data)) ,--First Record always starts with 0
Substring (data,dbo.get_occurance_index( ',',1,data)+1,dbo.get_occurance_index( ',',2,data)-dbo.get_occurance_index( ',',1,data)-1) ,
Substring (data,dbo.get_occurance_index( ',',2,data)+1,len(data)) , -- Last record cant be more than len of actual data
data 
From @data 
vignesh
sumber
2

Saya menemukan bahwa menggunakan PARSENAME seperti di atas menyebabkan nama apapun dengan titik menjadi nulled.

Jadi jika ada inisial atau judul di nama diikuti dengan titik mereka mengembalikan NULL.

Saya menemukan ini berhasil untuk saya:

SELECT 
REPLACE(SUBSTRING(FullName, 1,CHARINDEX(',', FullName)), ',','') as Name,
REPLACE(SUBSTRING(FullName, CHARINDEX(',', FullName), LEN(FullName)), ',', '') as Surname
FROM Table1
RoadRunner
sumber
2
select distinct modelFileId,F4.*
from contract
cross apply (select XmlList=convert(xml, '<x>'+replace(modelFileId,';','</x><x>')+'</x>').query('.')) F2
cross apply (select mfid1=XmlNode.value('/x[1]','varchar(512)')
,mfid2=XmlNode.value('/x[2]','varchar(512)')
,mfid3=XmlNode.value('/x[3]','varchar(512)')
,mfid4=XmlNode.value('/x[4]','varchar(512)') from XmlList.nodes('x') F3(XmlNode)) F4
where modelFileId like '%;%'
order by modelFileId
jujur
sumber
2
Select distinct PROJ_UID,PROJ_NAME,RES_UID from E2E_ProjectWiseTimesheetActuals
where   CHARINDEX(','+cast(PROJ_UID as varchar(8000))+',', @params) > 0 and  CHARINDEX(','+cast(RES_UID as varchar(8000))+',', @res) > 0
pengguna7678586
sumber
4
Meskipun kode ini dapat menjawab pertanyaan, memberikan konteks tambahan tentang mengapa dan / atau bagaimana kode ini menjawab pertanyaan tersebut meningkatkan nilai jangka panjangnya.
Seret dan Jatuhkan
2

Saya menulis ulang jawaban di atas dan membuatnya lebih baik:

CREATE FUNCTION [dbo].[CSVParser]
(
  @s        VARCHAR(255),
  @idx      NUMERIC
)
RETURNS VARCHAR(12)
BEGIN
    DECLARE @comma int
    SET @comma = CHARINDEX(',', @s)
    WHILE 1=1
    BEGIN
        IF @comma=0
            IF @idx=1
                RETURN @s
            ELSE
                RETURN ''

        IF @idx=1
        BEGIN
            DECLARE @word VARCHAR(12)
            SET @word=LEFT(@s, @comma - 1)
            RETURN @word
        END

        SET @s = RIGHT(@s,LEN(@s)-@comma)
        SET @comma = CHARINDEX(',', @s)
        SET @idx = @idx - 1
    END
    RETURN 'not used'
END

Contoh penggunaan:

SELECT dbo.CSVParser(COLUMN, 1),
       dbo.CSVParser(COLUMN, 2),
       dbo.CSVParser(COLUMN, 3)
FROM   TABLE
Pete Alvin
sumber
2

pertanyaannya sederhana, tapi masalahnya panas :)

Jadi saya membuat beberapa pembungkus untuk string_split () yang menghasilkan pivot dengan cara yang lebih umum. Ini fungsi tabel yang mengembalikan nilai (nn, nilai1, nilai2, ..., nilai50) - cukup untuk sebagian besar baris CSV. Jika ada lebih banyak nilai, nilai tersebut akan digabungkan ke baris berikutnya - nn menunjukkan nomor baris. Setel parameter ketiga @columnCnt = [yourNumber] untuk dibungkus pada posisi tertentu:

alter FUNCTION fn_Split50
(   
    @str varchar(max),
    @delim char(1), 
    @columnCnt int = 50
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT * 
    FROM (SELECT 
            nn = (nn - 1) / @columnCnt + 1, 
            nnn = 'value' + cast(((nn - 1) % @columnCnt) + 1 as varchar(10)), 
            value
        FROM (SELECT 
            nn = ROW_NUMBER() over (order by (select null)),
            value
            FROM string_split(@str, @delim) aa
            ) aa
        where nn > 0
    ) bb
    PIVOT  
    (  
    max(value) 
    FOR nnn IN (    
        value1, value2, value3, value4, value5, value6, value7, value8, value9, value10,
        value11, value12, value13, value14, value15, value16, value17, value18, value19, value20,
        value21, value22, value23, value24, value25, value26, value27, value28, value29, value30,
        value31, value32, value33, value34, value35, value36, value37, value38, value39, value40,
        value41, value42, value43, value44, value45, value46, value47, value48, value49, value50        
     )  
    ) AS PivotTable 
)

Contoh penggunaan:

select * from dbo.fn_split50('zz1,aa2,ss3,dd4,ff5', ',', DEFAULT)

hasil 1

select * from dbo.fn_split50('zz1,aa2,ss3,dd4,ff5,gg6,hh7,jj8,ww9,qq10', ',', 3)

masukkan deskripsi gambar di sini

select * from dbo.fn_split50('zz1,11,aa2,22,ss3,33,dd4,44,ff5,55,gg6,66,hh7,77,jj8,88,ww9,99,qq10,1010', ',',2)

masukkan deskripsi gambar di sini

Semoga bisa membantu :)

parfilko.dll
sumber