这是我的简化数据库方案
-- -----------------------------------------------------
-- Table `products`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `products` (
`id` INT NULL AUTO_INCREMENT,
`name` VARCHAR(45) NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `properties`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `properties` (
`id` INT NOT NULL AUTO_INCREMENT,
`product_id` INT NULL,
`key` VARCHAR(45) NULL,
`value` VARCHAR(45) NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Data for table `products`
-- -----------------------------------------------------
INSERT INTO `products` (`id`, `name`) VALUES (1, 'English Book with AudioCD');
INSERT INTO `products` (`id`, `name`) VALUES (2, 'Polish Book');
-- -----------------------------------------------------
-- Data for table `properties`
-- -----------------------------------------------------
INSERT INTO `properties` (`id`, `product_id`, `key`, `value`) VALUES (1, 1, 'Format', 'Book');
INSERT INTO `properties` (`id`, `product_id`, `key`, `value`) VALUES (2, 1, 'Format', 'Audio');
INSERT INTO `properties` (`id`, `product_id`, `key`, `value`) VALUES (3, 2, 'Format', 'Book');
INSERT INTO `properties` (`id`, `product_id`, `key`, `value`) VALUES (4, 1, 'Language', 'English');
INSERT INTO `properties` (`id`, `product_id`, `key`, `value`) VALUES (5, 2, 'Language', 'Polish');
Run Code Online (Sandbox Code Playgroud)
这是表格表示
+----+--------------------------+
| id | name |
+----+--------------------------+
| 1 | English Book wit AudioCD |
| 2 | Polish Book |
+----+--------------------------+
+----+------------+----------+---------+
| id | product_id | key | value |
+----+------------+----------+---------+
| 1 | 1 | Format | Book |
| 2 | 1 | Format | AudioCD |
| 3 | 2 | Format | Book |
| 4 | 1 | Language | English |
| 5 | 2 | Language | Polish |
+----+------------+----------+---------+
Run Code Online (Sandbox Code Playgroud)
我需要选择所有具有关键“格式”和价值“书籍”和“AudioCD”的产品。但我只需要满足所有这些条件的产品。所以我只想要 product_id 1,而不是 2(因为它没有 AudioCD)。另外我还想添加语言键。
有没有办法在没有多个 JOINS 的情况下做到这一点?多个 JOINS 的问题始于我假设键值属性的 20-30 个组合,因为它们将被自由添加。
感谢任何提示!
您可以通过使用的组合得到的结果WHERE
,GROUP BY
以及HAVING
返回products
有两个Book
和Audio
值。
select p.id, p.name
from products p
inner join properties t
on p.id = t.product_id
where t.key = 'Format'
and t.value in ('Book', 'Audio')
group by p.id, p.name
having count(distinct t.value) = 2;
Run Code Online (Sandbox Code Playgroud)
请参阅SQL Fiddle with Demo。基本上,您将在WHERE
子句中放置所需的值- 这将是Book
and Audio
。然后,你GROUP BY
将product.id
和product.name
这些都是每个产品特有的。最后,您将使用该HAVING
子句计算properties.value
返回的不同值。这应该等于您在WHERE
条款中拥有的项目数。
这也可以使用 内部的条件聚合来编写HAVING
:
select p.id, p.name
from products p
inner join properties t
on p.id = t.product_id
group by p.id, p.name
having sum(case when t.key = 'Format' and t.value = 'Book' then 1 else 0 end) > 0
and sum(case when t.key = 'Format' and t.value = 'Audio' then 1 else 0 end) > 0
Run Code Online (Sandbox Code Playgroud)
如果要包含Language
键,则可以在HAVING
子句中使用条件聚合:
select p.id, p.name
from products p
inner join properties t
on p.id = t.product_id
group by p.id, p.name
having
sum(case when t.key = 'Format' and t.value = 'Book' then 1 else 0 end) > 0
and sum(case when t.key = 'Format' and t.value = 'Audio' then 1 else 0 end) > 0
and sum(case when t.key = 'Language' and t.value = 'English' then 1 else 0 end) > 0
Run Code Online (Sandbox Code Playgroud)
看演示