Je cherche à diviser '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ...' (délimité par des virgules) dans une table ou variable de table.Fonction de partage équivalente en T-SQL?
Est-ce que quelqu'un a une fonction qui retourne chacun d'affilée?
Je cherche à diviser '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ...' (délimité par des virgules) dans une table ou variable de table.Fonction de partage équivalente en T-SQL?
Est-ce que quelqu'un a une fonction qui retourne chacun d'affilée?
Voici la solution un peu à l'ancienne:
/*
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, @[email protected]))
else
insert into @tParts
values(null)
set @iStart = @iPos+1
if @iStart > len(@sString)
break
end
RETURN
END
Dans SQL Server 2008, vous pouvez obtenir le même avec le code .NET. Peut-être que cela fonctionnerait plus vite, mais cette approche est certainement plus facile à gérer.
Merci, j'aimerais aussi savoir. Y a-t-il une erreur ici? J'ai écrit ce code il y a peut-être 6 ans et ça fonctionnait bien depuis quand. – XOR
Je suis d'accord. C'est une très bonne solution lorsque vous ne voulez pas (ou simplement ne pouvez pas) vous impliquer dans la création de paramètres de type table, ce qui serait le cas dans mon cas. Les DBA ont verrouillé cette fonctionnalité et ne le permettent pas. Merci XOR! – dscarr
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=50648
Une sélection de différentes méthodes
Je suis tenté de serrer dans ma solution préférée. La table résultante sera composée de 2 colonnes: PosIdx pour la position de l'entier trouvé; et Valeur en entier.
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
Il fonctionne en utilisant le CTE récursif comme liste de positions, de 1 à 100 par défaut. Si vous avez besoin de travailler avec chaîne de plus de 100, il suffit d'appeler cette fonction en utilisant 'l'option (maxrecursion 4000)' comme ce qui suit:
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)
+1 pour avoir mentionné l'option maxrecursion. De toute évidence, une récursion lourde doit être utilisée avec précaution dans un environnement de production, mais il est bon d'utiliser des CTE pour effectuer de lourdes tâches d'importation ou de conversion de données. –
Essayez cette
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)
OU
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
Beaucoup plus de façons de faire la même chose est ici How to split comma delimited string?
Remarque pour tous ceux qui recherchent un séparateur de chaînes général: La première solution donnée ici n'est pas un séparateur de chaînes général - il est sûr seulement si vous êtes sûr que l'entrée ne contiendra jamais <', '> ou '&' (par exemple une entrée est une séquence d'entiers). L'un des trois caractères ci-dessus entraînera une erreur d'analyse au lieu du résultat attendu. – miroxlav
Événement avec les problèmes mentionnés par miroxlav (Ce qui devrait être résolu avec un peu de réflexion), c'est certainement l'une des solutions les plus créatives que j'ai trouvées (la première)! Très agréable! –
La ligne 'SELECT b, CHARINDEX (@delimiter, @str, b) + LEN (@delimiter)' devrait être 'SELECT b, CHARINDEX (@delimiter, @str, b + 1) + LEN (@delimiter)' . Le ** b + 1 ** fait une grande différence. Testé ici avec l'espace comme délimiteur, n'a pas fonctionné sans ce correctif. – JwJosefy
Cela ressemble beaucoup à .NET, pour ceux d'entre vous qui sont familiers avec cette fonction:
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'
Cela a fonctionné pour moi après avoir ajouté GO après la fin – clairestreb
This blog est venu avec une assez bonne solution en utilisant XML dans T-SQL.
Ceci est la fonction que je suis venu avec basé sur ce blog (type changement de dénomination sociale et le résultat fonction cast par nécessité):
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
ici est la fonction split que u demandé
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
exécuter la fonction comme celui-ci
select * from dbo.split('1,2,3,4,5,6,7,8,9,10,11,12,13,14,15',',')
Si simple, a travaillé comme un charme –
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
Ceci est une autre version qui n'a aucune restriction (ex: caractères spéciaux lors de l'utilisation de l'approche xml, nombre d'enregistrements dans l'approche CTE) et fonctionne beaucoup plus rapidement sur la base d'un test sur 10M + Cela pourrait aider.
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, @[email protected])))
If @IncludeEmpty=1 or LEN(@Item)>0 Begin
Insert Into @ListTable (ID, ListValue) Values (@ID, @Item)
Set @ID = @ID+1
End
Set @CurrentPosition = @[email protected]
Set @NextPosition = Charindex(@Delimiter, @ListString, @CurrentPosition)
End
RETURN
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
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)
Source de cette réponse: http://sqlhint.com/sqlserver/how-to/best-split-function-tsql-delimited
Alors que cela peut théoriquement répondre à la question, [il serait préférable] (http://meta.stackexchange.com/q/8259) pour inclure les parties essentielles de la réponse ici, et fournir le lien pour référence. –
@Xavi: ok, j'ai inclus les parties essentielles de la réponse. Merci pour votre indice. –
Vous écrivez cette fonction dans SQL Server après ce problème sera résolu.
http://csharpdotnetsol.blogspot.in/2013/12/csv-function-in-sql-server-for-divide.html
Ne pas copier seulement des liens ... Ce n'est pas un signe de bonnes questions ... Vous devez expliquer en détail –
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
utilisation
Select * from dbo.Split(N'1,2,3,4,6',',')
Vous avez balisé ce SQL Server 2008, mais les futurs visiteurs à cette question (en utilisant SQL Server 2016+) voudront probablement savoir sur STRING_SPLIT
.
Avec cette nouvelle fonction intégrée, vous pouvez maintenant utiliser simplement
SELECT TRY_CAST(value AS INT)
FROM STRING_SPLIT ('1,2,3,4,5,6,7,8,9,10,11,12,13,14,15', ',')
Certaines restrictions de cette fonction et des résultats prometteurs des tests de performance sont en this blog post by Aaron Bertrand.
en utilisant le tableau de pointage ici est une fonction de chaîne de split (meilleure approche possible) par 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
;
Référé de Tally OH! An Improved SQL 8K “CSV Splitter” Function
J'ai récemment effectué une étude mineure comparant les approches les plus communes à ce problème, qui peut être utile de lire: http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings et http://www.sqlperformance.com/2012/08/t- sql-queries/splitting-strings-follow-up –
duplication possible f [Séparer une chaîne dans SQL] (http://stackoverflow.com/questions/2647/split-string-in-sql) – Luv
Erland Sommarskog a maintenu la réponse faisant autorité à cette question au cours des 12 dernières années: [http://www.sommarskog.se/arrays-in-sql.html](http://www.sommarskog.se/arrays-in-sql.html) Il ne vaut pas la peine de reproduire toutes les options ici sur StackOverflow, il suffit de visiter sa page et vous apprendrez tout ce que vous avez toujours voulu savoir. – Portman