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.

War es hilfreich?

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

ist
AND 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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top