Ciao.
Si, in linea di principio, sarei anch'io d'accordo con te. Tuttavia ISNUMERIC presenta delle particolarità operative per cui tendo a non usarla.
Sempre in linea generale, il fatto che ISNUMERIC ritorni 1 non significa necessariamente che si possa fare sul suo argomento ogni tipo di casting, sia pure lecito dal punto di vista concettuale.
A titolo di esempio, ISNUMERIC supporta argomenti del tipo '1e3', ossia il numero 1000 espresso in notazione esponenziale.
Tuttavia, mentre l'istruzione CAST('1000' AS INT) ritorna correttamente l'intero 1000, l'espressione CAST('1e3' AS INT) produce un errore.
Al contrario, CAST('1e3' AS FLOAT) funziona correttamente.
In generale, quindi, il ricorrere a ISNUMERIC non ci mette al riparo da possibili errori a run-time.
Voglio dire, insomma, che in ogni caso si è chiamati ad un adattamento in base al contesto e allora tanto vale scriversi delle funzioni proprie, se ritenuto conveniente, per ogni specifica esigenza.
Io lo faccio anche per una migliore scalabilità del codice dal momento che, a seconda delle versioni di SQL Server, non tutte le funzioni sono disponibili.
Ci sono da segnalare, poi, i comportamenti di ISNUMERIC in presenza dei segni '+', '-' e di valuta e non è detto che siano sempre desiderabili in ogni caso.
Hai ragione, la mia funzione non supporta i numeri negativi!
Anzi, dirò di più, nemmeno i positivi se sono preceduti dal segno '+' )
E' chiaro che ho voluto scrivere una soluzione venuta "di getto", senza voler avere la benché minima pretesa di presentare una soluzione elegante e/o esaustiva.
Anzi, a guardarla meglio, la soluzione è proprio un abbozzo che si potrebbe riscrivere senz'altro in modo migliore.
D'altra parte, il compito del Forum è piuttosto quello di "mettere la pulce nell'orecchio" che quello di fornire soluzioni complete e pronte all'uso.
Certamente è come dici tu, che i dati sul db sono già corretti dal punto di vista delle conversioni. Il mio era solo un modo di dire che, nel caso vi fossero stringhe sui generis, la query sarebbe andata comunque in errore.
Così, giusto perché lo hai notato e poiché mi ritengo anche un appassionato di soluzione in SQL, ho colto l'occasione per riscriverla in modo che sia più semplice e che supporti anche i segni '+' e '-', per quello che vale naturalmente e senza nessuna pretesa di completezza.
Chiedo scusa per la mia prolissità davvero spropositata.
create function [dbo].[ufn_Valore](@valore varchar(100))
returns float as
begin
declare @Ret varchar(100) = (case when @valore='' then NULL else replace(ltrim(@valore), ',', '.') end)
declare @comma tinyint = 0
declare @segno varchar(1)
declare @i tinyint = 0
declare @l tinyint
declare @c char(1)
select @segno = left(@Ret, 1) where left(@Ret, 1) in ('+', '-')
if @segno is not null set @Ret = stuff(@Ret, 1, 1, '') else set @segno=''
set @l = len(@Ret)
while @i < @l
begin
if @comma > 1 set @Ret = null else
begin
set @i = @i + 1
set @c = substring(@Ret, @i, 1)
if @c = '.'
set @comma = @comma + 1
else
if (ascii(@c) < ascii('0') or ascii(@c) > ascii('9')) set @Ret = null
;
end
if @Ret is null set @i = @l
end
;
return cast(@segno + @Ret as float)
end