我敢打赌,这是一个简单的问题,但我的MySQL排骨有点生疏。需要一些帮助,通过多条件连接为以下场景生成正确的查询。我有一个属性表(思考标签)和另一个有记录列表的表。当我想匹配在查询中定义了多个属性的页面时遇到问题。
+--------------------------------------+
| ATTRIBUTES |
+-----------+------------+-------------+
| name | value | page_id |
+-----------+------------+-------------+
| type food 2 |
| fruit apple 2 |
| color green 2 |
| type frog 3 |
| color green 3 |
+--------------------------------------+
+--------------------------------------+
| PAGES |
+--------------+-----------------------+
| page_id | title |
+--------------+-----------------------+
| 2 Granny Smith |
| 3 Kermit the Frog |
+--------------------------------------+
使用案例
Query: type+food
Results: Granny Smith
Query: color+green
Results: Granny Smith, Kermit the Frog
Query: type+food and color+green
Results: Granny Smith
这是我正在玩的查询,但显然不起作用:
SELECT page.page_id, page.title
FROM page_attributes
LEFT JOIN page ON (page_attributes.page_id = page.page_id)
WHERE (page_attributes.name = 'color'
AND page_attributes.value = 'green')
AND (page_attributes.name = 'type'
AND page_attributes.value = 'food')
答案 0 :(得分:2)
即使可能有更高效的方法,一种方法是使用多个INNER JOIN
制作一个查询,每个属性一个。使用INNER JOIN
而不是LEFT JOIN
时,所有条件必须为true才能匹配主行。
SELECT page.page_id, page.title
FROM page
INNER JOIN page_attributes a1 ON (a1.page_id = page.page_id)
INNER JOIN page_attributes a2 ON (a2.page_id = page.page_id)
WHERE (a1.name = 'color' AND a1.value = 'green')
AND (a2.name = 'type' AND a2.value = 'food')
LIMIT 10
答案 1 :(得分:0)
与Nitro一样,但保留带有ON子句的属性的标准。另外,请确保在属性表上有一个索引(page_id,name,value),以便优化连接。
SELECT
page.page_id,
page.title
FROM
page
INNER JOIN page_attributes a1
ON page.page_id = a1.page_id
AND a1.name = 'color'
AND a1.value = 'green'
INNER JOIN page_attributes a2
ON page.page_id = a2.page_id
AND a2.name = 'type'
AND a2.value = 'food'
LIMIT 10
如您所见,您想要添加另一个“条件”,只需复制/覆盖整个联接。它要么找到匹配并允许包含,要么不包含并忽略页面记录。
答案 2 :(得分:0)
问题在于您尝试将所有条件同时应用于连接的不同行。以下是联接关系(在任何SELECT
或WHERE
过滤之前)的样子:
Joined relation:
+--------------+-----------------------+-------------+-------------+
| page_id | title | name | value |
+--------------+-----------------------+-------------+-------------+
| 2 Granny Smith type food |
| 2 Granny Smith color green |
| 2 Granny Smith fruit apple |
| 3 Kermit the Frog color green |
| 3 Kermit the Frog type frog |
+--------------+-----------------------+-------------+-------------+
WHERE子句将应用于此中间结果的每一行。所以,你的查询中的条款:
WHERE (page_attributes.name = 'color'
AND page_attributes.value = 'green')
AND (page_attributes.name = 'type'
AND page_attributes.value = 'food')
对于该连接关系的每一行都将为false。
简单地将AND
更改为OR
将不起作用,因为这只会找到包含任何标记值的页面,而不是所有标记值,这是您真正想要的查询要做。
不幸的是,使用这种表结构,没有通用的标准化方法来为任意数量的被查询的标签执行此操作。如果您事先知道将查询多少个标记,那么在page_attributes
表中使用多个联接的其他答案中的建议将起作用,并且您可以通过多个UNION
ed查询获得类似的效果。但同样,只有在您确定要查询的标签数量时,这些才有效。
最简单的一般解决方案是避免尝试在SQL中完成所有操作。执行连接和任何不依赖于标记值的WHERE
条件,然后让应用程序代码遍历结果并强制执行标记查询逻辑。