Tôi đang tìm cách chia '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ...' (được phân cách bằng dấu phẩy) thành một biến bảng hoặc bảng .
Có ai có một hàm trả về từng cái một không?
Tôi đang tìm cách chia '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ...' (được phân cách bằng dấu phẩy) thành một biến bảng hoặc bảng .
Có ai có một hàm trả về từng cái một không?
Câu trả lời:
Đây là một giải pháp lỗi thời:
/*
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
Trong SQL Server 2008, bạn có thể đạt được điều tương tự với mã .NET. Có thể nó sẽ hoạt động nhanh hơn, nhưng chắc chắn cách tiếp cận này dễ quản lý hơn.
Thử cái này
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)
HOẶC LÀ
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
Nhiều cách khác để làm điều tương tự là ở đây Làm thế nào để phân tách chuỗi phân cách bằng dấu phẩy?
<
, >
hoặc &
(ví dụ: đầu vào là một chuỗi số nguyên). Bất kỳ ba ký tự nào ở trên sẽ khiến bạn gặp lỗi phân tích thay vì kết quả mong đợi.
SELECT b, CHARINDEX(@delimiter, @str, b) + LEN(@delimiter)
nên thực sự SELECT b, CHARINDEX(@delimiter, @str, b+1) + LEN(@delimiter)
. Các b + 1 tạo ra một sự khác biệt lớn. Đã thử nghiệm ở đây với không gian là dấu phân cách, không hoạt động mà không sửa lỗi này.
MAXRECURSION
tùy chọn để tách hơn 100 phần, thay thế LEN
bằng một cái gì đó từ stackoverflow.com/q/2025585 để xử lý khoảng trắng và loại trừ NULL
các hàng cho NULL
đầu vào.
Bạn đã gắn thẻ SQL Server 2008 này nhưng khách truy cập trong tương lai cho câu hỏi này (sử dụng SQL Server 2016+) có thể sẽ muốn biết về STRING_SPLIT
.
Với chức năng dựng sẵn mới này, giờ bạn có thể sử dụng
SELECT TRY_CAST(value AS INT)
FROM STRING_SPLIT ('1,2,3,4,5,6,7,8,9,10,11,12,13,14,15', ',')
Một số hạn chế của chức năng này và một số kết quả đầy hứa hẹn của thử nghiệm hiệu suất có trong bài đăng trên blog này của Aaron Bertrand .
Điều này giống như .NET, đối với những bạn quen thuộc với chức năng đó:
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'
đây là chức năng phân chia mà bạn yêu cầu
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
thực hiện chức năng như thế này
select * from dbo.split('1,2,3,4,5,6,7,8,9,10,11,12,13,14,15',',')
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)
Nguồn của phản hồi này: http://sqlhint.com/sqlserver/how-to/best-split-feft-tsql-delrict
Tôi bị cám dỗ để ép trong giải pháp yêu thích của tôi. Bảng kết quả sẽ bao gồm 2 cột: PosIdx cho vị trí của số nguyên tìm thấy; và Giá trị bằng số nguyên.
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
Nó hoạt động bằng cách sử dụng CTE đệ quy làm danh sách các vị trí, từ 1 đến 100 theo mặc định. Nếu bạn cần làm việc với chuỗi dài hơn 100, chỉ cần gọi hàm này bằng cách sử dụng 'tùy chọn (maxrecursion 4000)' như sau:
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)
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
sử dụng
Select * from dbo.Split(N'1,2,3,4,6',',')
CTE đơn giản này sẽ cung cấp những gì cần thiết:
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
Đây là một phiên bản khác thực sự không có bất kỳ hạn chế nào (ví dụ: ký tự đặc biệt khi sử dụng phương pháp xml, số lượng bản ghi trong phương pháp CTE) và nó chạy nhanh hơn nhiều dựa trên thử nghiệm trên các bản ghi 10M + với độ dài trung bình của chuỗi nguồn là 4000. Hy vọng điều này có thể giúp đỡ
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
Sử dụng bảng kiểm đếm ở đây là một hàm chuỗi tách (cách tiếp cận tốt nhất có thể) của Jeff 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
;
Được giới thiệu từ Tally OH! Một chức năng Splitter Splitter SQL 8K được cải tiến
Blog này đi kèm với một giải pháp khá tốt bằng cách sử dụng XML trong T-SQL.
Đây là chức năng tôi đã đưa ra dựa trên blog đó (thay đổi tên hàm và loại kết quả theo nhu cầu):
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
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
/* *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
Bạn viết hàm này trong máy chủ sql sau khi vấn đề đó sẽ được giải quyết.
http://csharpdotnetsol.blogspot.in/2013/12/csv-feft-in-sql-server-for-divide.html