Come facciamo ad estrarre da una stringa o dal testo contenuto in un determinato campo, tutti i valori delimitati da un determinato carattere?
Una sorta di funzione Split di VB, tanto per capirci.
Beh, così su due piedi non è facilissimo; è per questo che ho dato una sbirciatina su internet alla ricerca di qualche cosa che facesse al caso mio, trovando, come ovvio, molte soluzioni.
Una di quelle che più mi ha soddisfatto è di Martin Naude e può essere reperita sul sito Devx al seguente link.
La funzione richiede un nVarchar come stinga da analizzare ed un nVarchar di lunghezza massima a 10 come delimitatore di campo.
Il risultato dell'operazione ci viene restituito sottoforma di tabella.
if exists (select * from dbo.sysobjects where id =
object_id(N'[dbo].[UTILfn_Split]') and xtype in (N'FN', N'IF', N'TF'))
drop function [dbo].[UTILfn_Split]
GO
create function dbo.UTILfn_Split(
@myString nvarchar (4000),
@Delimiter nvarchar (10)
)
returns @ValueTable table ([Value] nvarchar(4000))
begin
declare @NextString nvarchar(4000)
declare @Pos int
declare @NextPos int
declare @CommaCheck nvarchar(1)
--Initialize
set @NextString = ''
set @CommaCheck = right(@myString,1)
--Check for trailing Comma, if not exists, INSERT
--if (@CommaCheck <> @Delimiter )
set @myString = @myString + @Delimiter
--Get position of first Comma
set @Pos = charindex(@Delimiter,@myString)
set @NextPos = 1
--Loop while there is still a comma in the String of levels
while (@pos <> 0)
begin
set @NextString = substring(@myString,1,@Pos - 1)
insert into @ValueTable ( [Value]) Values (@NextString)
set @myString = substring(@myString,@pos +1,len(@myString))
set @NextPos = @Pos
set @pos = charindex(@Delimiter,@myString)
end
return
end
Ora mettiamo alla prova la nostra funzione:
DECLARE @myString as nvarchar(4000)
SELECT @myString = 'Oggi è una bella giornata e speriamo che sia anche anche una bella serata'
SELECT * FROM UTILfn_Split(@myString,' ')
/* output
Value
-----------------------
Oggi
è
una
bella
giornata
e
speriamo
che
sia
anche
anche
una
bella
serata
(14 row(s) affected) */
Direi che è perfetta, ma... non contento vi ho apportato ugualmente alcune modifiche, aggiungendovi due nuovi campi: rowNumber che indica la posizione in tabella e, di conseguenza all'interno della stringa analizzata e Num che indica il numero di volte che questa si ripete.
Ho, inoltre. modificato il nome del campo [value] in "valore" per evitare di mettere sempre le parentesi quadre.
Facciamo lo stesso esempio, questa volta creando la funcione fn_Split con le nuove features.
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Martin Naude
-- Source: http://www.devx.com/tips/Tip/20009
-- Modify by: Sandro Bizioli
-- Create date:
-- Description:
-- =============================================
CREATE FUNCTION [dbo].[fn_Split](
@myString nvarchar (4000),
@Delimiter varchar (10)
)
returns @ValueTable table (rowNumber int identity(1,1), Valore nvarchar(4000), Num int null)
begin
declare @NextString nvarchar(4000)
declare @Pos int
declare @myStep int
declare @CommaCheck nvarchar(1)
--Initialize
set @NextString = ''
set @CommaCheck = right(@myString,1)
if @Delimiter = ''
Select @Delimiter = ' '
Set @myStep = len(@Delimiter + '|') -1
--Check for trailing Comma, if not exists, INSERT
--if (@CommaCheck <> @Delimiter )
set @myString = @myString + @Delimiter
--Get position of first Comma
Set @Pos = charindex(@Delimiter, @myString)
--Loop while there is still a comma in the String of levels
while (@pos <> 0)
begin
set @NextString = substring(@myString, 1, @Pos - 1)
insert into @ValueTable (Valore) Values (@NextString)
-- Aggiorno le occorrenze
update @ValueTable set num =
(
select count(*)
from @ValueTable
Where Valore = @NextString
)
where Valore = @NextString
set @myString = substring(@myString, @pos + @myStep , len(@myString))
set @pos = charindex(@Delimiter, @myString)
end
return
end
Recuperiamo i valori come nell'esempio precedente:
DECLARE @myString as nvarchar(4000)
SELECT @myString = 'Oggi è una bella giornata e speriamo che sia anche una bella serata'
SELECT * FROM fn_Split(@myString,' ')
/* output
rowNumber Valore Num
----------- ------------- -----------
1 Oggi 1
2 è 1
3 una 2
4 bella 2
5 giornata 1
6 e 1
7 speriamo 1
8 che 1
9 sia 1
10 anche 1
11 una 2
12 bella 2
13 serata 1
(14 row(s) affected) */
Come si nota rowNumber indica il numero progressivo della parola mentre num il ripetersi di essa nella stringa.
"una" e "bella" si ripetono 2 volte, le altre solo una.
Ora facciamo un filtro sul risultato, chiedendo di analizzare solo una parola, ad esempio "bella"
DECLARE @myString as nvarchar(4000)
SELECT @myString = 'Oggi è una bella giornata e speriamo che sia anche anche una bella serata'
--SELECT len([value]) FROM UTILfn_Split(@myString,' ')
SELECT * FROM fn_Split(@myString,' ') WHERE valore ='bella'
rowNumber Valore Num
----------- --------- -----------
4 bella 2
13 bella 2
(2 row(s) affected)
Come si nota riusciamo a capire che "bella" si trova come 4a e 13a parola nella nostra stringa e che è ripetuta 2 volte.
Ok. Lo ammetto, le modifiche non sono gran chè, ma a me tornavano utili e a voi?