Null許容列でデータベーステーブルを検索したいのですが。時々私が探している値はそれ自体がNULLです。 Nullは何もないので、NULLであっても、
where MYCOLUMN=SEARCHVALUE
失敗します。今私はに頼らなければなりません
where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))
それを言う簡単な方法はありますか?
(問題がある場合はOracleを使用しています)
IsNullやNVLなどを実行できますが、これにより、エンジンがより多くの作業を実行できるようになります。関数を呼び出して列変換を行い、結果を比較する必要があります。
持っているものを使う
where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))
@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%増加します。そのため、あるコードが別のコードほど整然としていない、またはエレガントに見えない場合でも、大幅に効率的になる可能性があります。この手順を複数回実行しましたが、結果は毎回ほぼ同じでした。アンディへの称賛...
単純かどうかはわかりませんが、たまに使ったことがある
WHERE ISNULL(MyColumn, -1) = ISNULL(SearchValue, -1)
「-1」を列タイプに有効な値で置き換えますが、実際にはデータで検出されない可能性があります。
注:私はOracleではなくMS SQLを使用しているため、「ISNULL」が有効かどうかは不明です。
Expert Oracle Database Architecture で見た:
WHERE DECODE(MYCOLUMN, SEARCHVALUE, 1) = 1
NVLを使用して、次のように両側でnullをいくつかのダミー値に置き換えます。
WHERE NVL(MYCOLUMN,0) = NVL(SEARCHVALUE,0)
実行されたクエリの観点からおそらく最適である別の代替方法何らかのクエリ生成を実行している場合にのみ役立ちますは、検索値に基づいて必要な正確なクエリを生成することです。
擬似コードが続きます。
if (SEARCHVALUE IS NULL) {
condition = 'MYCOLUMN IS NULL'
} else {
condition = 'MYCOLUMN=SEARCHVALUE'
}
runQuery(query,condition)
帯域外の値が考えられる場合:
where coalesce(mycolumn, 'out-of-band')
= coalesce(searchvalue, 'out-of-band')
これは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
試す
WHERE NVL(mycolumn,'NULL') = NVL(searchvalue,'NULL')
これは、レポートを駆動する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)
私はあなたが持っているものは大丈夫だと思います。あなたは多分使用できます:
where NVL(MYCOLUMN, '') = NVL(SEARCHVALUE, '')