NO MS SQL FUNCAO DUPLO SPLIT

TUNUSAT 25/11/2014 12:06:23
#442757
Por favor PessoALL,

Estou tentando montar uma função dentro do SQL Server 2008 para fazer um [Ô]duplo Split[Ô]. A idéia é assim, por exemplo:
Eu tenho uma variável chamada [Ô]@BASE[Ô] com quebra por [Ô];[Ô] (ponto e vírgula) e [Ô];[Ô] (vírgula):
DECLARE @BASE VARCHAR(300)
SELECT @BASE = [ô]0.1,0.3,0.001;0.4,0.6,0.005;0.7,0.9,0.01[ô]


A função precisa retornar uma coluna transformando-a em linha. Exemplo:
SELECT 0.001, 0.005, 0.01

Criei esta função dentro do MS SQL Server:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE FUNCTION [dbo].[dSplit](
@frase VARCHAR(max)
, @delimitador1 VARCHAR(max) = [ô];[ô]
, @delimitador2 VARCHAR(max) = [ô],[ô]
) RETURNS @result TABLE (item VARCHAR(8000))

BEGIN
DECLARE @parte VARCHAR(8000)
WHILE CHARINDEX(@delimitador1,@frase,0) <> 0
BEGIN
SELECT
@parte=RTRIM(LTRIM(
SUBSTRING(@frase,1,
CHARINDEX(@delimitador1,@frase,0)-1))),
@frase=RTRIM(LTRIM(SUBSTRING(@frase,
CHARINDEX(@delimitador1,@frase,0)
+ LEN(@delimitador1), LEN(@frase))))
IF LEN(@parte) > 0
INSERT INTO @result SELECT @parte
END

IF LEN(@frase) > 0
INSERT INTO @result SELECT @frase
RETURN
END


Okay ... ela me devolve em uma linha única a última posição do [Ô];[Ô].

Dai pensei em replicar o WHILE inteiro e guardar a posição que este WHILE interno está e concatenar assim não perderia o resultado.
Mas em algum ponto ele se perde!

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER FUNCTION [dbo].[dSplit](
@frase VARCHAR(max)
, @delimitador1 VARCHAR(max) = [ô];[ô]
, @delimitador2 VARCHAR(max) = [ô],[ô]
) RETURNS @result TABLE (item VARCHAR(8000))

BEGIN
DECLARE @parte VARCHAR(8000)
DECLARE @parte2 VARCHAR(8000)
DECLARE @GUARDA VARCHAR(8000)
WHILE CHARINDEX(@delimitador1,@frase,0) <> 0
BEGIN
SELECT
@parte=RTRIM(LTRIM(
SUBSTRING(@frase,1,
CHARINDEX(@delimitador1,@frase,0)-1))),
@frase=RTRIM(LTRIM(SUBSTRING(@frase,
CHARINDEX(@delimitador1,@frase,0)
+ LEN(@delimitador1), LEN(@frase))))
--IF LEN(@parte) > 0
--INSERT INTO @result SELECT @parte

--INICIO DA REPLIACAÇÃO DO WHILE
WHILE CHARINDEX(@delimitador2,@parte,0) <> 0
BEGIN
SELECT
@parte2=RTRIM(LTRIM(
SUBSTRING(@parte,1,
CHARINDEX(@delimitador2,@parte,0)-1))),
@parte=RTRIM(LTRIM(SUBSTRING(@parte,
CHARINDEX(@delimitador2,@parte,0)
+ LEN(@delimitador2), LEN(@parte))))
SELECT @GUARDA = concat(@GUARDA, [ô] | [ô], @parte2)
IF LEN(@GUARDA) > 0
INSERT INTO @result SELECT @GUARDA
END
--FIM
END

IF LEN(@GUARDA) > 0
INSERT INTO @result SELECT @GUARDA
RETURN
END


Por favor, pode me ajudar?

[][ô]s,
Tunusat.
TUNUSAT 25/11/2014 15:52:33
#442766
PessoALL!

Achei este exemplo bem bacana e adaptei ... chegou perto! Nunca vi este [Ô]CROSS APPLY[Ô] na vida! KKKKK!

http://jingyangli.wordpress.com/2012/10/18/split-string-with-multiple-delimiters-t-sql-xml-method/

create table test(resp varchar(100))
insert into test(resp)
SELECT [ô]0.1,0.3,0.001;0.4,0.6,0.005;0.7,0.9,0.01[ô]

;with mycte as
(SELECT S.a.value([ô].[ô], [ô]VARCHAR(100)[ô]) AS splitVal1
FROM
(SELECT *,CAST (N[ô]<H><r>[ô] + Replace( resp, [ô];[ô],[ô]</r><r>[ô]) + [ô]</r></H>[ô] AS XML) AS [vals]
FROM test) d CROSS APPLY d.[vals].nodes([ô]/H/r[ô]) S(a)
)
Select DISTINCT S.a.value([ô](/H/r)[1][ô], [ô]VARCHAR(100)[ô]) Range_Inicial,
S.a.value([ô](/H/r)[2][ô], [ô]VARCHAR(100)[ô]) Range_Final,
S.a.value([ô](/H/r)[3][ô], [ô]VARCHAR(100)[ô]) Porcentagem
FROM
(SELECT *, CAST (N[ô]<H><r>[ô] + Replace( splitVal1, [ô],[ô],[ô]</r><r>[ô]) + [ô]</r></H>[ô] AS XML) [vals]
FROM mycte) d CROSS APPLY d.[vals].nodes([ô]/H/r[ô]) S(a)

ORDER BY Range_Inicial

drop table test


Estava conversando com o chefe aqui e percebemos que este cara usa XML ... diz ele que o XML cria uma tabela no banco de dados despencando a performance...
Com é que eu converto este cara para uma função?

[][ô]s,
Tunusat.
TUNUSAT 25/11/2014 22:28:22
#442774
PessoALL!

Preciso transformar o exemplo acima em uma Função!
Montei o código abaixo, mas deu errado...
... por favor, podem me ajudar?
CREATE FUNCTION [dbo].[dSplit](
@frase VARCHAR(max)
,@delimitador1 VARCHAR(max) = [ô];[ô]
,@delimitador2 VARCHAR(max) = [ô],[ô]
) RETURNS @result TABLE (item VARCHAR(8000))

BEGIN
DECLARE @parte TABLE(LINHA VARCHAR(8000))
SELECT @parte = (
SELECT @frase
;with mycte as
(SELECT S.a.value([ô].[ô], [ô]VARCHAR(100)[ô]) AS splitVal1
FROM
(SELECT *,CAST (N[ô]<H><r>[ô] + Replace( resp, @delimitador1,[ô]</r><r>[ô]) + [ô]</r></H>[ô] AS XML) AS [vals]
FROM test) d CROSS APPLY d.[vals].nodes([ô]/H/r[ô]) S(a)
)
SELECT DISTINCT S.a.value([ô](/H/r)[1][ô], [ô]VARCHAR(100)[ô]) Range_Inicial,
S.a.value([ô](/H/r)[2][ô], [ô]VARCHAR(100)[ô]) Range_Final,
S.a.value([ô](/H/r)[3][ô], [ô]VARCHAR(100)[ô]) Porcentagem
FROM
(SELECT *, CAST (N[ô]<H><r>[ô] + Replace( splitVal1, @delimitador2,[ô]</r><r>[ô]) + [ô]</r></H>[ô] AS XML) [vals]
FROM mycte) d CROSS APPLY d.[vals].nodes([ô]/H/r[ô]) S(a)

ORDER BY Range_Inicial
)
INSERT INTO @result SELECT @parte
END


[][ô]s,
Tunusat.
TUNUSAT 26/11/2014 11:17:14
#442781
PessoALL,

Conversando em outro fórum (https://social.technet.microsoft.com/Forums/sqlserver/pt-BR/509b02af-2674-4132-bb24-03949c92721f/no-ms-sql-funcao-duplo-split?forum=transactsqlpt), cheguei a duas funções a saber:
- dbo.dSplit;
- dbo.UFN_SEPARATES_COLUMNS;

Gostei mas da [Ô]dSplit[Ô], mas ela usa XML e possivelmente prejudicará a performance... O que vocês acham?
Pedi para disponibilizar as duas aqui no VBMania no repositório de código. Em breve estarão disponíveis.

Abaixo os códigos:

- dSplit:
------------------------------
-- Adaptado por José Diz / Belo Horizonte, MG - Brasil
-- De: http://jingyangli.wordpress.com/2012/10/18/split-string-with-multiple-delimiters-t-sql-xml-method/
------------------------------
-- https://social.technet.microsoft.com/Forums/sqlserver/pt-BR/509b02af-2674-4132-bb24-03949c92721f/no-ms-sql-funcao-duplo-split?forum=transactsqlpt
------------------------------
-- SPLIT DUPLO!
------------------------------
CREATE FUNCTION dbo.fnDSplit (
@frase varchar(300),
@delimitador1 char(1),
@delimitador2 char(1)
)
returns @result TABLE (Range_Inicial varchar(30), Range_Final varchar(30), Porcentagem varchar(30)) as
begin
declare @myXML XML;
set @myXML= N[ô]<H><r>[ô] + Replace(@frase, @delimitador1, [ô]</r><r>[ô]) + [ô]</r></H>[ô];

with cte as (
SELECT Cast(N[ô]<H><r>[ô] + Replace(Replace(Vals.id.value([ô].[ô], [ô]NVARCHAR(50)[ô]),@delimitador2,[ô]|[ô]), [ô]|[ô], [ô]</r><r>[ô]) + [ô]</r></H>[ô] as XML) as val
from @myXML.nodes([ô]/H/r[ô]) as Vals(id)
)
INSERT into @result
SELECT distinct S.a.value([ô](/H/r)[1][ô], [ô]NVARCHAR(50)[ô]) as C1,
S.a.value([ô](/H/r)[2][ô], [ô]NVARCHAR(50)[ô]) as C2,
S.a.value([ô](/H/r)[3][ô], [ô]NVARCHAR(50)[ô]) as C3
from cte
cross apply val.nodes([ô]/H/r[ô]) S(a);
return;
end;
go
------------------------------
-- PARA TESTAR!
------------------------------
DECLARE @BASE VARCHAR(300)
SELECT @BASE = [ô]0.1,0.3,0.001; 0.4,0.6,0.005;0.7,0.9,0.01[ô]
SELECT * FROM dbo.fnDSplit(@BASE, [ô];[ô], [ô],[ô])
------------------------------


- UFN_SEPARATES_COLUMNS
------------------------------
-- Desenvolvido por Durval Ramos
------------------------------
-- http://social.technet.microsoft.com/wiki/pt-br/contents/articles/24654.t-sql-dividindo-uma-string-em-multiplas-colunas.aspx
------------------------------
-- T-SQL: Dividindo uma String em múltiplas colunas
------------------------------
CREATE FUNCTION dbo.UFN_SEPARATES_COLUMNS(
@TEXT
varchar(8000)
,@COLUMN
tinyint
,@SEPARATOR char(1)
)RETURNS varchar(8000)
AS
BEGIN
DECLARE @POS_START int = 1
DECLARE @POS_END int = CHARINDEX(@SEPARATOR, @TEXT, @POS_START)

WHILE (@COLUMN >1 AND @POS_END> 0)
BEGIN
SET @POS_START = @POS_END + 1
SET @POS_END = CHARINDEX(@SEPARATOR, @TEXT, @POS_START)
SET @COLUMN = @COLUMN - 1
END

IF @COLUMN > 1 SET @POS_START = LEN(@TEXT) + 1
IF @POS_END = 0 SET @POS_END = LEN(@TEXT) + 1

RETURN SUBSTRING (@TEXT, @POS_START, @POS_END - @POS_START)
END
GO
------------------------------
-- PARA TESTAR!
-- OBTéM OS ELEMENTOS DE UMA ESTRUTURA [Ô]ISBN[Ô]
------------------------------
DECLARE @ISBN varchar(20) = [ô]978-0-571-08989-5[ô]
SELECT
dbo.UFN_SEPARATES_COLUMNS(@ISBN, 1, [ô]-[ô]) AS PREFIX,
dbo.UFN_SEPARATES_COLUMNS(@ISBN, 2, [ô]-[ô]) AS REGISTRATION_GROUP,
dbo.UFN_SEPARATES_COLUMNS(@ISBN, 3, [ô]-[ô]) AS REGISTRANT,
dbo.UFN_SEPARATES_COLUMNS(@ISBN, 4, [ô]-[ô]) AS PUBLICATION,
dbo.UFN_SEPARATES_COLUMNS(@ISBN, 5, [ô]-[ô]) AS [CHECK]
GO
------------------------------
-- OUTRO TESTE (DUPLA SEPARAÇÃO):
------------------------------
DECLARE @BASE VARCHAR(300)
SELECT @BASE = [ô]0.1,0.3,0.001;0.4,0.6,0.005;0.7,0.9,0.01[ô]

SELECT dbo.UFN_SEPARATES_COLUMNS(@BASE, 1, [ô];[ô]),
dbo.UFN_SEPARATES_COLUMNS(dbo.UFN_SEPARATES_COLUMNS(@BASE, 1, [ô];[ô]),1,[ô],[ô]),
dbo.UFN_SEPARATES_COLUMNS(dbo.UFN_SEPARATES_COLUMNS(@BASE, 1, [ô];[ô]),2,[ô],[ô]),
dbo.UFN_SEPARATES_COLUMNS(dbo.UFN_SEPARATES_COLUMNS(@BASE, 1, [ô];[ô]),3,[ô],[ô])
GO
------------------------------


[][ô]s,
Tunusat.
FILMAN 26/11/2014 22:41:18
#442810
Resposta escolhida
olá, veja se ajuda essa função:

CREATE FUNCTION [dbo].[FCT_SPLIT_STRING](@string NVARCHAR(MAX), @delimiter1 CHAR(1), @delimiter2 CHAR(1) = null)
RETURNS @output TABLE(RESULTADO NVARCHAR(MAX)
)
BEGIN

DECLARE @substart INT, @subend INT
DECLARE @start INT, @end INT

SELECT @start = 1, @end = CHARINDEX(@delimiter1, @string)

WHILE @start < LEN(@string) + 1 BEGIN
IF @end = 0
SET @end = LEN(@string) + 1

IF @delimiter2 is null BEGIN
INSERT INTO @output (RESULTADO)VALUES(SUBSTRING(@string, @start, @end - @start))
END
ELSE BEGIN
SELECT @substart = 1, @subend = CHARINDEX(@delimiter2, SUBSTRING(@string, @start, @end - @start))

WHILE @substart < LEN(SUBSTRING(@string, @start, @end - @start)) + 1 BEGIN
IF @subend = 0
SET @subend = LEN(SUBSTRING(@string, @start, @end - @start)) + 1

INSERT INTO @output (RESULTADO)VALUES(SUBSTRING(SUBSTRING(@string, @start, @end - @start), @substart, @subend - @substart))

SET @substart = @subend + 1
SET @subend = CHARINDEX(@delimiter2, SUBSTRING(@string, @start, @end - @start), @substart)
END
END

SET @start = @end + 1
SET @end = CHARINDEX(@delimiter1, @string, @start)

END
RETURN
END
Tópico encerrado , respostas não são mais permitidas