MySQLのJOINの結合方法で再度質問です。


前回の質問
http://q.hatena.ne.jp/1195028480
でテーブル同士のフィールドをチェックし、出力する方法を教えていただきました。

そして
SELECT * FROM b_table AS b LEFT JOIN a_table AS a on (b.money>=a.money_s AND b.money<=a.money_b AND b.tax=a.tax) WHERE b.money is not null ORDER BY a.a_table_id

というようにすると、aテーブル(条件設定)で指定した条件に合ったbテーブル(料金表)のレコードを抽出出来るようになりました。

そこで質問ですが、aテーブルのtaxに値が入っていないレコードは結合条件を
(b.money>=a.money_s AND b.money<=a.money_b)

としたいのですが、そのような事は可能でしょうか?
(つまり、aテーブルに入力されている条件が、2つの場合・3つの場合(レコード毎で異なる場合)でも出力できるようにしたい)

SQL文を分けて2つ書けば出来るでしょうが、あくまで「1つのSQL文で出来る場合」を教えて下さい。もし、不可能ならそれで納得します。


MySQLは4.0.26を使っています。その他のバージョンで上記の事が可能なら教えて下さい。

回答の条件
  • 1人3回まで
  • 登録:2007/11/15 19:12:04
  • 終了:2007/11/18 01:35:26

回答(3件)

id:chuken_kenkou No.1

chuken_kenkou回答回数722ベストアンサー獲得回数542007/11/15 23:41:37

ポイント20pt

前回の質問の回答は、LEFT JOINにする必要はなく、INNER JOINでよかったですね。失礼しました。

WHERE b.money is not null 

a_tableをLEFT JOINするのだから、a_tableのキー列でないと意味がないですが?

以下のSQLで、前回の期待した結果と同じ結果が得られると思います。

SELECT * FROM b_table AS b 
 INNER JOIN a_table AS a
  ON (b.money>=a.money_s AND b.money<=a.money_b AND b.tax=a.tax) 
 ORDER BY a.a_table_id

それで今回の要件に関してですが、今回はLEFT JOINを使う方法になります。

以下のSQLでいかがでしょうか?

SELECT * FROM b_table AS b
 LEFT JOIN a_table AS a 
  ON  (b.money>=a.money_s AND b.money<=a.money_b AND b.tax=a.tax) 
  WHERE a.money_s IS NOT NULL  AND a.money_b IS NOT NULL 
 ORDER BY a.a_table_id

MySQL AB :: MySQL 4.1 リファレンスマニュアル :: 6.4.1.1 JOIN 構文

id:kt26

すみません、ちょっと質問の意味と違うような…。


三番目の例は私が質問で出した例の、WHEREの部分に追加していただいて、money_sとmoney_bがNULLでない場合を条件にしていますよね?(ちなみに、b.money is not nullとなっているのは、コピペミスです。すみません)


そうではなくて、例えば

b.tax=a.tax

は、bテーブルのtaxとaテーブルのtaxが一致するものを表示するという条件ですが、「aテーブルの対象レコードにtaxの値が無い場合、この部分を避けたい」と言うのが希望です。


money_sとmoney_bしか入力していない場合は「b.money>=a.money_s AND b.money<=a.money_b」という結合条件を、money_sとmoney_bとtaxを入力している場合は「b.money>=a.money_s AND b.money<=a.money_b AND b.tax=a.tax」と言う結合条件を


という、IFみたいな事が出来ないかと思い、相談させて頂きました。


{追記}

ちょっとわかりづらいかもしれませんので、、結果として以下のような出力が出来ればと思っています。

AのID Bの料金Aの範囲Aのtax
1 100 50~150 1
2 100 100~200

※Bテーブルにはmoney「100」とtax「1」が入っている

2007/11/16 00:48:36
id:chuken_kenkou No.2

chuken_kenkou回答回数722ベストアンサー獲得回数542007/11/16 02:11:18

ポイント100pt

aテーブルの対象レコードにtaxの値が無い場合

これは、Aのtaxはnullと考えていいでしょうか?

もしそうなら、「or a.tax is null」といった条件を追加する方法が、よく行われると思います。

select * from b_table as b
 left join a_table as a
  on b.money>=a.money_s and b.money<=a.money_b
     and (b.tax=a.tax or a.tax is null)  
 order by a.a_table_id

http://q.hatena.ne.jp/ダミーです

id:kt26

ありがとうございます。こういうやり方があるんですね。当初の目的としてはうまくできました。


ただ、別質問にした方が良いかもしれないんですが、IFみたいな事って出来ませんかね?

aテーブルに「種類(type)」と言うのを追加して、

typeが1なら結合条件は「b.money>=a.money_s and b.money<=a.money_b and b.tax=a.tax」になる。
typeが2なら「b.money>=a.money_s and b.money<=a.money_b」

のような。

MySQLでIFを使えるのは知っていますが、回答していただいたSQL文に果たしてIFを組み込み、

私が思っているような条件分岐が出来るものだろうか?もし出来たらより汎用性が広がる


と思っています。何度もすみませんが、もしご存じでしたら、教えていただければと思います。

2007/11/16 17:23:27
id:chuken_kenkou No.3

chuken_kenkou回答回数722ベストアンサー獲得回数542007/11/16 17:56:26

ポイント100pt

希望の操作ができる検索条件例です。

where b.money>=a.money_s and b.money<=a.money_b 
    and (b.tax=a.tax and type=1 or type=2)

RDBMSは、インデクスの定義と、検索条件、ORDER BYやGROUP BY、DISTINCTといった指定等の

組み合わせから、なるべく最適なアクセス計画を作ろうとします。

そのため、DB操作に直接関係しない検索条件を、SQL中に指定可能だからといって、指定していいか?」

ということも考える必要があります。

今回の場合は、typeを含めると、(money,tax,type)という列構成のインデクスがあり、データ件数が

1000件以上くらいなら、インデクスがない場合に比べ、差が出るかもしれません。

データ件数が多くても1000件程度なら、それ程、気にする必要はないですけどね。

id:kt26

ありがとうございます。非常に参考になりました。

また、コメントの件もさんこうにさせていただきます。

2007/11/18 01:34:13
  • id:chuken_kenkou
    条件式でのIF関数などの使用について、回答しておきます。

    set @type=2;
    set @c=111;

    select * from tbl1
    where A=1 and B=11
    and if(@type=2,1,C=@c)
    ;



    select * from tbl1
    where A=1 and B=11
    and case when @type=1 then C=@c else 1 end
    ;

    といった書き方ができます。

    ただ、関数で列を加工(部分抽出など)したり、条件分岐したりすると、インデクスを有効利用できなく
    なるので注意が必要です。ORDER BYやGROUP BYでも同様です。

  • id:chuken_kenkou
    ユーザ変数で例を示しましたが、提示された表定義の例も示しておきますね。


    (1)IF関数を使う

    select * from b_table as b
    left join a_table as a
    on b.money>=a.money_s and b.money<=a.money_b
    and if(type=1,b.tax=a.tax,if(type=2,1,0))
    order by a.a_table_id
    ;

    (2)CASE式を使う

    select * from b_table as b
    left join a_table as a
    on b.money>=a.money_s and b.money<=a.money_b
    and case when type=1 then b.tax=a.tax
    when type=2 then 1
    else 0
    end
    order by a.a_table_id
    ;

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません