2013-02-06 15 views
14

ho il seguente codice di gettare nvarchar a intero:SQL Server - verificare se cast è possibile

 cast(@value as int) 

Tuttavia non ho il controllo del parametro @value, da cui il codice potrebbe fallire. Esiste comunque la possibilità di verificare se è possibile un cast prima di fare un cast?

risposta

21

Ebbene, in SQL Server 2012 è possibile utilizzare il nuovo TRY_CAST(), ma con SQL Server 2008, si dovrebbe essere in grado di utilizzare ISNUMERIC(), e quindi includere la gestione per i valori che non passano quel test.

+5

-1: selezionare isnumeric ('1.'); seleziona cast ('1.'come int); – Pete

+0

ISNumeric ('a1a') restituisce 1, tuttavia non è possibile eseguire il cast ('a1a' come float) – CodingTT

+0

Credo che intendessi SQL Server 2014: https://msdn.microsoft.com/en-us/library/hh974669.aspx –

10

Ho recentemente risposto a una domanda al riguardo e l'utilizzo di ISNUMERIC a CAST su un INT non funzionerà da solo. Essendo il motivo, ISNUMERIC restituisce true per i numeri interi (1.5), ad esempio.

qui era una risposta recente sul tema:

https://stackoverflow.com/a/14692165/1073631

considerare l'aggiunta di un ulteriore controllo utilizzando CHARINDEX con ISNUMERIC, o quello che preferisco, usare un'espressione regolare per convalidare i dati.

Ed ecco un Fiddle che dimostra il problema con l'utilizzo di ISNUMERIC a proprio. E lo Fiddle utilizza invece un'espressione regolare che funziona.

DECLARE @Test nvarchar(10) 
SET @Test = '1.5' 
--Works 
SELECT CASE WHEN @Test NOT LIKE '%[^0-9]%' THEN CAST(@Test as int) ELSE 0 END 
-- Produces Error 
SELECT CASE WHEN ISNUMERIC(@Test) = 1 THEN CAST(@Test as int) ELSE 0 END 

Buona fortuna.

+0

+1. . . Il primo è giusto. La tua risposta dovrebbe essere un po 'più chiara che il secondo è sbagliato (devo scorrere per vedere "Produces Error"). –

+0

Dovresti anche evitare gli overflow (e facoltativamente consentire numeri interi negativi): http://stackoverflow.com/a/24250511/1149773 – Douglas

0

Il test corretta è:

select (case when isnumeric(val) = 1 and val not like '%e%' and val not like '%.%' 
      then cast(val as int) 
     end) 

La funzione isnumeric() restituisce 1 per tutto ciò che si presenta come un galleggiante, quindi bisogna stare attenti.

È anche possibile utilizzare quella che considero una peculiarità di SQL Server. È possibile trasmettere il valore floating 1.23 a un int, ma non è possibile eseguire il cast del valore di stringa. Così, il seguente funziona anche:

select (case when isnumeric(val) = 1 
      then cast(cast(val as float) as int) 
     end) 
+1

No, questo è sbagliato. 'isnumeric ('+') == 1'. 'isnumeric ('-') == 1'. 'isnumeric' è un'implementazione orribile, e la loro risposta ti lascia aperti a casi di edge multipli in cui un' cast' a 'int' fallirà nonostante il tuo check. – mattmc3

+0

@ mattmc3. . Hai notato che l'OP accettava essenzialmente questa risposta. Inoltre, la conversione in 'float' risolve molti di questi problemi (anche se non con overflow). –

+0

La risposta accettata ottiene la parte TRY_CAST corretta per SQL 2012+. Per usare ISNUMERIC, devi fare un sacco di ginnastica per gestire i casi limite. Ad esempio, inserisci "+" o "-" come valori di "val". Il cast di "float" bombarderà in modo spettacolare. (^^ non il mio downvote BTW - preferisco i commenti a rep replay). Questa risposta fornisce un modo per usare 'ISNUMERIC' che gestisce effettivamente i casi limite e garantisce di avere un'alternativa' TRY_CAST' corretta: http://stackoverflow.com/questions/4522056/how-to-determine-the-field-value -che-non-può-convertire-a-decimale-float-int-i – mattmc3

1

forse possiamo fare qualcosa di simile:

declare @value as nvarchar(10) = 'A'; 

begin try 
    select cast(@value as int); 
end try 
begin catch 
-- do something 
end catch 
+0

Mi piace questo approccio ma non possiamo farlo all'interno di un'istruzione SELECT, possiamo? –

2

io in genere uso il seguente, che sembra coprire tutte le situazioni.

SELECT CASE WHEN 1 = ISNUMERIC(@value + '.0') THEN CAST(@value as int) ELSE 0 END 

Si avvale del fatto che "ISNUMERIC" non consente due periodi. Il "TRY_CAST" in SQL Server 2012+ è una soluzione decisamente migliore.

0

utilizzare una procedura con un blocco TRY CATCH per eliminare gli errori

cioè

CREATE PROCEDURE p_try_cast 
@type nvarchar(MAX), 
@value nvarchar(MAX) 
AS 
BEGIN 

    BEGIN TRY 
     DECLARE @sql  varchar(MAX) 
     DECLARE @out_table TABLE(value varchar(MAX)) 

     SET @sql = 'SELECT CONVERT(varchar(max), CAST(''' + @value + ''' AS ' + @type + '))' 

     INSERT @out_table 
     EXECUTE (@sql) 

     IF EXISTS (SELECT 1 FROM @out_table WHERE value = @value) 
      RETURN 1 

     RETURN 0 
    END TRY 
    BEGIN CATCH 
     RETURN 0 
    END CATCH 

END 

GO 

Ora è possibile chiamare che con la stringa passata e il tipo desiderato e il proc restituisce 1 per il successo e 0 per il fallimento

DECLARE @ret int 

-- This returns 0 - Fail 
EXEC @ret = p_try_cast 'integer', '1.5' 

-- This returns 1 - Success 
EXEC @ret = p_try_cast 'integer', '1.5' 

-- This returns 0 - Fail 
EXEC @ret = p_try_cast 'char(4)', 'HELLO' 

-- This returns 1 - Success 
EXEC @ret = p_try_cast 'char(4)', 'HELL' 
Problemi correlati