2009-08-06 37 views
5

Attualmente ho una tabella con una colonna come varchar. Questa colonna può contenere numeri o testo. Durante determinate query mi trattano come una colonna bigint (faccio un join tra essa e una colonna in un'altra tabella che è bigint)Errore durante la conversione del tipo di dati varchar

Finché c'erano solo i numeri in questo campo non ha avuto problemi, ma al minuto anche una riga aveva il testo e non i numeri in questo campo ho ottenuto un "Errore nella conversione del tipo di dati varchar in bigint." errore anche se nella parte WHERE mi sono accertato che nessuno dei campi di testo si presentasse.

per risolvere questo ho creato una vista come segue:

SELECT  TOP (100) PERCENT ID, CAST(MyCol AS bigint) AS MyCol 
FROM   MyTable 
WHERE  (isnumeric(MyCol) = 1) 

Ma anche se la vista mostra solo le righe con valori numerici e getta Mycol a bigint ho ancora un Errore che converte il tipo di dati varchar a bigint quando si esegue la seguente query:

SELECT * FROM MyView where mycol=1 

quando si fa query la vista non dovrebbe sapere cosa sta succedendo dietro di essa! dovrebbe semplicemente vedere due campi bigint! (see attached image, anche lo studio di gestione mssql mostra i campi vista come bigint)

+1

Personalmente penso che tu stia risolvendo il problema sbagliato. Qualcosa non va nella progettazione dello schema/database se si utilizza una colonna per due scopi diversi. –

+1

Sì, lo so, ma l'intero sistema è troppo lungo per apportare importanti cambiamenti ora – adinas

risposta

0

Hai provato a convertire il campo bigint di altre tabelle in varchar? Per quanto mi riguarda, ha senso eseguire una conversione più robusta ... Non dovrebbe influire troppo sulle prestazioni se il campo varchar è indicizzato.

+0

Questa potrebbe essere una soluzione, ma quello che mi ha davvero intrigato era ottenere l'errore sulla vista anche se aveva solo campi bigint – adinas

0

Considera di creare un campo bigint ridondante per contenere il valore intero di af MyCol.

È possibile quindi indicizzare il nuovo campo per accelerare il join.

+0

Ciò significherebbe cambiare grandi parti del mio progetto per selezionare il campo corretto ogni volta ... – adinas

0

Provare a effettuare la selezione in 2 fasi.

innanzitutto creare una vista che seleziona tutte le colonne in cui il mio colore è numerico.

Quindi eseguire una selezione in quella vista in cui si esegue il cast del campo varchar.

L'altra cosa che puoi guardare è il tuo progetto di tabelle per rimuovere la necessità del cast.

EDIT

  • Sono alcuni dei numeri più grandi di bigint?
  • Ci sono spazi, in testa, in coda o nel numero?
  • Ci sono caratteri di formato? Punti decimali?
+0

Provato. Ho ancora lo stesso errore anche quando si interroga la seconda vista – adinas

1

Idealmente, si vuole cercare di evitare la memorizzazione dei dati in questo modulo - varrebbe la pena dividere i dati BIGINT in una colonna separata per le prestazioni e la facilità di interrogazione.

Tuttavia, è possibile eseguire un JOIN come questo esempio. Nota, sono non utilizzando ISNUMERIC() per determinare se si tratta di un BIGINT valido perché ciò convaliderebbe valori errati che causerebbero un errore di conversione (ad esempio numeri decimali).

DECLARE @MyTable TABLE (MyCol VARCHAR(20)) 
DECLARE @OtherTable TABLE (Id BIGINT) 

INSERT @MyTable VALUES ('1') 
INSERT @MyTable VALUES ('Text') 
INSERT @MyTable VALUES ('1 and some text') 
INSERT @MyTable VALUES ('1.34') 
INSERT @MyTable VALUES ('2') 
INSERT @OtherTable VALUES (1) 
INSERT @OtherTable VALUES (2) 
INSERT @OtherTable VALUES (3) 

SELECT * 
FROM @MyTable m 
    JOIN @OtherTable o ON CAST(m.MyCol AS BIGINT) = o.Id 
WHERE m.MyCol NOT LIKE '%[^0-9]%' 

Aggiornamento: L'unico modo che riesco a trovare per farlo funzionare per avere una clausola WHERE per un valore intero specifico senza fare un altro CAST() sulla colonna presumibilmente bigint nella clausola in cui troppo, è quello di utilizzare una funzione definita dall'utente:

CREATE FUNCTION [dbo].[fnBigIntRecordsOnly]() 
RETURNS @Results TABLE (BigIntCol BIGINT) 
AS 
BEGIN 
INSERT @Results 
SELECT CAST(MyCol AS BIGINT) 
FROM MyTable 
WHERE MyCol NOT LIKE '%[^0-9]%' 
RETURN 
END 

SELECT * FROM [dbo].[fnBigIntRecordsOnly]() WHERE BigIntCol = 1 

io in realtà non credo che questa è una grande idea prestazione saggia, ma è una soluzione

0

Prova ad usare questo:

Questo dovrebbe funzionare poiché la selezione interna restituisce solo valori numerici e la selezione esterna può quindi convertire tutti i valori dalla prima selezione in un valore numerico. Sembra che nel proprio codice SQL provi a eseguire il cast prima di eseguire la funzione isnumerica (forse ha qualcosa a che fare con l'ottimizzazione).

+0

La query restituisce effettivamente solo le righe con i numeri. ma quando lo trasformo in una vista e interrogando la vista ottengo lo stesso 'Errore nella conversione del tipo di dati varchar in bigint' (solo quando faccio "dove mycol = 1" ottengo l'errore) – adinas

1

Per rispondere alla domanda sul messaggio di errore: quando si fa riferimento a un nome di vista in un'altra query (supponendo che sia una visualizzazione tradizionale non una vista materializzata), SQL Server sostituisce in modo efficace la definizione della vista nella query di consumo e poi lo esegue.

Il vantaggio di questa operazione è che l'ottimizzatore di query può fare un lavoro molto meglio se si vede l'intera query, invece di ottimizzare la vista separatamente come una "scatola nera".

Una conseguenza è che se si verifica un errore, le descrizioni di errore possono sembrare confuso perché il motore di esecuzione accede tabelle sottostanti per i dati, non la vista.

io non sono sicuro di come materializzate vengono trattati vista, ma immagino che siano trattati come tavoli, dal momento che i dati memorizzati nella cache di vista è nel database.

Detto questo, sono d'accordo con le risposte precedenti - si dovrebbe ripensare il vostro disegno tavolo e separare i valori dei dati di testo e numeri interi in colonne separate.

1

provare a cambiare l'immagine per questo:

SELECT TOP 100 PERCENT ID, 
Cast(Case When IsNumeric(MyCol) = 1 Then MyCol Else null End AS bigint) AS MyCol 
FROM MyTable 
WHERE (IsNumeric(MyCol) = 1) 
+0

scusa questa query restituita lo stesso 'Errore nella conversione del tipo di dati varchar to bigint 'err – adinas

+0

Quale versione di SQL Server stai usando? Ho provato questo in SQL2000 e fino senza problemi. Felice che tu abbia trovato una soluzione, comunque :) – MartW

2

OK. Alla fine ho creato una vista che funziona:

SELECT TOP (100) PERCENT id, CAST(CASE WHEN IsNumeric(MyCol) = 1 THEN MyCol ELSE NULL END AS bigint) AS MyCol 
FROM   dbo.MyTable 
WHERE  (MyCol NOT LIKE '%[^0-9]%') 

Grazie alla AdaTheDev e CodeByMoonlight. Ho usato le tue due risposte per arrivare a questo. (Grazie anche agli altri repeater)

Ora, quando mi unisco ad altri colts bigint o faccio qualcosa come "SELECT * FROM MyView where mycol = 1" restituisce il risultato corretto senza errori. La mia ipotesi è che il cast nella query stessa causa la query optimizer di non guardare la tabella originale come Christian Hayter detto può essere in corso con le altre viste

Problemi correlati