Wörtliche nicht Formatstring für Oracle SQL to_date auf einem String-Spalte passen
Frage
Liebe SQL-Gurus von Stack-Überlauf:
Umwelt: Oracle
Ich versuche zu verstehen, warum ich nicht eine to_date Auswahl auf einer Tabellenspalte, die Strings enthalten tun können. Hinweis tableZ mit einer Spalte von namen Wert im Beispiel unten enthält eine Reihe von Strings, von denen einige sind das richtige Format, beispielsweise 2010.06.20 00.00.00.
tableZ
| Value |
| __________________ |
| 6/21/2010 00:00:00 |
| Somestring |
| Some Other strings |
| 6/21/2010 00:00:00 |
| 6/22/2010 00:00:00 |
Die folgenden Werke
SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate
FROM tableX a, tableY b, tableZ c
WHERE Lower(a.name) = 'somedate'
AND a.id = b.other_id
AND b.id = c.new_id
Das gibt so etwas wie (was gut ist):
| somedate |
| __________________ |
| 21.06.2010 00:00:00 |
| 21.06.2010 00:00:00 |
| 22.06.2010 00:00:00 |
Die folgenden funktioniert nicht
SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate
FROM properties$aud a, template_properties$aud b, consumable_properties$aud c
WHERE Lower(a.name) = 'somedate'
AND a.id = b.property_id
AND b.id = c.template_property_id
AND To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') IS NOT NULL
kommt zurück mit:
ORA-01861: wörtliche Format-String entspricht nicht
Was bin ich hier? Nur eine kurze Anmerkung:
...
AND b.id = c.template_property_id
AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL
funktioniert auch nicht.
Danke !!
Ziel in der Lage sein Datum zwischen Abfragen auf c.value zu tun, um Datumsbereiche zu wählen.
Lösung
Die Reihenfolge, dass Oracle die Bedingungen in der where-Klausel gefunden wertet ist nicht festgelegt. Das heißt, dass es wählen kann den Zustand enthält TO_DATE vor den anderen Kriterien zu bewerten, in welchem ??Fall die Abfrage fehl. Um zu verhindern, dass addieren sich die ordered_predicates auf Ihre Frage andeuten, aber beachten Sie, dass diese Abstimmung manuell zusätzliche erfordern Leistung zu verbessern.
SELECT /*+ ordered_predicates */
To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate
FROM properties$aud a,
template_properties$aud b,
consumable_properties$aud c
WHERE Lower(a.name) = 'somedate'
AND a.id = b.property_id
AND b.id = c.template_property_id
AND To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') IS NOT NULL
Offenbar ordered_predicates
ist veraltet mit 10 g beginnen. In diesem Fall denke ich, die einzige Möglichkeit ist es, eine Unterabfrage in einer solchen Art und Weise zu verwenden, dass Optimierer sie zu bewerten gezwungen wird zuerst (das heißt es nicht um die Abfragen kombinieren). Der einfachste Weg, dies zu tun ist rownum
in der where-Anweisung von der inneren Abfrage zu setzen.
SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate
FROM (SELECT value
FROM properties$aud a,
template_properties$aud b,
consumable_properties$aud c
WHERE Lower(a.name) = 'somedate'
AND a.id = b.property_id
AND b.id = c.template_property_id
AND rownum > 0)
WHERE To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') IS NOT NULL
Andere Tipps
create or replace function to_date_or_null(v_str_date in varchar2
, v_str_fmt in varchar2 default null) return date as
begin
if v_str_fmt is null then
return to_date(v_str_date);
else
return to_date(v_str_date, v_str_fmt);
end if;
exception
when others then
return null;
end to_date_or_null;
/
Test:
SQL> select to_date_or_null('2000-01-01', 'YYYY-MM-DD') from dual -- Valid;
TO_DATE_OR_NULL('20
-------------------
2000-01-01 00:00:00
SQL> select to_date_or_null('Not a date at all') from dual -- Not Valid;
TO_DATE_OR_NULL('NO
-------------------
SQL> select to_date_or_null('2000-01-01') from dual -- Valid matches my NLS settings;
TO_DATE_OR_NULL('20
-------------------
2000-01-01 00:00:00
SQL> select to_date_or_null('01-Jan-00') from dual -- Does not match my NLS settings;
TO_DATE_OR_NULL('01
-------------------
Eine andere Technik, um die Umwandlung in einem CASE einbetten. Zum Beispiel
SELECT * FROM table
WHERE col_a = '1'
AND case when col_a = '1' then to_date(col_b,'DD/MM/YYYY') end = trunc(sysdate)
Das wird wirklich hässlich schnell, wenn die Klauseln allerdings kompliziert.
Möchten Sie überprüfen möchten, ob c.value ein gültiges Format mit
istAND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL
? Das wird nicht funktionieren, müssen Sie die Prüfung auf andere Weise durchzuführen. Sie könnten einen regulären Ausdruck verwenden (ich denke, sie nicht in einer Weile benutzt). Noch besser wäre es, wenn Ihr Datenmodell erlaubt es dir, die Zeilen in Frage zu erkennen.