টি-এসকিউএল সমান বিভাজন?


128

আমি '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ...' (কমা বিস্মৃত) একটি টেবিল বা টেবিলের ভেরিয়েবলে বিভক্ত করতে চাইছি ।

কারও কি এমন একটি ফাংশন রয়েছে যা প্রতিটি একের পর এক ফেরত দেয়?


http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=50648 বিভিন্ন পদ্ধতির একটি নির্বাচন
অ্যাডলফ রসুন

1
এরল্যান্ড সোমমারস্কোগ গত 12 বছর ধরে এই প্রশ্নের অনুমোদনযোগ্য উত্তর বজায় রেখেছেন: http://www.sommarskog.se/arrays-in-sql.html স্ট্যাকওভারফ্লোতে এখানে সমস্ত অপশন পুনরুত্পাদন করার জন্য উপযুক্ত নয়, কেবল তার পৃষ্ঠাটি দেখুন এবং আপনি যা জানতে চেয়েছিলেন তা আপনি শিখবেন।
পোর্টম্যান

2
আমি সম্প্রতি এই সমস্যাটির সর্বাধিক সাধারণ পদ্ধতির তুলনা করে একটি ছোট্ট অধ্যয়ন করেছি, এটি পড়ার মতো হতে পারে: sqlperformance.com/2012/07/t-sql-queries/split-strings এবং sqlperformance.com/2012/08/t- স্কয়ার-প্রশ্নগুলি /…
অ্যারন বার্ট্র্যান্ড


দেখে মনে হচ্ছে আপনি এখানে বেশ কয়েকটি ভাল উত্তর পেয়েছেন; তাদের মধ্যে কেন একটির উত্তর হিসাবে চিহ্নিত করবেন না বা যদি এখনও তার উত্তর না দেওয়া হয় তবে আপনার সমস্যাটিকে আরও বিশদে বর্ণনা করবেন না।
রায়ানফায়েস্কটল্যান্ড

উত্তর:


51

এখানে কিছুটা পুরানো ধরণের সমাধান:

/*
    Splits string into parts delimitered with specified character.
*/
CREATE FUNCTION [dbo].[SDF_SplitString]
(
    @sString nvarchar(2048),
    @cDelimiter nchar(1)
)
RETURNS @tParts TABLE ( part nvarchar(2048) )
AS
BEGIN
    if @sString is null return
    declare @iStart int,
            @iPos int
    if substring( @sString, 1, 1 ) = @cDelimiter 
    begin
        set @iStart = 2
        insert into @tParts
        values( null )
    end
    else 
        set @iStart = 1
    while 1=1
    begin
        set @iPos = charindex( @cDelimiter, @sString, @iStart )
        if @iPos = 0
            set @iPos = len( @sString )+1
        if @iPos - @iStart > 0          
            insert into @tParts
            values  ( substring( @sString, @iStart, @iPos-@iStart ))
        else
            insert into @tParts
            values( null )
        set @iStart = @iPos+1
        if @iStart > len( @sString ) 
            break
    end
    RETURN

END

এসকিউএল সার্ভার ২০০৮ এ আপনি .NET কোডের সাহায্যে একই অর্জন করতে পারেন। সম্ভবত এটি দ্রুত কাজ করবে, তবে অবশ্যই এই পদ্ধতিটি পরিচালনা করা সহজ।


ধন্যবাদ, আমি এটি জানতে চাই। এখানে কোন ত্রুটি আছে? আমি এই কোডটি সম্ভবত 6 বছর আগে লিখেছি এবং এটি ঠিক তখন থেকেই কার্যকর ছিল।
XOR

আমি রাজী. আপনি যখন টেবিলের ধরণের পরামিতি তৈরির সাথে জড়িত থাকতে চান না (বা সহজভাবে পারেন না) এটি খুব ভাল সমাধান হয়, যা আমার ক্ষেত্রে কেস হবে। ডিবিএ'র বৈশিষ্ট্যটি লক হয়ে গেছে এবং এটি অনুমতি দেবে না। ধন্যবাদ এক্সওর!
dscarr

DECLARE VarString NVARCHAR (2048) = 'মাইক / জন / মিকো / ম্যাট'; কারাকস্ট্রিং এনভিচারার (1) = '/' ঘোষণা করুন; Dbo.FnSplitString (VarString, CaracString) থেকে * নির্বাচন করুন
ফার্নান্দো ইয়েভেনেস

55

এটা চেষ্টা কর

DECLARE @xml xml, @str varchar(100), @delimiter varchar(10)
SET @str = '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15'
SET @delimiter = ','
SET @xml = cast(('<X>'+replace(@str, @delimiter, '</X><X>')+'</X>') as xml)
SELECT C.value('.', 'varchar(10)') as value FROM @xml.nodes('X') as X(C)

অথবা

DECLARE @str varchar(100), @delimiter varchar(10)
SET @str = '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15'
SET @delimiter = ','
;WITH cte AS
(
    SELECT 0 a, 1 b
    UNION ALL
    SELECT b, CHARINDEX(@delimiter, @str, b) + LEN(@delimiter)
    FROM CTE
    WHERE b > a
)
SELECT SUBSTRING(@str, a,
CASE WHEN b > LEN(@delimiter) 
    THEN b - a - LEN(@delimiter) 
    ELSE LEN(@str) - a + 1 END) value      
FROM cte WHERE a > 0

একই কাজ করার আরও অনেকগুলি উপায় এখানে কমা বিস্মৃত স্ট্রিংগুলিকে কীভাবে ভাগ করবেন?


9
সাধারণ স্ট্রিং স্প্লিটার অনুসন্ধানকারী যে কোনও ব্যক্তির জন্য নোট: এখানে প্রদত্ত প্রথম সমাধানটি কোনও সাধারণ স্ট্রিং স্প্লিটার নয় - এটি কেবল তখনই নিরাপদ যদি আপনি নিশ্চিত হন যে ইনপুটটি কখনই থাকবে না <, >বা &(যেমন ইনপুটটি পূর্ণসংখ্যার ক্রম)। উপরের তিনটি অক্ষরের যেকোনটি আপনাকে প্রত্যাশিত ফলাফলের পরিবর্তে পার্স ত্রুটি পেতে পারে।
মিরোক্লাভ

1
মিরোক্লাভ দ্বারা উল্লিখিত সমস্যাগুলির সাথে ইভেন্ট (যা কিছু চিন্তাভাবনার সাথে সমাধানযোগ্য হওয়া উচিত), এটি অবশ্যই খুঁজে পাওয়া সৃজনশীল সমাধানগুলির মধ্যে একটি (প্রথম)! খুব সুন্দর!
মেজর-মান্ন

লাইনটি SELECT b, CHARINDEX(@delimiter, @str, b) + LEN(@delimiter)আসলে হওয়া উচিত SELECT b, CHARINDEX(@delimiter, @str, b+1) + LEN(@delimiter)B + 1 একটি বড় পার্থক্য তোলে। এখানে সীমানা হিসাবে স্থানের সাথে পরীক্ষিত, এই ফিক্স ছাড়া কাজ করে না।
JwJosefy

@ এমিরক্স্লাভ এছাড়াও, আমার অভিজ্ঞতা অনুসারে, স্ট্রিংকে বিভক্ত করতে এক্সএমএল ব্যবহার করা একটি অত্যন্ত ব্যয়বহুল পথ।
আন্ডারস্কোর_ডি

দুর্দান্ত সমাধান! লক্ষণীয় যে ব্যবহারকারীরা 100 টিরও বেশি অংশ বিভক্ত করতে, MAXRECURSIONবিকল্পগুলি স্ট্যাকওভারফ্লো.com/q/2025585 থেকে স্থানগুলি হ্যান্ডেল করার জন্য প্রতিস্থাপন LENকরতে এবং ইনপুটগুলির জন্য সারিগুলি বাদ দিতে পারে । NULLNULL
কেভিনোয়েড

27

আপনি এই এসকিউএল সার্ভার ২০০৮-এ ট্যাগ করেছেন তবে ভবিষ্যতে এই প্রশ্নের ভবিষ্যতের দর্শক (এসকিউএল সার্ভার ২০১++ ব্যবহার করে) সম্ভবত এটি সম্পর্কে জানতে চাইবেন STRING_SPLIT

এই নতুন অন্তর্নির্মিত ফাংশনটির সাথে আপনি এখন কেবল ব্যবহার করতে পারেন

SELECT TRY_CAST(value AS INT)
FROM   STRING_SPLIT ('1,2,3,4,5,6,7,8,9,10,11,12,13,14,15', ',') 

এই ফাংশনটির কিছু সীমাবদ্ধতা এবং পারফরম্যান্স পরীক্ষার কিছু আশাব্যঞ্জক ফলাফল অ্যারন বারট্র্যান্ডের এই ব্লগ পোস্টে


13

এটি আপনার কাছে যারা সেই ফাংশনের সাথে পরিচিত তাদের জন্য নেট নেট এর মতো:

CREATE FUNCTION dbo.[String.Split]
(
    @Text VARCHAR(MAX),
    @Delimiter VARCHAR(100),
    @Index INT
)
RETURNS VARCHAR(MAX)
AS BEGIN
    DECLARE @A TABLE (ID INT IDENTITY, V VARCHAR(MAX));
    DECLARE @R VARCHAR(MAX);
    WITH CTE AS
    (
    SELECT 0 A, 1 B
    UNION ALL
    SELECT B, CONVERT(INT,CHARINDEX(@Delimiter, @Text, B) + LEN(@Delimiter))
    FROM CTE
    WHERE B > A
    )
    INSERT @A(V)
    SELECT SUBSTRING(@Text,A,CASE WHEN B > LEN(@Delimiter) THEN B-A-LEN(@Delimiter) ELSE LEN(@Text) - A + 1 END) VALUE      
    FROM CTE WHERE A >0

    SELECT      @R
    =           V
    FROM        @A
    WHERE       ID = @Index + 1
    RETURN      @R
END

SELECT dbo.[String.Split]('121,2,3,0',',',1) -- gives '2'

9

এখানে বিভক্ত ফাংশন যা আপনি জিজ্ঞাসা করেছেন

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

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

এইভাবে ফাংশন চালানো

select * from dbo.split('1,2,3,4,5,6,7,8,9,10,11,12,13,14,15',',')

5
DECLARE
    @InputString NVARCHAR(MAX) = 'token1,token2,token3,token4,token5'
    , @delimiter varchar(10) = ','

DECLARE @xml AS XML = CAST(('<X>'+REPLACE(@InputString,@delimiter ,'</X><X>')+'</X>') AS XML)
SELECT C.value('.', 'varchar(10)') AS value
FROM @xml.nodes('X') as X(C)

এই প্রতিক্রিয়াটির উত্স: http://sqlhint.com/sqlserver/how-to/best-split-function-tsql-dilimited


যতক্ষণ এই তাত্ত্বিক প্রশ্নের উত্তর হতে পারে, এটা বাঞ্ছনীয় হবে উত্তর অপরিহার্য অংশের এখানে অন্তর্ভুক্ত করা, এবং রেফারেন্স এর জন্য লিঙ্ক প্রদান।
জাভি লোপেজ

1
@ জাভি: ঠিক আছে, আমি উত্তরের প্রয়োজনীয় অংশগুলি অন্তর্ভুক্ত করেছি। আপনার ইঙ্গিত জন্য ধন্যবাদ।
মিহাই বেজনারিউ

3

আমি আমার প্রিয় দ্রবণটি চেপে ধরতে প্রলোভিত হই। ফলস্বরূপ সারণীতে 2 টি কলাম থাকবে: প্রাপ্ত পূর্ণসংখ্যার অবস্থানের জন্য পজ আইডিএক্স; এবং পূর্ণসংখ্যার মান।


create function FnSplitToTableInt
(
    @param nvarchar(4000)
)
returns table as
return
    with Numbers(Number) as 
    (
        select 1 
        union all 
        select Number + 1 from Numbers where Number < 4000
    ),
    Found as
    (
        select 
            Number as PosIdx,
            convert(int, ltrim(rtrim(convert(nvarchar(4000), 
                substring(@param, Number, 
                charindex(N',' collate Latin1_General_BIN, 
                @param + N',', Number) - Number))))) as Value
        from   
            Numbers 
        where  
            Number <= len(@param)
        and substring(N',' + @param, Number, 1) = N',' collate Latin1_General_BIN
    )
    select 
        PosIdx, 
        case when isnumeric(Value) = 1 
            then convert(int, Value) 
            else convert(int, null) end as Value 
    from 
        Found

এটি ডিফল্টরূপে 1 থেকে 100 পর্যন্ত পজিশনের তালিকা হিসাবে পুনরাবৃত্ত সিটিই ব্যবহার করে কাজ করে। যদি আপনার 100 টিরও বেশি দীর্ঘ স্ট্রিংয়ের সাথে কাজ করা দরকার হয় তবে নিম্নলিখিত বিকল্পগুলির মতো 'বিকল্প (ম্যাক্সক্রেকশন 4000)' ব্যবহার করে এই ফাংশনটি কল করুন:


select * from FnSplitToTableInt
(
    '9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ' + 
    '9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ' +
    '9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ' +
    '9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ' +
    '9, 8, 7, 6, 5, 4, 3, 2, 1, 0'
) 
option (maxrecursion 4000)

2
ম্যাক্সক্র্যাকশন বিকল্প উল্লেখ করার জন্য +1 স্পষ্টত ভারী পুনরাবৃত্তি একটি উত্পাদন পরিবেশে যত্ন সহ ব্যবহার করা উচিত, তবে ভারী ডেটা আমদানি বা রূপান্তর কার্য সম্পাদন করতে সিটিই ব্যবহার করার পক্ষে এটি দুর্দান্ত।
টিম মেডোরা

3
CREATE FUNCTION Split
(
  @delimited nvarchar(max),
  @delimiter nvarchar(100)
) RETURNS @t TABLE
(
-- Id column can be commented out, not required for sql splitting string
  id int identity(1,1), -- I use this column for numbering splitted parts
  val nvarchar(max)
)
AS
BEGIN
  declare @xml xml
  set @xml = N'<root><r>' + replace(@delimited,@delimiter,'</r><r>') + '</r></root>'

  insert into @t(val)
  select
    r.value('.','varchar(max)') as item
  from @xml.nodes('//root/r') as records(r)

  RETURN
END
GO

ব্যবহার

Select * from dbo.Split(N'1,2,3,4,6',',')

3

এই সাধারণ সিটিই যা প্রয়োজন তা দেবে:

DECLARE @csv varchar(max) = '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15';
--append comma to the list for CTE to work correctly
SET @csv = @csv + ',';
--remove double commas (empty entries)
SET @csv = replace(@csv, ',,', ',');
WITH CteCsv AS (
    SELECT CHARINDEX(',', @csv) idx, SUBSTRING(@csv, 1, CHARINDEX(',', @csv) - 1) [Value]
    UNION ALL
    SELECT CHARINDEX(',', @csv, idx + 1), SUBSTRING(@csv, idx + 1, CHARINDEX(',', @csv, idx + 1) - idx - 1) FROM CteCsv
    WHERE CHARINDEX(',', @csv, idx + 1) > 0
)

SELECT [Value] FROM CteCsv

@ জিনসুনজি আপনি এই উত্তরটি দেখতে চাইতে পারেন, এটি গৃহীত উত্তরের চেয়ে বেশি দক্ষ এবং সহজ।
মিশা তুরস্কিন

2

এটি অন্য একটি সংস্করণ যা সত্যই কোনও বিধিনিষেধ নেই (উদাহরণস্বরূপ: এক্সটিএমএল পদ্ধতির ব্যবহারের সময় বিশেষ অক্ষর, সিটিই পদ্ধতির মধ্যে রেকর্ডের সংখ্যা) এবং এটি উত্সের স্ট্রিং গড় দৈর্ঘ্য 4000 এর 10M + রেকর্ডের উপর ভিত্তি করে একটি পরীক্ষার উপর ভিত্তি করে দ্রুত চলে runs আশা করি এটি সাহায্য করতে পারত.

Create function [dbo].[udf_split] (
    @ListString nvarchar(max),
    @Delimiter  nvarchar(1000),
    @IncludeEmpty bit) 
Returns @ListTable TABLE (ID int, ListValue nvarchar(1000))
AS
BEGIN
    Declare @CurrentPosition int, @NextPosition int, @Item nvarchar(max), @ID int, @L int
    Select @ID = 1,
   @L = len(replace(@Delimiter,' ','^')),
            @ListString = @ListString + @Delimiter,
            @CurrentPosition = 1 
    Select @NextPosition = Charindex(@Delimiter, @ListString, @CurrentPosition)
   While @NextPosition > 0 Begin
   Set  @Item = LTRIM(RTRIM(SUBSTRING(@ListString, @CurrentPosition, @NextPosition-@CurrentPosition)))
   If      @IncludeEmpty=1 or LEN(@Item)>0 Begin 
     Insert Into @ListTable (ID, ListValue) Values (@ID, @Item)
     Set @ID = @ID+1
   End
   Set  @CurrentPosition = @NextPosition+@L
   Set  @NextPosition = Charindex(@Delimiter, @ListString, @CurrentPosition)
  End
    RETURN
END

1

ব্যবহার ট্যালি টেবিল এখানে জেফ Moden পর এক বিভক্ত স্ট্রিং ফাংশন (সম্ভাব্য সর্বোত্তম পদ্ধতি) হয়

CREATE FUNCTION [dbo].[DelimitedSplit8K]
        (@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
;

ট্যালি ওহ থেকে রেফারেন্স! একটি উন্নত এসকিউএল 8 কে "সিএসভি বিভাজন" ফাংশন


0

এই ব্লগটি টি-এসকিউএল-এ XML ব্যবহার করে বেশ ভাল সমাধান নিয়ে এসেছে।

এই ব্লগটির উপর ভিত্তি করে আমি এই ফাংশনটি নিয়ে এসেছি (ফাংশনের নাম এবং ফলাফলের প্রকারের প্রয়োজন অনুসারে পরিবর্তন করুন):

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[SplitIntoBigints]
(@List varchar(MAX), @Splitter char)
RETURNS TABLE 
AS
RETURN 
(
    WITH SplittedXML AS(
        SELECT CAST('<v>' + REPLACE(@List, @Splitter, '</v><v>') + '</v>' AS XML) AS Splitted
    )
    SELECT x.v.value('.', 'bigint') AS Value
    FROM SplittedXML
    CROSS APPLY Splitted.nodes('//v') x(v)
)
GO

0
CREATE Function [dbo].[CsvToInt] ( @Array varchar(4000)) 
returns @IntTable table 
(IntValue int)
AS
begin
declare @separator char(1)
set @separator = ','
declare @separator_position int 
declare @array_value varchar(4000) 

set @array = @array + ','

while patindex('%,%' , @array) <> 0 
begin

select @separator_position = patindex('%,%' , @array)
select @array_value = left(@array, @separator_position - 1)

Insert @IntTable
Values (Cast(@array_value as int))
select @array = stuff(@array, 1, @separator_position, '')
end

0
/* *Object:  UserDefinedFunction [dbo].[Split]    Script Date: 10/04/2013 18:18:38* */
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[Split]
(@List varchar(8000),@SplitOn Nvarchar(5))
RETURNS @RtnValue table
(Id int identity(1,1),Value nvarchar(100))
AS
BEGIN
    Set @List = Replace(@List,'''','')
    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))

    Return
END
go

Select *
From [Clv].[Split] ('1,2,3,3,3,3,',',')
GO

-4

আপনি সমস্যাটি সমাধান হওয়ার পরে এই ফাংশনটি স্কিএল সার্ভারে লিখবেন।

http://csharpdotnetsol.blogspot.in/2013/12/csv-function-in-sql-server-for-divide.html


কেবল লিঙ্কগুলি অনুলিপি করবেন না ... এটি উত্তম প্রশ্নের একটি চিহ্ন নয় ... আপনাকে বিশদে বিশদটি ব্যাখ্যা করতে হবে
হাংরি ডিক্টেটর
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.