我认为这或多或少是微不足道的事情,但在这里......
我有几个关系表,我正在尝试根据2个值检索行。到目前为止,这是我的查询:
SELECT `inventory`.*, `tags`.*, `tags_inv`.*, `categories`.*, `categories_inv`.*
FROM (`tags`)
LEFT JOIN `tags_inv` ON `tags_inv`.`tag_id` = `tags`.`tag_id`
LEFT JOIN `inventory` ON `inventory`.`inventory_id` = `tags_inv`.`inv_id`
LEFT JOIN `categories_inv` ON `categories_inv`.`inv_id` = `inventory`.`inventory_id`
LEFT JOIN `categories` ON `categories`.`cat_id` = `categories_inv`.`cat_id`
WHERE `categories`.`cat_id` = 1
AND `inventory`.`inv_name` LIKE '%p%'
OR `inventory`.`inv_dim_w` LIKE '%p%'
OR `inventory`.`inv_dim_l` LIKE '%p%'
OR `inventory`.`inv_dim_h` LIKE '%p%'
OR `tags`.`tag_description` LIKE '%p%'
ORDER BY `inventory`.`inv_name`
问题是我的查询从我的数据库中选择了所有内容(就像它忽略了cat_id
),但我想只选择cat_id
1的行...在这种情况下... >
有没有一种快速合理的方法来解决这个问题? :)
提前致谢!
答案 0 :(得分:4)
在WHERE子句中使用括号将所有OR条件组合在一起。因为你在WHERE中的同一级别上有AND和OR,所以它忽略了所有OR分支的cat_id = 1过滤器。
答案 1 :(得分:4)
提醒自己a LEFT JOIN b
的含义。这意味着,我们希望表a
中的所有行是否存在表b
中的匹配行。您正在为所有联接使用LEFT JOIN,但WHERE子句中的条件意味着您真的想要INNER JOIN。
查看布尔运算符的优先级。 AND比OR更紧密地绑定(在所有编程语言中都是如此,而不仅仅是SQL),所以你的WHERE子句相当于:
WHERE (`categories`.`cat_id` = 1 AND `inventory`.`inv_name` LIKE '%p%')
OR `inventory`.`inv_dim_w` LIKE '%p%'
OR `inventory`.`inv_dim_l` LIKE '%p%'
OR `inventory`.`inv_dim_h` LIKE '%p%'
OR `tags`.`tag_description` LIKE '%p%'
您需要使用括号来控制自然运算符优先级。
WHERE `categories`.`cat_id` = 1 AND
(`inventory`.`inv_name` LIKE '%p%'
OR `inventory`.`inv_dim_w` LIKE '%p%'
OR `inventory`.`inv_dim_l` LIKE '%p%'
OR `inventory`.`inv_dim_h` LIKE '%p%'
OR `tags`.`tag_description` LIKE '%p%')
将LIKE模式匹配谓词与前导通配符一起使用意味着您的查询无法使用索引来提高效率。因此,必须读取库存和标签表的每一行以评估模式匹配。要解决此问题,您可以使用全文搜索工具,或者将其他列添加到仅包含您要搜索的“p”的表中。
WHERE `categories`.`cat_id` = 1
AND (`inventory`.`has_p` = 1 OR `tags`.`has_p` = 1)
使用索引优化OR表达式很困难,因为MySQL在大多数情况下有一个限制,即每个表引用只能使用一个索引。解决方法是运行多个查询并将它们组合在一起。这样,对表的每个引用都可以使用自己的索引。
SELECT ... WHERE `categories`.`cat_id` = 1 AND `inventory`.`has_p` = 1
UNION ALL
SELECT ... WHERE `categories`.`cat_id` = 1 AND `tags`.`has_p` = 1