Sandro Bizioli


Chi sogna di giorno conosce molte cose che sfuggono a chi sogna soltanto di notte. (E.A.Poe)
Mappa

Funzione Split in SQL

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?
Categoria: SQL Server
martedì, 28 feb 2006 Ore. 17.04
Statistiche
  • Views Home Page: 111.524
  • Views Posts: 568.225
  • Views Gallerie: 117.370
  • n° Posts: 227
  • n° Commenti: 222
Copyright © 2002-2007 - Blogs 2.0
dotNetHell.it | Home Page Blogs
ASP.NET 2.0 Windows 2003