2012-11-01 6 views
5

ho una visione del genere:DOVE su Visualizza Alias ​​causa l'errore

SELECT location, CAST(SUBSTRING(location, 9, 4) AS int) AS ProcessCode 
FROM dbo.asset 
WHERE (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE')) 
AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_') 

Se io lo chiamo così, funziona:

SELECT * FROM FooView 

Tuttavia, se posso aggiungere una clausola WHERE:

SELECT * FROM FooView WHERE ProcessCode > 0 

ottengo questo errore:

Conversion failed when converting the varchar value '-01-' to data type int.

Perché? Poiché la posizione deve essere nel formato 1-2-100-0800-A, non vedo come possa esserci un errore di conversione. È possibile che CAST non riesca prima che lo WHERE abbia la possibilità di filtrare i risultati? Se è così, allora perché funziona la prima query?

EDIT - work-around

Ho appena avuto un collega suggerire un buon work-around. Funziona, ma non spiega ancora perché il problema iniziale.

questo è nel SELEZIONA per ProcessCode:

CASE WHEN location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_' 
THEN CAST(SUBSTRING(location, 9, 4) AS int) ELSE 0 END AS ProcessCode, 
+0

per interesse quale versione di SQL Server? e quale tipo di colonna è Location? –

+0

SQL Server 2012. La posizione è varchar (24). –

risposta

4

modificare la visualizzazione a questo

0.123.516,41 mila
SELECT location, 
     CASE WHEN SUBSTRING(location, 9, 4) > '' 
      AND SUBSTRING(location, 9, 4) NOT LIKE '%[^0-9]%' THEN 
       CAST(SUBSTRING(location, 9, 4) AS int) END AS ProcessCode 
    FROM dbo.asset 
WHERE (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE')) 
    AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_') 

Vai a questa Connect item

SQL Server è libero di valutare la WHERE/clausola SELECT nell'ordine in cui decide è ottimizzato. Una vista a meno che non sia materializzata come VISTA INDICE è espansa alla query esterna, quindi la tua clausola WHERE viene effettivamente semplificata nella vista, ad esempio

SELECT * FROM FooView WHERE ProcessCode > 0 
-- is really seen as 
SELECT location, CAST(SUBSTRING(location, 9, 4) AS int) AS ProcessCode 
FROM dbo.asset 
WHERE (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE')) 
AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_') 
AND CAST(SUBSTRING(location, 9, 4) AS int) > 0 ---- << Expanded inline 

Poiché l'espressione è usata sia per le clausole SELECT e WHERE, sembra che SQL Server ha deciso di risolvere l'espressione nella clausola SELECT prima nel recupero originale. Questo può essere facilmente visto usando Ctrl-L per visualizzare il piano di esecuzione della query. Si vedrà che SQL Server effettua un singolo recupero dalla tabella, prendendo 2 espressioni, ovvero e CAST(SUBSTRING(location, 9, 4) AS int) allo stesso tempo.

+0

Grazie. Questo è un po 'come la soluzione alla mia domanda. Vedi la mia modifica. Mentre fornisce un'alternativa di lavoro, non spiega il comportamento originale. –

+0

Ho aggiunto una spiegazione. Inoltre, la tua soluzione è in qualche modo dipendente dai dati perché non stai testando il bit che viene castato, ma piuttosto il pattern dei dati della colonna. – RichardTheKiwi

+0

Questo spiegherebbe il comportamento. Se la SELEZIONE viene valutata prima che WHERE abbia avuto la possibilità di filtrare i dati non validi, ciò causerebbe l'errore. È questo che stai dicendo? –

0

il cast non riesce prima del quale, sì. In effetti il ​​cast fallisce prima del SELECT stesso, se non sbaglio, subito dopo guarda la tabella e determina la forma della sottostringa sotto la colonna location.

Sembra che tu stia facendo un errore di calcolo su cosa viene restituito la sottostringa, perché se dici che il formato è effettivamente 1-2-100-0800-A, allora SUBSTRING (str, 9, 4) dovrebbe restituire 0800 , ma restituisce '-1-', che non è un INT.

seziona la tua frase in quelle più piccole. guarderei prima il risultato di SUBSTRING.

speranza che ha aiutato.

+1

Grazie, ma non penso di sbagliare l'analisi di cosa restituisce la sottostringa. Penso che l'intera questione sia che il cast sta accadendo prima del filtro WHERE, ma potrei sbagliarmi. Se questo è il caso, allora perché funziona la prima query? –

1

Questo funziona su SQL Server 2008, qualcos'altro funky sta succedendo ...

create view myview 
AS 
SELECT CAST(SUBSTRING('1-2-100-0800-A', 9, 4) AS int) as ProcessCode 
Where '1-2-100-0800-A' LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_' 

GO 

SELECT * FROM myview WHERE ProcessCode > 0 

Ecco il violino>http://sqlfiddle.com/#!3/3bcfd/2

Modifica Potrebbe essere l'ordine di esecuzione, come suggerito qui di seguito, provare con un a (ottimizzata con id)

SELECT location, CAST(SUBSTRING(location, 9, 4) AS int) AS ProcessCode 
FROM dbo.asset 
Where id in(
select id 
from dbo.asset 
WHERE (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE')) 
AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_') 
) 
+0

Penso che funzioni perché si sta testando solo con uno, un buon valore. Ci sono altri valori negativi che dovrebbero essere rimossi tramite la clausola WHERE. –

+0

puoi dare un esempio di un valore "cattivo"? –

+0

Certo, tutto ciò che non si adatta a questa espressione regolare: ALM00-00-06, 1-5-RMT, 1-0-DEV. –

Problemi correlati