2013-07-25 14 views
5

Stavo lavorando con una query sql SAS proc e ho scoperto qualcosa di strano. In primo luogo, ho provato questo semplice query:Comportamento dispari su Somma (Ottenere overflow numerico)

proc sql; 
    CREATE TABLE test AS 
    (SELECT 
     YEAR(dt) AS yr, 
     MONTH(dt) AS mo, 
     SUM(val) AS total 
    FROM 
     mydb1234.myTable 
    WHERE 
     myDate BETWEEN x AND y 
    GROUP BY 
     yr, mo); 
run; 

Quando eseguo questa query, ricevo questo errore:

ERROR: Teradata row not delivered (trget): Numeric overflow occurred during computation. 

Da quello che posso dire, questo accade quando il mio valore riassunto diventa troppo grande per essere nel tipo di dati che sta cercando di utilizzare proc sql.

ho deciso che vorrei solo dividere il numero che sto somma:

SUM(val/1000) AS total 

Tuttavia, questo ha avuto conseguenze impreviste. Il totale sommato era inferiore a una somma manuale che ho fatto in Excel. Il totale si abbassa man mano che aggiungo altri ordini di grandezza al divisore. Immagino che questo stia eliminando valori più piccoli che cerca di sommare (ad esempio 10/1000 vs 108/10000, ecc.) Che non raggiungono mai la somma e sono invece letti come zero.

C'è un modo per forzare questo sql proc a creare una tabella utilizzando una lunghezza del campo che può contenere i miei valori totali? Sono nell'intervallo di miliardi e miliardi di miliardi, quindi non penso a niente di insolito. Ero curioso di vedere cosa pensavi.

+0

Questo non è un problema specifico SAS, non credo. SAS non ti darà un overflow; a meno che tu non sia in numeri così folli che non potrebbe essere memorizzato in modo impreciso a 64 bit, comunque, il che non è certamente il caso. Se hai generato un numero di> 15 cifre significative, potrebbe iniziare a perdere significato, ma non ti darà alcuna indicazione che lo stia facendo. – Joe

+0

Come funziona l'interfaccia con i teradata? Esiste un 'libname' su un server teradata, o è passato, o qualcos'altro? – Joe

+0

C'è una biblioteca e mi riferimento in questo modo: 'DA mydb1234.myTable' Dove mydb1234 è un' libref' –

risposta

1

ho intenzione di indagare i problemi di fondo che ha causato questo problema come Joe ha sottolineato prima. Tuttavia, ho trovato una soluzione rapida che risolve il problema di root. Ho usato la seguente riga per il mio SUM

Round((SUM(myField))/1) format=13. 
5

Sospetto che ciò che sta accadendo è che la query viene rimandata su Teradata tramite pass-through implicito e, di conseguenza, qualcosa non funziona in Teradata. È possibile che tu abbia bisogno che la query esegua esplicitamente il cast della somma come qualcosa di diverso da come viene castato.

Per vedere cosa sta accadendo esattamente, utilizzare OPTIONS SASTRACE; dalla documentazione si consiglia di provare

options sastrace=',,,d' sastraceloc=saslog nostsuffix; 

anche se potrebbe essere necessario andare in giro con le opzioni alcuni. Questo mostrerà la query esatta che viene eseguita in Teradata. Prova la stessa query direttamente in Teradata e verifica se è possibile evitare che abbia lo stesso problema.

Una volta capito, è possibile eseguire la query corretta utilizzando il pass-through esplicito; cioè

proc sql; 
connect to teradata [options, same as on the libname usually]; 
create table mydata as select * from connection to teradata (
    ... actual teradata syntax ... 
); 
quit; 
+0

Questo ha senso, ci proverò, grazie !! –

0

In queste situazioni os tipo è sempre il tipo di dati che è stato definito per la colonna val nella tabella Teradata che sta causando il problema 'overflow numerico'. (Sto assumendo val è definito come Integer tipo che può contenere fino a +/- 2.1billion)

Prova questa,

proc sql; 
    CREATE TABLE test AS 
    (SELECT 
     YEAR(dt) AS yr, 
     MONTH(dt) AS mo, 
     SUM(cast(val as dec(32,0))) AS total 
    FROM 
     mydb1234.myTable 
    WHERE 
     myDate BETWEEN x AND y 
    GROUP BY 
     yr, mo); 
QUIT; 

Nel codice precedente, SUM(cast(val as dec(32,0))) viene dapprima convertendo (colata, ufficialmente) la Colonna val a un tipo di dati che può contenere più di qualche miliardo e quindi sommare. La colonna sommata total sarà di dec(32,0) e SAS è più che capace di gestire numeri così grandi.

+0

Non penso che sarebbe compilato in SAS, dal momento che il cast non è una funzione SAS, vero? Funzionerebbe in passthrough esplicito. – Joe

+0

Se si esegue l'SQL come passaggio (sfruttando l'elaborazione del database) su Teradata, l'SQL in questa risposta verrà eseguito direttamente su Teradata. –

+0

Certo, ma la risposta sopra non lo fa. :) La maggior parte delle volte "fare leva sull'elaborazione del database" non è molto importante in quanto SAS lo fa in gran parte (converte il codice SAS nell'elaborazione in-database); che dopo tutto è quello che ci sta mettendo nei guai, in primo luogo qui. – Joe