0

質問があります

SELECT DISTINCT ID 
  From ACCUSED 
 WHERE CAST(DATE_ENTERED AS date) BETWEEN '12-Apr-2013' and '12-Apr-2013'

このクエリは、「有効な月ではありません」というエラーを表示します

文字列の日付がnullでない他のテーブルに同じクエリを適用すると、正常に機能します。これはうまくいきます

SELECT DISTINCT ID 
  From Customer 
 WHERE CAST(DATE_ENTERED AS date) BETWEEN '12-Apr-2013' and '12-Apr-2013'
4

1 に答える 1

3

DATE_ENTEREDそれがVARCHAR2列であると仮定します

  1. 日付を文字列として保存しないでください。日付は列に格納する必要がありDATEます。間違ったデータ型を使用することが問題の原因であり、正しいデータ型を使用するようにデータ モデルを修正することが適切な解決策です。
  2. 文字列を日付に変換する場合はTO_DATE、明示的な書式マスクを指定して関数を使用します。CASTまたはフォーマット マスクのTO_DATEない は、セッションNLS_DATE_FORMATがフォーマット マスクとして指定するものをすべて引き起こします。これはセッションごとに異なる可能性があるため、コードが一部のクライアントの一部のユーザーに対しては機能し、他のユーザーまたは他のクライアントに対しては機能しない可能性があり、バグを見つけるのは必然的に困難になります。
  3. ADATEは常にDATE、文字列ではなく別のものと比較する必要があります。日付を文字列と比較すると、Oracle は暗黙的な変換を行う必要があり、これもまたセッションを使用し、NLS_DATE_FORMATコードの信頼性を低下させます。リテラル日付を指定する場合は、TO_DATE関数を使用して文字列を日付に変換する (明示的な書式マスクを使用) か、ANSI 日付リテラルを使用します。
  4. IDそれが主キーであると仮定するとDISTINCT、せいぜい無意味であり、最悪の場合、Oracle に不要なソートを強いることになります。

最初の最善の解決策は、データ モデルを変更してDATE_ENTERED、実際にはDATE. これを行うと、クエリは (ANSI 日付リテラルを使用して) になります。

SELECT id
  FROM accused
 WHERE date_entered BETWEEN date '2013-04-12' and date '2013-04-12'

または明示的にTO_DATE

SELECT id
  FROM accused
 WHERE date_entered BETWEEN to_date( '12-Apr-2013', 'DD-Mon-YYYY' ) 
                        AND to_date( '12-Apr-2013', 'DD-Mon-YYYY' ) 

何らかの理由で、間違ったデータ モデルで立ち往生している場合、保存したすべての文字列が実際に有効であれば、次のようなことができます。

SELECT id
  FROM accused
 WHERE to_date( date_entered, 'DD-Mon-YYYY' ) BETWEEN to_date( '12-Apr-2013', 'DD-Mon-YYYY' ) 
                                                  AND to_date( '12-Apr-2013', 'DD-Mon-YYYY' ) 

ただし、取得しているエラーを考えると、テーブルに格納されている文字列が有効な日付を表していない行がテーブルに少なくともいくつかある可能性が非常に高いようです。問題は、どの行が無効であるかを把握しようとすることになります。1 つのオプションは、新しい関数を作成することです。

CREATE OR REPLACE FUNCTION my_to_date( p_date_str    IN VARCHAR2,
                                       p_format_mask IN VARCHAR2 )
  RETURN DATE
IS
  l_date DATE;
BEGIN
  l_date := to_date( p_date_str, p_format_mask );
  RETURN l_date;
EXCEPTION
  WHEN others THEN
    RETURN NULL;
END;

次に、クエリでその関数を使用します。

SELECT *
  FROM accused
 WHERE date_entered IS NOT NULL
   AND my_to_date( date_entered, 'DD-Mon-YYYY' ) IS NULL

DATE_ENTEREDは、 が形式の有効な日付を表していないすべての行を返しますDD-Mon-YYYY。最終的にこのデータを修正する必要があります。無効なデータを含む行を無視しても問題ない場合は、クエリを記述できます

SELECT id
  FROM accused
 WHERE my_to_date( date_entered, 'DD-Mon-YYYY' ) BETWEEN to_date( '12-Apr-2013', 'DD-Mon-YYYY' ) 
                                                     AND to_date( '12-Apr-2013', 'DD-Mon-YYYY' ) 
于 2013-04-12T08:01:03.693 に答える