2016-08-18 63 views
4

我有三個表格, tb_filters,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

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通過複選框選擇的頁面中,必須從數據庫中提取屬於過濾器標識1以及過濾標識3的所有產品。在這種情況下,id爲1的產品應該出現。其次,只有一個篩選器(比如id = 3)被選中時,所有屬於這個id的產品都應該被提取。在這種情況下,產品id 1,3和4將會出現。

如果選擇了過濾器ID 2,那麼只有一個id = 2的產品會出現。

如果選擇過濾器(2和3)的組合,則不會有產品因爲沒有屬於它們兩個的產品而出現。

寫入查詢以獲得上述目標的方式是什麼?

請注意,我想包括列:product_id,product_name,filter_id和filter_name以在表結果集中顯示數據。

編輯:

輸出應符合以下時過濾ID 1和3進行了檢查:

enter image description here

編輯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

注意,在'tb_products_to_filters'代理鍵是多餘的,因爲你有'(產品,過濾器_id)'一個完美的自然鍵。另外(我承認這是一個個人抱怨),考慮到SQL中的每個對象都是一個表(除非它是一個視圖),tb_前綴似乎是不必要的。 – Strawberry

+0

'tb_products_to_filters'中的關鍵'id'不是多餘的。這是一個自動遞增的主鍵。其他兩列'product_id'和'filter_id'都沒有唯一值。因此'id'列對於操作和進一步查詢這個表是必需的。 'tb_'前綴也是不必要的。這是個人偏好。這是一個道德命名法。難道你不知道WordPress爲'wp_'添加表嗎? – user5307298

+0

它們在組合考慮時具有獨特的價值。 – Strawberry

回答

2

您可以使用HAVING子句GROUP_CONCAT

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 

您可以調整這就是你想要的任何方式。請注意,放置在IN()內部參數的數目應該是一樣的COUNT(..) = X

編輯:

一個獨特的關鍵字是必需的GROUP_CONCAT而獲取這些列,否則所有的過濾器會來在列表中。我試了一下

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