46

null 許容列でデータベース テーブルを検索したいと考えています。検索している値自体が NULL である場合があります。Null は何にも等しいので、NULL であっても、

where MYCOLUMN=SEARCHVALUE 

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

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

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

(それが問題になる場合は、Oracleを使用しています)

4

11 に答える 11

72

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

持っているものを使う

where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))
于 2008-10-10T14:42:06.330 に答える
36

@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% 近く高くなります。したがって、あるコードが別のコードほど整頓されていない、またはエレガントに見えなくても、はるかに効率的である可能性があります。この手順を複数回実行しましたが、結果は毎回ほぼ同じでした。アンディへの​​称賛...

于 2008-10-10T16:12:03.653 に答える
14

Expert Oracle Database Architectureで私が見たもの:

WHERE DECODE(MYCOLUMN, SEARCHVALUE, 1) = 1
于 2011-03-14T20:17:55.947 に答える
13

もっと簡単かどうかはわかりませんが、時々使用しました

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

「-1」を、列タイプには有効であるが、実際にはデータ内に見つからない可能性が高い値に置き換えます。

注: 私は Oracle ではなく MS SQL を使用しているため、「ISNULL」が有効かどうかはわかりません。

于 2008-10-10T14:40:11.500 に答える
8

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

WHERE NVL(MYCOLUMN,0) = NVL(SEARCHVALUE,0)
于 2008-10-10T14:40:10.063 に答える
6

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

擬似コードが続きます。

if (SEARCHVALUE IS NULL) {
    condition = 'MYCOLUMN IS NULL'
} else {
    condition = 'MYCOLUMN=SEARCHVALUE'
}
runQuery(query,condition)
于 2008-10-10T14:46:10.427 に答える
2

試す

WHERE NVL(mycolumn,'NULL') = NVL(searchvalue,'NULL')
于 2008-10-10T14:39:52.967 に答える
2

帯域外の値が可能な場合:

where coalesce(mycolumn, 'out-of-band') 
    = coalesce(searchvalue, 'out-of-band')
于 2008-11-09T10:07:29.980 に答える
1

これは、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
于 2008-12-09T02:30:07.890 に答える
0

あなたが持っているものは大丈夫だと思います。あなたはおそらく使用することができます:

where NVL(MYCOLUMN, '') = NVL(SEARCHVALUE, '')
于 2008-10-10T14:42:25.863 に答える