以下を実現するSQLをお願いします。
テーブル bookinfo
id auto_increment
select varchar(10)
booktitle text
bookid varchar(45)
bookcate varchar(20)
検索機能を作成しているのですが、本のカテゴリーが bookcate に "テクノロジー" や "English" のように入力されています。 ひとつの本でもカテゴリが複数ある場合があるので、その際には書くカテゴリごとにレコードを作製し入力し、bookidでまとめています。
たとえば絞込みで カテゴリが "絵本","学習","低学年向け" の本を検索したいのですが、
select * from bookinfo where select = "all" AND bookcate in ("絵本","学習","低学年向け") で検索すると、カテゴリに 絵本 が含まれるのもすべてがSELECTされてしまいます。
そうではなくて、bookidが同じもので3つのカテゴリが入っているものをはじめてSELECTするSQLをお願いします。
> when "絵本" then (1<<0)
> when "学習" then (1<<1)
> when "低学年向け" then (1<<2)
>この数字は検索カテゴリが増えるに従ってどのよう>につけていけばいいのでしょうか?
カテゴリーの数ではなく whenに書いた順番
なので10進数で書くと
when "絵本" then 1
when "学習" then 2
when "低xx" then 4
のように2倍した数字を順にかくだけです。
(2倍するのは、2進数で桁上げをさせる為)
カテゴリーを特定の数値に固定する必要は
ありません。
項目がwhenに一致しない場合はelseの0
となり0となります。
bitsの値は、各whenで一致した項目の
数値を足したものになります。
全部一致する場合は
7 = 1 + 2 + 4
(2進数では111)
bit_orは2進数で論理演算する機能
です。
1を2進数で表現すると 1
2を2進数で表現すると 10
4を2進数で表現すると100
のように順に0が増えます。
bit_orは上記内容の各桁の論理和を
計算します。
論理は
0と0 -> 0
1と0,0と1,1と1 -> 1
となります。
上記1,10、100を各桁で
論理和すると
1 10 100 ===== 111
となります。
カテゴリー64個以下で済むなら
はじめからカテゴリーを数値かして
保存しておいた方処理も早く出来る。
http://dev.mysql.com/doc/refman/4.1/en/group-by-functions.html
select * from bookinfo
where bookid in (select bookid from bookinfo where bookcate ='絵本')
and bookid in (select bookid from bookinfo where bookcate ='学習')
and bookid in (select bookid from bookinfo where bookcate ='低学年向け')
ではどうでしょうか?
ありがとうございます。
確かにできるかもしれませんが、一回につき数個のSELECTをかけてしまっているので、負荷問題が心配です。
もっと効率のいい方法はないでしょうか?
カラム名に予約語selectは使用出来ない
事はありませんがそのままでは使用できません。
必ず`select`と書く必要があります。
select * from bookinfo as b1
where `select`="all"
and bookcate in ("絵本","学習","低学年向け")
and ("絵本","学習","低学年向け")
=( (select bookcate from bookinfo as b2 where b2.bookid=b1.bookid and b2.bookcate="絵本" limit 1),
(select bookcate from bookinfo as b2 where b2.bookid=b1.bookid and b2.bookcate="学習" limit 1),
(select bookcate from bookinfo as b2 where b2.bookid=b1.bookid and b2.bookcate="低学年向け" limit 1)
)
group by bookid
あ、はい。わかりました。。。
同じbookid内でbookcateが重複しないのであれば下記で抽出できると思います。
select * from bookinfo as b1
where
( select count(*) from bookinfo as b2 where b1.bookid = b2.bookid and
( b2.bookcate="絵本" or b2.bookcate="学習" or b2.bookcate="低学年向け")
) = 3
おぉ!まさにこんな感じのを求めていました。ありがとうございます。
もう少し効率のよい方法があるか待ってみます。
ありがとうございました。
MYSQL 5.0以上が前提で少し反則気味ですが。
select booktitle,bookid,bit_or( case bookcate when "絵本" then (1<<0) when "学習" then (1<<1) when "低学年向け" then (1<<2) else 0 end ) as bits from bookinfo group by bookid having bits=b'111'; 又は from bookinfo group by bookid having bit_count(bits)=3 でもよい
大変貴重なご回答ありがとうございます。
> when "絵本" then (1<<0)
> when "学習" then (1<<1)
> when "低学年向け" then (1<<2)
>この数字は検索カテゴリが増えるに従ってどのよう>につけていけばいいのでしょうか?
カテゴリーの数ではなく whenに書いた順番
なので10進数で書くと
when "絵本" then 1
when "学習" then 2
when "低xx" then 4
のように2倍した数字を順にかくだけです。
(2倍するのは、2進数で桁上げをさせる為)
カテゴリーを特定の数値に固定する必要は
ありません。
項目がwhenに一致しない場合はelseの0
となり0となります。
bitsの値は、各whenで一致した項目の
数値を足したものになります。
全部一致する場合は
7 = 1 + 2 + 4
(2進数では111)
bit_orは2進数で論理演算する機能
です。
1を2進数で表現すると 1
2を2進数で表現すると 10
4を2進数で表現すると100
のように順に0が増えます。
bit_orは上記内容の各桁の論理和を
計算します。
論理は
0と0 -> 0
1と0,0と1,1と1 -> 1
となります。
上記1,10、100を各桁で
論理和すると
1 10 100 ===== 111
となります。
カテゴリー64個以下で済むなら
はじめからカテゴリーを数値かして
保存しておいた方処理も早く出来る。
http://dev.mysql.com/doc/refman/4.1/en/group-by-functions.html
回答ありがとうございます。
早速試してみたいと思います。本当にありがとうございました。
回答ありがとうございます。
早速試してみたいと思います。本当にありがとうございました。