具有否定和/或多个标准的mysql一对多查询

Jef*_*eff 5 mysql database relational-database one-to-many

我认为这样的查询很容易,因为关系数据库的性质,但它似乎给了我一个合适的.我也搜索过,但没有发现真正有用的东西.情况如下:

假设我对产品和产品标签有简单的关系.这是一对多关系,因此我们可以拥有以下内容:

productid  |  tag
========================
1          |  Car
1          |  Black
1          |  Ford
2          |  Car
2          |  Red
2          |  Ford
3          |  Car
3          |  Black
3          |  Lexus
4          |  Motorcycle
4          |  Black
5          |  Skateboard
5          |  Black
6          |  Skateboard
6          |  Green
Run Code Online (Sandbox Code Playgroud)

什么是最有效的查询方式(Ford OR Black OR Skateboard) AND NOT (Motorcycles OR Green)?我需要做的另一个问题就是所有问题(Car) or (Skateboard) or (Green AND Motorcycle) or (Red AND Motorcycle).

products表中有大约150k条记录,tags表中有600k条记录,因此查询需要尽可能高效.这是我一直在讨论的一个问题(示例#1),但它似乎需要大约4秒左右.任何帮助将非常感激.

SELECT p.productid
FROM   products p
       JOIN producttags tag1 USING (productid)
WHERE  p.active = 1
       AND tag1.tag IN ( 'Ford', 'Black', 'Skatebaord' )
       AND p.productid NOT IN (SELECT productid
                               FROM   producttags
                               WHERE  tag IN ( 'Motorcycle', 'Green' ));
Run Code Online (Sandbox Code Playgroud)

 

更新

到目前为止我发现的最快的查询是这样的.这需要100-200毫秒,但它似乎非常灵活和丑陋.基本上我抓住所有匹配的产品Ford,BlackSkateboard.我将这些匹配产品的所有标签连接成冒号分隔的字符串,并删除所有与:Green:AND 匹配的产品:Motorcycle:.有什么想法吗?

SELECT p.productid,
       Concat(':', Group_concat(alltags.tag SEPARATOR ':'), ':') AS taglist
FROM   products p
       JOIN producttags tag1 USING (productid)
       JOIN producttags alltags USING (productid)
WHERE  p.active = 1
       AND tag1.tag IN ( 'Ford', 'Black', 'Skateboard' )
GROUP  BY tag1.productid
HAVING ( taglist NOT LIKE '%:Motorcycle:%'
         AND taglist NOT LIKE '%:Green:%' ); 
Run Code Online (Sandbox Code Playgroud)

Bil*_*win 3

我会编写没有子查询的排除连接:

SELECT p.productid
FROM   products p
INNER JOIN producttags AS t ON p.productid = t.productid
LEFT OUTER JOIN producttags AS x ON p.productid = x.productid 
       AND x.tag IN ('Motorcycle', 'Green')
WHERE  p.active = 1
       AND t.tag IN ( 'Ford', 'Black', 'Skateboard' )
       AND x.productid IS NULL;
Run Code Online (Sandbox Code Playgroud)

确保您在两列(active、productid)上按顺序拥有产品索引。

您还应该按顺序在两列(productid、tag)上有一个 Producttags 索引。

我需要做的另一个查询是类似所有(汽车)或(滑板)或(绿色和摩托车)或(红色和摩托车)。

有时这些复杂的条件对于 MySQL 优化器来说是很困难的。一种常见的解决方法是使用 UNION 组合更简单的查询:

SELECT p.productid
FROM   products p
INNER JOIN producttags AS t1 ON p.productid = t1.productid
WHERE  p.active = 1
   AND t1.tag IN ('Car', 'Skateboard')

UNION ALL

SELECT p.productid
FROM   products p
INNER JOIN producttags AS t1 ON p.productid = t1.productid
INNER JOIN producttags AS t2 ON p.productid = t2.productid 
WHERE  p.active = 1
   AND t1.tag IN ('Motorcycle')
   AND t2.tag IN ('Green', 'Red');
Run Code Online (Sandbox Code Playgroud)

PS:您的标记表不是实体-属性-值表。