5

スタック オーバーフローの SQL 教祖様へ:

環境:オラクル

文字列を含むテーブル列で to_date 選択を実行できない理由を理解しようとしています。以下の例で、名前が Value の列を持つ tableZ には一連の文字列が含まれていることに注意してください。そのうちのいくつかは正しい形式です (たとえば、6/20/2010 00:00:00)。

テーブルZ

| Value              |
| __________________ |
| 6/21/2010 00:00:00 |
| Somestring         |
| Some Other strings |
| 6/21/2010 00:00:00 |
| 6/22/2010 00:00:00 |

以下の作品

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

これは次のようなものを返します(これは良いことです):

| somedate            |
| __________________  |
| 21.06.2010 00:00:00 |
| 21.06.2010 00:00:00 |
| 22.06.2010 00:00:00 |

以下は動作しません

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

戻ってきます:

ORA-01861: リテラルがフォーマット文字列と一致しません

ここで何が欠けていますか?簡単なメモ:

 ...
AND b.id = c.template_property_id 
AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL

どちらも機能しません。

ありがとう!!

日付範囲を選択するために、c.value で日付 BETWEEN クエリを実行できるようにすることを目標としています。

4

4 に答える 4

10

Oracle が where 句で見つかった条件を評価する順序は固定されていません。つまり、他の条件よりも先に TO_DATE を含む条件を評価することを選択できます。その場合、クエリは失敗します。これを防ぐには、ordered_predicates ヒントをクエリに追加しますが、パフォーマンスを向上させるために、追加の手動調整が必要になる場合があることに注意してください。

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

どうやらordered_predicates10gから廃止予定です。その場合、唯一のオプションは、オプティマイザーが最初にサブクエリを評価するように強制されるような方法でサブクエリを使用することだと思います(つまり、クエリを組み合わせることができません)。これを行う最も簡単な方法rownumは、内部クエリの where ステートメントを挿入することです。

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
于 2010-06-23T20:20:34.070 に答える
3

別の手法は、変換をCASEに埋め込むことです。例えば

SELECT * FROM table
WHERE col_a = '1'
AND case when col_a = '1' then to_date(col_b,'DD/MM/YYYY') end = trunc(sysdate)

ただし、句が複雑な場合、これは非常に高速になります。

于 2010-06-24T00:28:05.063 に答える
2
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;
/

テスト:

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
-------------------
于 2010-06-23T22:46:13.337 に答える
0

c.value が有効な形式であるかどうかを確認しますか?

AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL

? これは機能しません。別の方法でチェックを実行する必要があります。正規表現を使用できます(しばらく使用していなかったと思います)。データモデルで問題の行を識別できる場合はなおさらです。

于 2010-06-23T20:02:12.823 に答える