2016-08-18 8 views
4

私は3つのテーブルを持っています。 tb_products、およびtb_products_to_filtersになります。MySQLで製品とフィルタの多対多の関係をクエリする方法は?

tb_filters:

CREATE TABLE IF NOT EXISTS `tb_filters` 
(
    `filter_id` INT (11) AUTO_INCREMENT PRIMARY KEY, 
    `filter_name` VARCHAR (255) 
); 

INSERT INTO `tb_filters` 
(`filter_name`) 
VALUES ('USB'), 
('High Speed'), 
('Wireless'), 
('Ethernet'); 

enter image description here

tb_products:

CREATE TABLE IF NOT EXISTS `tb_products` 
(
    `product_id` INT (11) AUTO_INCREMENT PRIMARY KEY, 
    `product_name` VARCHAR (255) 
); 

INSERT INTO `tb_products` 
(`product_name`) 
VALUES ('Ohm precision shunt resistor'), 
('Orchestrator Libraries'), 
('5cm scanner connection'), 
('Channel isolated digital'), 
('Network Interface Module'); 

enter image description here

一部ダミーデータと共に、これらのテーブルの構造は次式で与えられます。 10

tb_products_to_filters:

CREATE TABLE IF NOT EXISTS `tb_products_to_filters` 
(
    `id` INT (11) AUTO_INCREMENT PRIMARY KEY, 
    `product_id` INT (11), 
    `filter_id` INT (11) 
); 

INSERT INTO `tb_products_to_filters` 
(`product_id`, `filter_id`) 
VALUES (1, 1), 
(2, 2), 
(3, 3), 
(4, 3), 
(1, 3); 

enter image description here

テーブル上記 "tb_products_to_filters" に見ることにより、私の必要なクエリは、次のとおりフィルタID = 1及び3にチェックボックスを介して選択さ

ページでは、フィルタID 1とフィルタID 3に属するすべての製品をデータベースからフェッチする必要があります。この場合、id 1の製品が来るはずです。

第2に、1つのフィルタ(たとえばid = 3)だけがチェックされている場合、このIDに該当するすべての製品をフェッチする必要があります。この状態では、製品id 1、3および4が来る。

フィルタID 2を選択すると、id = 2の製品が1つだけ表示されます。

フィルタ(2及び3)の組み合わせが選択された場合、それらの両方に属しない製品が存在しないため、その後全く製品が来ないであろう。

上記の目標を達成するためにクエリを作成する方法は何ですか?

私は列を含めることに注意してください:PRODUCT_ID、PRODUCT_NAME、filter_idとFILTER_NAMEをテーブルの結果セット内のデータを表示します。

EDIT:フィルタのID 1と3をチェックしたとき

出力は以下と一致する必要があります。

enter image description here

EDIT 2:

私は、クエリの下にしようとしていますフィルタ1と3がチェックされたときに結果を取得する:

SELECT `p`.`product_id`, `p`.`product_name`, 
GROUP_CONCAT(DISTINCT `f`.`filter_id` ORDER BY `f`.`filter_id` SEPARATOR ', ') AS filter_id, GROUP_CONCAT(DISTINCT `f`.`filter_name` ORDER BY `f`.`filter_name` SEPARATOR ', ') AS filter_name 
FROM `tb_products` AS `p` INNER JOIN `tb_products_to_filters` AS `ptf` 
ON `p`.`product_id` = `ptf`.`product_id` INNER JOIN `tb_filters` AS `f` 
ON `ptf`.`filter_id` = `f`.`filter_id` GROUP BY `p`.`product_id` 
HAVING GROUP_CONCAT(DISTINCT `ptf`.`filter_id` SEPARATOR ', ') = ('1,3') 
ORDER BY `p`.`product_id` 

しかし、残念ながら、空のセットを返します。どうして?

+0

あなたは '(PRODUCT_ID、filter_id)'の完璧な自然の鍵を持っているようtb_products_to_filters' 'でサロゲートキーは、冗長であることに注意してください。また、SQLのすべてのオブジェクトが(ビューでない限り)テーブルであることを考えると、tb_の接頭辞は不要と思われます(これは個人的な不満です)。 – Strawberry

+0

tb_products_to_filtersの鍵 'id'は冗長ではありません。自動増分された主キーです。他の2列の 'product_id'と' filter_id'は一意の値を持ちません。したがって、このテーブルを操作してさらにクエリするには、 'id'カラムが必要でした。また、 'tb_'接頭辞は不要ではありません。それは個人的な好みです。それは倫理的な命名法です。 WordPressがテーブルの先頭に 'wp_'を付けて同じことをしているのを知らないのですか? – user5307298

+0

これらは組み合わせて考えると一意の値を持ちます。 – Strawberry

答えて

2

あなたはGROUP_CONCATHAVING句を使用することができます。

SELECT t.product_id,tp.product_name, 
     GROUP_CONCAT(t.filter_id) as filter_id, 
     GROUP_CONCAT(tb.filter_name) as filter_name 
FROM tb_products_to_filters t 
INNER JOIN tb_filters tb ON(t.filter_id = tb.filter_id) 
INNER JOIN tb_products tp ON(t.product_id = tp.product_id) 
WHERE t.filter_id IN(1,3) 
GROUP BY t.product_id 
HAVING COUNT(distinct t.filter_id) = 2 

あなたはこのあなたが好きなように調整することができます。すべてのフィルタがリストに来るそうでない場合は、それらの列をフェッチ中

DISTINCTキーワードはGROUP_CONCATに必要とされていますIN()内部に配置された引数の数がCOUNT(..) = X

EDITと同じでなければならないことに注意してください。私はやってみた

SELECT t.product_id,tp.product_name, 
     GROUP_CONCAT(DISTINCT t.filter_id ORDER BY `t`.`filter_id` SEPARATOR ', ') as filter_id, 
     GROUP_CONCAT(DISTINCT tb.filter_name ORDER BY tb.filter_name SEPARATOR ', ') as filter_name 
FROM tb_products_to_filters t 
INNER JOIN tb_filters tb ON(t.filter_id = tb.filter_id) 
INNER JOIN tb_products tp ON(t.product_id = tp.product_id) 
WHERE t.filter_id IN(1,3) 
GROUP BY t.product_id 
HAVING COUNT(distinct t.filter_id) = 2 

しかし、まだすべてのフィルタ名(イーサネット、高速、USB、ワイヤレス)がリストに入っています。対応するフィルタID(1,3)が文字列内にあるフィルタ名のみをリストする方法

enter image description here

+0

あなたの質問は間違っています! '#1054 - 'having clause'の 't.product_filter'列が不明です – user5307298

+0

私の質問が更新されました。私はすべての列が欲しい。だから私は最初の2テーブルは必要ないと言って間違っています。 – user5307298

+0

@ user5307298あなた自身でいくつかの努力をしてみてください。次回はあなたの自己をよりよく説明してください。クエリが更新されました。 – sagi

関連する問題