2016-08-18 120 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