2017-10-02 3 views
1

Ich habe gekämpft, um zu verstehen, warum diese Abfrage nicht funktioniert. Alle Partitionsnamen für diesen Besitzer haben Werte im Format 'R_DATE_20170831'. Aber die Abfrage unten gibt immer einen Fehler zurück ORA-01841 (voll) Jahr muss zwischen -4713 und +9999 liegen, und nicht 0 sein. Wenn ich jedes Datum Teil einzeln anzeigen, sind sie alle in diesem Bereich. Mein NLS_DATE_FORMAT zeigt einen Wert 'DD-MON-RR'.Was verursacht diesen Datumsvergleichsfehler?

SELECT COUNT(*) 
FROM dba_tab_partitions 
WHERE table_owner = 'myId' AND 
     TO_DATE(SUBSTR(partition_name,INSTR(partition_name,'_',1,2) + 1),'YYYYMMDD') < TRUNC(SYSDATE) - 10; 

Ich habe auch versucht, um die sysdate-10 eine TO_DATE mit geeigneten Masken setzen, aber immer noch den Fehler. Irgendeine Einsicht? Vielen Dank!

+0

Die Syntax, wie Sie es haben jetzt korrekt ist. Ich vermute, Sie fangen die fehlerhaften Zeilen nicht auf. Wie "zeige ich jedes Datum einzeln an"? Haben Sie beispielsweise zuerst überprüft, ob der SUBSTR-Teil, den Sie konvertieren, immer aus acht Zeichen besteht? ** Auch **: Bitte geben Sie Ihre genaue Oracle-Version (einschließlich Subversion - wie 12.1.0.2.0); In Oracle 12.2 gibt es eine neue Funktion, VALIDATE_CONVERSION, die diese Überprüfungen schnell durchführen kann. – mathguy

Antwort

2

Ich habe etwas ähnliches in SQL Server gesehen, verursacht durch die Tatsache, dass die WHERE Ausdrücke nicht unbedingt in Reihenfolge ausgewertet werden. Das würde bedeuten, dass andere Partitionen die arithmetische Datenlogik durchlaufen - und den Fehler verursachen.

CASE garantiert Reihenfolge der Auswertung. Funktioniert das?

SELECT COUNT(*) 
FROM dba_tab_partitions 
WHERE table_owner = 'myId' AND 
     (CASE WHEN table_owner = 'myId' 
      THEN TO_DATE(SUBSTR(partition_name, INSTR(partition_name, '_', 1, 2) + 1), 'YYYYMMDD') 
     END) < TRUNC(SYSDATE) - 10; 

Oder diese Version:

SELECT COUNT(*) 
FROM dba_tab_partitions 
WHERE table_owner = 'myId' AND 
     (CASE WHEN regexp_like(partition_name, '[^_]*_[^_*]_[0-9]{8}$' 
      THEN TO_DATE(SUBSTR(partition_name, INSTR(partition_name, '_', 1, 2) + 1), 'YYYYMMDD') 
     END) < TRUNC(SYSDATE) - 10; 
+0

Ich hätte den 'table_owner = 'myId'-Teil in eine Inline-Ansicht verschoben, aber ich mag diese CASE-Lösung. – kfinity

+0

Das ist in der Tat ein häufiges Problem - immer wenn ein Optimierer (Oracle oder anders) denkt, dass Push-Prädikate zu einer schnelleren Ausführung führen, können Sie diese Art von Verhalten sehen. Das OP sagt, dass, wenn er jedes Datum einzeln überprüft hat, alles in Ordnung war - aber das muss geprüft werden. Wie auch immer, gute Antwort! – mathguy

+0

Um "jeden Teil separat anzuzeigen", nahm ich nur die zwei Hauptteile der where-Klausel und bewegte sie in die select-Klausel, um sie anzuzeigen. Visuell waren beide ausgewählte Werte alle 9 Zeichen in einem DD-MMM-YY-Format, und viele der ersten Werte waren eindeutig scotto

Verwandte Themen