web-dev-qa-db-ja.com

Oracle null == nullを決定します

Null許容列でデータベーステーブルを検索したいのですが。時々私が探している値はそれ自体がNULLです。 Nullは何もないので、NULLであっても、

where MYCOLUMN=SEARCHVALUE 

失敗します。今私はに頼らなければなりません

where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))

それを言う簡単な方法はありますか?

(問題がある場合はOracleを使用しています)

44
James Curran

IsNullやNVLなどを実行できますが、これにより、エンジンがより多くの作業を実行できるようになります。関数を呼び出して列変換を行い、結果を比較する必要があります。

持っているものを使う

where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))
68
Andy Lester

@Andy Lesterは、クエリの元の形式はNVLを使用するよりも効率的であると断言します。そのアサーションをテストすることにしました。

    SQL> DECLARE
      2    CURSOR B IS
      3       SELECT batch_id, equipment_id
      4         FROM batch;
      5    v_t1  NUMBER;
      6    v_t2  NUMBER;
      7    v_c1  NUMBER;
      8    v_c2  NUMBER;
      9    v_b   INTEGER;
     10  BEGIN
     11  -- Form 1 of the where clause
     12    v_t1 := dbms_utility.get_time;
     13    v_c1 := dbms_utility.get_cpu_time;
     14    FOR R IN B LOOP
     15       SELECT COUNT(*)
     16         INTO v_b
     17         FROM batch
     18        WHERE equipment_id = R.equipment_id OR (equipment_id IS NULL AND R.equipment_id IS NULL);
     19    END LOOP;
     20    v_t2 := dbms_utility.get_time;
     21    v_c2 := dbms_utility.get_cpu_time;
     22    dbms_output.put_line('For clause: WHERE equipment_id = R.equipment_id OR (equipment_id IS NULL AND R.equipment_id IS NULL)');
     23    dbms_output.put_line('CPU seconds used: '||(v_c2 - v_c1)/100);
     24    dbms_output.put_line('Elapsed time: '||(v_t2 - v_t1)/100);
     25  
     26  -- Form 2 of the where clause
     27    v_t1 := dbms_utility.get_time;
     28    v_c1 := dbms_utility.get_cpu_time;
     29    FOR R IN B LOOP
     30       SELECT COUNT(*)
     31         INTO v_b
     32         FROM batch
     33        WHERE NVL(equipment_id,'xxxx') = NVL(R.equipment_id,'xxxx');
     34    END LOOP;
     35    v_t2 := dbms_utility.get_time;
     36    v_c2 := dbms_utility.get_cpu_time;
     37    dbms_output.put_line('For clause: WHERE NVL(equipment_id,''xxxx'') = NVL(R.equipment_id,''xxxx'')');
     38    dbms_output.put_line('CPU seconds used: '||(v_c2 - v_c1)/100);
     39    dbms_output.put_line('Elapsed time: '||(v_t2 - v_t1)/100);
     40  END;
     41  /


    For clause: WHERE equipment_id = R.equipment_id OR (equipment_id IS NULL AND R.equipment_id IS NULL)
    CPU seconds used: 84.69
    Elapsed time: 84.8
    For clause: WHERE NVL(equipment_id,'xxxx') = NVL(R.equipment_id,'xxxx')
    CPU seconds used: 124
    Elapsed time: 124.01

    PL/SQL procedure successfully completed

    SQL> select count(*) from batch;

  COUNT(*)
----------
     20903

SQL> 

アンディの正しさを知って驚いた。 NVLソリューションを実行するには、コストが約50%増加します。そのため、あるコードが別のコードほど整然としていない、またはエレガントに見えない場合でも、大幅に効率的になる可能性があります。この手順を複数回実行しましたが、結果は毎回ほぼ同じでした。アンディへの​​称賛...

36
DCookie

単純かどうかはわかりませんが、たまに使ったことがある

WHERE ISNULL(MyColumn, -1) = ISNULL(SearchValue, -1)

「-1」を列タイプに有効な値で置き換えますが、実際にはデータで検出されない可能性があります。

注:私はOracleではなくMS SQLを使用しているため、「ISNULL」が有効かどうかは不明です。

13
Chris Shaffer

Expert Oracle Database Architecture で見た:

WHERE DECODE(MYCOLUMN, SEARCHVALUE, 1) = 1
13
Peter Meinl

NVLを使用して、次のように両側でnullをいくつかのダミー値に置き換えます。

WHERE NVL(MYCOLUMN,0) = NVL(SEARCHVALUE,0)
8
JosephStyons

実行されたクエリの観点からおそらく最適である別の代替方法何らかのクエリ生成を実行している場合にのみ役立ちますは、検索値に基づいて必要な正確なクエリを生成することです。

擬似コードが続きます。

if (SEARCHVALUE IS NULL) {
    condition = 'MYCOLUMN IS NULL'
} else {
    condition = 'MYCOLUMN=SEARCHVALUE'
}
runQuery(query,condition)
6
Vinko Vrsalovic

帯域外の値が考えられる場合:

where coalesce(mycolumn, 'out-of-band') 
    = coalesce(searchvalue, 'out-of-band')
2
Ted

これはOracleでも機能します。

WHERE MYCOLUMN || 'X'  = SEARCHVALUE || 'X'

ORを使用したIS NULLテストに勝る状況がいくつかあります。

また、DECODEを使用するとNULLとNULLを照合できることにも驚きました。

WITH 
TEST AS
(
    SELECT NULL A FROM DUAL
)
SELECT DECODE (A, NULL, 'NULL IS EQUAL', 'NULL IS NOT EQUAL')
FROM TEST
1
EvilTeach

試す

WHERE NVL(mycolumn,'NULL') = NVL(searchvalue,'NULL')
1
DCookie

これは、レポートを駆動するOracleの機能を使用している場合によくある状況です。ユーザーが値を入力して結果を制限したり、空白のままにしてすべてのレコードを返すことができるようにしたいと考えています。これは私が使用したものであり、私たちにとってはうまくいきました。

WHERE rte_pending.ltr_rte_id = prte_id
  OR ((rte_pending.ltr_rte_id IS NULL OR rte_pending.ltr_rte_id IS NOT NULL)
      AND prte_id IS NULL)
0
Jason Winger

私はあなたが持っているものは大丈夫だと思います。あなたは多分使用できます:

where NVL(MYCOLUMN, '') = NVL(SEARCHVALUE, '')
0
Carl