如何在MySQL中查询产品和过滤器之间的多对多关系?

时间:2016-08-18 09:36:37

标签: php mysql

我有三张桌子。 tb_filters,tb_products和tb_products_to_filters。这些表的结构以及一些虚拟数据由下式给出:

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时,必须从数据库中提取属于过滤器ID 1和过滤器ID 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`

但不幸的是,它返回一个空集。为什么呢?

1 个答案:

答案 0 :(得分: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中需要DISTINCT关键字,否则所有过滤器都会出现在列表中。我试着做了

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