LEFT JOINの条件式で=’’を使用した場合、なぜレコードを取得できないのか?

このQ&Aのポイント
  • LEFT JOINの条件式で空文字('')を使用すると、外部結合しているにもかかわらず0件になることがあります。
  • 右辺の値が空文字の場合、NULLとして扱われるため、JOIN条件での一致が起きず、結果的に取得できないことがあります。
  • 空文字を使用する代わりに、適切な値を指定することで、正常にレコードを取得することができます。
回答を見る
  • ベストアンサー

LEFT JOINの条件式で=’’を使用した場合

以下のSQLを実行した場合、レコードを1件取得して欲しいのですが、 なぜか上手く取得できません。 ご存知の方がいらっしゃいましたら、教えてください。 -- SQL1 --------------------------------------------------- select   MAIN.MAIN_NAME,   nvl(SUB1.CODE is NULL, 0) as SUB_CODE1,   nvl(SUB2.CODE is NULL, 0) as SUB_CODE2 from   MAIN_TABLE MAIN    left join SUB_TABLE SUB1 on MAIN.CODE = SUB1.CODE                    and SUB1.ZYOUKEN = '1'    (1)    left join SUB_TABLE SUB2 on MAIN.CODE = SUB2.CODE                    and SUB2.ZYOUKEN = ''     (2) where   MAIN.CODE = 'XXX' ----------------------------------------------------------- 質問1. どうも、(2)の部分を空文字(?)ではなく何か値を入れると正常に1件 取得できるようなのですが、なぜ外部結合しているにもかかわらず 0件になってしまうのかが良く分かりません。 質問2. やはり条件に空文字を使用するのはよろしくないでしょうか? ※補足 念のため、以下のSQLを実行したところ、こちらは問題なく1件取得 できているので、抽出条件は間違っていないです。 -- SQL2 --------------------------------------------------- select   MAIN.MAIN_NAME from   MAIN_TABLE MAIN where   MAIN.CODE = 'XXX' ----------------------------------------------------------- 以上です。宜しくお願いします。

  • Oracle
  • 回答数5
  • ありがとう数5

質問者が選んだベストアンサー

  • ベストアンサー
回答No.4

autotrace あたりで自分の意図したとおりのものになっているか確認してみてはどうでしょう? WHERE句が指定されているので、実行計画が等価結合に書き換わっちゃっている可能性があります。 昔、これではまったことがあるので 僕は外部結合するときはWHEREは指定しないようにして ON句で条件を指定するようにしています。 # 個人的にはバグじゃないかと思うんだけど仕様らしい。 たとえば、 WHERE句の条件を(1)あたりに追加してみてうまくいくようならこのケースかなと。

mirumiru36
質問者

お礼

なるほど! 私もバグのような気がしますが、仕様・・・ですか。 >>WHERE句の条件を(1)あたりに追加してみてうまくいくようならこのケースかなと。 社内に再現できる環境が無いので、次の機会に試してみます。 有難うございました。

その他の回答 (4)

  • ishi7474
  • ベストアンサー率32% (71/216)
回答No.5

今のところ(11.2まで)Oracle Databaseは長さ0の文字列をNULLとして処理するので、 ... and SUB2.ZYOUKEN = '' ではなくて ... and SUB2.ZYOUKEN IS NULL で条件にマッチしませんか(SUB2.ZYOUKENがVARCHAR2型という前提ですが)。

mirumiru36
質問者

お礼

とりあえず、変数が空白の場合は、ダミーの文字を入れて 「= ''」とならないようにすることにしました。 有難うございました。

回答No.3

とりあえず質問2についてですが、 NULL=NULLやNULL=''や''=''は真ではないですよ。 OracleにおいてNULLというのは「なんだかわからないもの」なので、 「なんだかわからないもの1」は「なんだかわからないもの2」と等しいかと聞いても、 「わからない」といわれてしまいます。 Select 'HOGE' From Dual Where NULL=NULL; Select 'HOGE' From Dual Where NULL=''; Select 'HOGE' From Dual Where ''=NULL; Select 'HOGE' From Dual Where ''=''; Select 'HOGE' From Dual Where NULL Is NULL; Select 'HOGE' From Dual Where '' Is NULL; この辺を実行して結果を確認してみてください。 Is NULL以外だと、NVL( HOGE, 'NULL' )='NULL'のような方法もあります。 個人的にはNo.1の方と同じくNULLは好きではないので、最初から固定長空白で埋める派です。 質問1について、 「1行取得したいのだが、上手く取得出来ない」というのは具体的にどのような状態でしょう? Oracleエラーが出るだとか、レコードが選択されないだとか、複数選択されてしまうとか。 nvl(SUB1.CODE is NULL, 0) as SUB_CODE1, という記述を初めて見るのですが、これはエラーが発生しませんか? NVL( HOGE, 0 ) と記述すると、HOGEがNULLの時に0が返される、という関数だったと思うのですが。

mirumiru36
質問者

お礼

とりあえず、変数が空白の場合は、ダミーの文字を入れて回避することにしました。 有難うございました。

mirumiru36
質問者

補足

ご丁寧に有難うございます。 >NULL=NULLやNULL=''や''=''は真ではないですよ。 もちろんこれは承知しています。 私の書き方が悪かったようですみません。 No.1の方に補足させて頂きましたので、宜しければそちらご覧下さい。 >「1行取得したいのだが、上手く取得出来ない」というのは具体的にどのような状態でしょう? レコードが1件も選択されない状態です。 >nvl(SUB1.CODE is NULL, 0) as SUB_CODE1, という記述を初めて見るのですが、これはエラーが発生しませんか? 確かにこの記述はおかしいですね。 ↓が正しいです。  nvl(SUB1.CODE , 0) as SUB_CODE1,  nvl(SUB1.CODE , 0) as SUB_CODE1,

  • nda23
  • ベストアンサー率54% (777/1415)
回答No.2

結合条件が定数というのは.・・・ こういう場合はサブクエリを使う方が効率が よいことが多いものです。 LEFT JOIN (SELECT * FROM SUB_TABLE WHERE ZYOUKEN = '') SUB2 ON MAIN.CODE = SUB2.CODE こういう感じですね。つまり、最初から量を 絞ったクエリと結合させる方が、結合させ てから絞るより速いということです。

mirumiru36
質問者

お礼

なるほど、勉強になります! ありがとうございました。

  • STICKY2006
  • ベストアンサー率29% (1536/5269)
回答No.1

>>SUB2.ZYOUKEN = '' SUB_TABLEのZYOUKENの中身が「スペース」「NULL」ってことは? 空白条件にする場合は RTRIM(LTRIM((SUB2.ZYOUKEN)) = ''とかよくやってますが。 オラクルじゃなくてSQLServerなので文法はお察しください。 ちなみに、NULLの場合は。。。大嫌いな処理なのでおいらが組む場合は極力NULLを使わないシステムにしてるので参考文は書きません。はい。 select * from SUB_TABLE where ZYOUKEN = '' これと同等ですよね。結合しなきゃですが。

mirumiru36
質問者

お礼

とりあえず、変数が空白の場合は、ダミーの文字を入れて回避することにしました。 有難うございました。

mirumiru36
質問者

補足

回答有難うございます。 >>SUB_TABLEのZYOUKENの中身が「スペース」「NULL」ってことは? これは設計上ありえません。 なので、別にZYOUKENの中身が''のデータを取得したい訳では無いのです。 少々書き方が悪かったようですみません。 上記SQLでは(1),(2)の右辺を固定で'1'、''と記載しましたが、 正確には変数1、変数2です。 場合によっては変数の中身が無いことがあるので、その場合右辺が''となります。 また、上記SQLを実行する意図ですが、  1.MAIN_TABLEにCODE='XXX'のレコードが存在するか。  2.SUB_TABLEにCODE='XXX' かつ ZYOUKEN=変数1    のレコードが存在するか。  3.SUB_TABLEにCODE='XXX' かつ ZYOUKEN=変数2    のレコードが存在するか。 この3つのチェックを行いたいのですが、MAIN_TABLEにCODE="XXX" のレコードが存在しているのに、結合条件が''になったときに なぜデータが1件も取得できないのかが疑問に思ったところです。

関連するQ&A

  • MAX関数を使ってからLEFT JOINしたいのですが・・

    毎度お世話になります。 下記2つのテーブルからテーブル結合をして表示させたいのですが、その前にサブテーブルにある時間データの中で最新のものだけと結合したいと考えています。色々試したのですがうまくいきません。どなたかご教授の程よろしくお願いいたします。 main_tbl | id | basyo | name | --------------------- | 1 | 1  | aa  | | 2 | 1  | bb  | | 3 | 2  | cc  | | 4 | 3  | dd  | sub_tbl | id | jyotai | time  | ------------------------ | 1 | 1   |12:25:30| | 1 | 2   |13:15:12| | 2 | 1   |13:20:14| | 1 | 3   |13:50:08| 欲しい結果 | id | basyo | name | jyotai | time | --------------------------------------- | 1 | 1  | aa  | 3   |13:50:08| | 2 | 1  | bb  | 1   |13:15:12| | 3 | 2  | cc  | null  | null | | 4 | 3  | dd  | null  | null | 考えた構文 $sql = "SELECT main_tbl.id, main_tbl.basyo, main_tbl.name, sub_tbl.jyotai, sub_tbl.time FROM main_tbl LEFT OUTER JOIN (SELECT MAX(time) FROM sub_tbl GROUP BY id) ON main_tbl.id = sub_tbl.id"; または $sql = "SELECT main_tbl.id, main_tbl.basyo, main_tbl.name, sub_tbl.jyotai, sub_tbl.time FROM main_tbl LEFT OUTER JOIN sub_tbl on main_tbl.id = sub_tbl.id WHERE SELECT MAX(time) FROM sub_tbl GROUP BY id"; または $sql1 = "SELECT MAX(time) FROM sub_tbl GROUP BY id"; $rs1 = mysql_db_query($db,$sql1) or die("sql Error!"); $sql = "SELECT main_tbl.id, main_tbl.basyo,main_tbl.name, $rs1.jyotai, $rs1.time FROM main_tbl LEFT OUTER JOIN $rs1 ON main_tbl.id = $rs1.id"; ~以下クエリの実行と表示文~ どれも駄目でした。(クエリエラー表示) 因みに結合のみとMAX関数を別々に実行すると表示できることを確認しています。 環境は WinXP Mysql5.0.41 php5.2.3 です。 まだまだ勉強中ですのでよろしくお願いいたします。

    • ベストアンサー
    • PHP
  • Left Joinについて

    Left Joinについて select * From shohin left join meisho on sh03 = me02 and me01 = 1 where **** select * From shohin left join meisho on sh03 = me02 where me01 = 1 left joinの中に me01 = 1があるパターンとwhere句に me01 = 1 があるパターンで検索結果が変わってくる具体的にどう変わるのでしょうか 良く理解ができていないので教えてください

  • left outer joinで抽出したい

    SELECT (TABLE1 INNER JOIN TABLE2 ON TABLE1.CODE = TABLE2.CODE) INNER JOIN TABLE3 ON TABLE1.JAN = TABLE3.JAN というSQL文があります。この文を変更して下記の条件での抽出をおこないたいと思います。 ■TABLE1.JANを元にする。 ■TABLE1.JAN = TABLE3.JANは抽出に含めない ■TABLE1.JANに存在していて、TABLE3.JANに存在しないJANをTABLE1.JANから抽出 このようなSQL文をかきたいのですが、どのようなSQL文にしたらよいでしょうか? left outer joinを使えばいいとは思うのですが、そこから先が思い浮かびません。 よろしくお願いします。

    • ベストアンサー
    • MySQL
  • どちらのLEFT JOINが早いでしょうか?

    下記2つのテーブルがあったとします。 ・大テーブルA 7000万件 ・小テーブルB 2000件(※現在はWHERE句で指定すると1件) をJOINする場合、下記のどちらの方法が望ましいでしょうか? 案1)子テーブルを親とする方法 テーブルA(ON句により1件~2000件) LEFT JOIN 7000万件のテーブルB 案2)親テーブルを子とする方法 7000万件のテーブルB LEFT JOIN テーブルA(ON句により1件~2000件) 又、LEFT JOINの、ON句で条件を絞るのと、 WHERE句で条件を絞るのではどちらが好ましいでしょうか?

    • ベストアンサー
    • MySQL
  • PDOのデータ取得方法について

    お世話になります。 以前まで「mysql_query」でSQLを実行していたのをPDOで行うように変更しております。 prepareの「?」の部分までのSQLにした場合(1)、データ取得出来ますが (2)ですとエラーも返ってこなくデータ取得出来ません。 色々と試してはいますが、全く出来なくて大変困っています。どうかご教示くださいませ。 1)SELECT * FROM table WHERE data_code = ? and data_code2 = ? 2)SELECT * FROM table WHERE data_code = ? and data_code2 = ? and (data_code3 = "null" or data_code3 is null or data_code3 = "") ※PHP5.3、MySQL5.0です。

    • 締切済み
    • PHP
  • 複数のテーブルに対してのleft join

    前回他の方が質問していますが、、、 T1、T2、T3、T4がありまして T1が軸のテーブルです。 その場合 select T1.a,T2.b,T3.c from T1,T2,T3 left join T4 on T1.x = T2.x and T2.xx = T3.xx and T2.xxx = T4.xxx where T4.x is null というふうなSQLを発行しようとしたのです。 しかし「onが無効」と怒られました。 ご存知の方教えてください。 HPなどご存知の方お願いいたします。 DB2/UDBです。

  • 少し複雑な left join

    まだデーターベースを独学で始めて数ヶ月の初心者です。 以下(3行目のleft join)の記述では動かないのですが、どのように 記述したらよいのでしょうか? やりたい内容は3行目にあるようにbookedというテーブルの中のdateが 2013-06-05だけ抽出した形のテーブルを、timeTplというテーブルとleft join させたいです。 1 "select * 2 from 3 timeTpl as t left join (SELECT * FROM booked where date ="2013-06-05") as b 4 on 5 t.start >= b.startTime and t.start < b.finishTime || 6 t.finish > b.startTime and t.finish <= b.finishTime 7 where 8 t.time > 9 (select start 10 from class as c left join member as m 11 on c.className = m.class 12 where m.name = '$name') 13 ) 14 "; よろしくお願いします。

  • left join が3つ以上のとき

    例えば select * from ((t1 left join t2 on t1.a=t2.a)left join t3 on t1.a=t3.a) where b.t1='y'; という風にカッコがついて記入しにくくなります。 4つの場合はさらに深刻です。 簡単な記法はないのでしょうか?

  • joinの場合のテーブル名の別名の使用方法

    select * from table1 a,table2 b where a.field1=b.field1; とできますが select * from table1 as a left join table2 as b on a.field1=b.field1; とできません。 joinの場合にテーブル名の別名を使う方法を教えてください

  • LEFT JOIN について

    table a ------ user_id ------ user1 user2 user3 user4 user5 ------ table b --------------- user_id role_id --------------- user1 role1 user2 role1 user3 role1 user2 role2 user4 role2 --------------- とします。 1つのSQL文で、a のすべてのユーザそれぞれが指定role_id に属しているかどうかを検索したいです。 例えば、すべてのユーザそれぞれが role1 に属しているかどうかを検索します。 欲しい結果は以下の通りです。 ------------ user1 true user2 true user3 true user4 false user5 false ------------ LEFT JOIN だと思いますが、うまくいきません。 SELECT a.user_id, b.role_id FROM a LEFT JOIN b ON a.user_id = b.user_id WHERE b.role_id='role1'; 結果は以下になります。 ------------ user1 role1 user2 role1 user3 role1 ------------ #Whereで絞って、当然の結果です SQLをどうかければよいでしょうか。 よろしくお願いします。

    • ベストアンサー
    • MySQL