普通的MySQL查询:WHERE(...)AND(...)

时间:2012-04-27 22:10:22

标签: mysql join foreign-keys

我必须有星期五的案例......假设我有以下表格和数据:

+------------+
| Park       |
+------------+
| Cape Cod   |
| Blue Ridge |
| Ice Age    |
+------------+

+--------+
| Tag    |
+--------+
| Biking |
| Skiing |
+--------+

+---------------------+
| ParkTags            |
+------------+--------+
| Cape Cod   | Biking |
| Blue Ridge | Hiking |
| Ice Age    | Biking |
| Ice Age    | Hiking |
+------------+--------+

换句话说,公园存储在一个表格中,标签存储在另一个表格中,第三个表格将一个或多个标签链接到公园。

我要做的是选择一个或多个标签并返回所有包含所有标签的公园。根据上面的信息,标签与公园相关联如下:

自行车: 科德角 冰河时代

徒步旅行: 蓝岭 冰河时代

骑自行车和徒步旅行: 冰河时代

我的问题是,我的查询错误是什么?我想要的是所有公园都有自行车和徒步旅行的标签。

# My query so far

SELECT
    Park.name as Park,
    Tag.name as Tag

FROM
    ParkTags
    JOIN Park ON Park.id = ParkTags.fk_park_id
    JOIN Tag  ON Tag.id  = ParkTags.fk_tag_id

WHERE
    Tag.name = 'Biking' AND Tag.name = 'Hiking'

ORDER BY
     Park.name

我的预期产量仅限于冰河世纪公园。运行该查询会返回零结果。如果我在条件中更改OR的AND,则结果是所有三个公园。

感谢。

5 个答案:

答案 0 :(得分:3)

Tag.name不能同时具有“自行车”和“徒步旅行”的值。

答案 1 :(得分:2)

嗯,我看到的第一个问题是你想要返回任何包含ALL标签的公园,但你使用where子句来指定你想要返回的标签......如上所述,你不会去有一个行同时匹配两个条件(AND运算符),但我认为标记列上的任何where子句都会制止你的要求,所以这没有实际意义。

这是您的表格定义

parks
---------
id
name

tag
------
id
name

parktags
-------
id
fk_parks_id
fk_tags_id

我可能从parktags表上的左连接开始,就像这样

SELECT p.name, t.name 
FROM   parktags PT
          LEFT JOIN parks P ON p.id = pt.fk_parks_id
          LEFT JOIN tag T ON t.id = pt.fk_tags_id

那将为您提供所有停车场,并配有匹配的公园和标签。现在我们只需要返回在parktags上有多个条目的那些。我们试试这样的事情

SELECT p.name, t.name 
FROM   parktags PT
          LEFT JOIN parks P ON p.id = pt.fk_parks_id
          LEFT JOIN tag T ON t.id = pt.fk_tags_id
GROUP BY pt.fk_parks_id
HAVING COUNT(pt.fk_tags_id) > 1

HAVING就像WHERE一样工作,除了HAVING允许你使用聚合进行条件检查,但是WHERE没有。我们本可以在where子句中使用子选择,没有什么特别的错误,但是子选择需要他们自己的,单独的执行计划,并且比连接更昂贵。

我面前没有控制台,所以我无法测试,我相信它会有问题。你可能不得不更多地使用HAVING和GROUP BY子句来使它恰到好处,但它将是这些线上的东西。让我知道它是怎么回事......

答案 2 :(得分:1)

SELECT p.name, 
       group_concat(t.name)

FROM Park p
JOIN ParkTags pt ON pt.fk_park_id = p.id
JOIN Tag t       ON pt.fk_tag_id  = t.id

WHERE (
    SELECT COUNT(*) 

    FROM ParkTags pt 
    JOIN Tag t ON t.id = pt.fk_tag_id 

    WHERE t.name in ('Biking','Hiking') 
    AND pt.fk_park_id=p.id
) = 2

GROUP BY p.id

答案 3 :(得分:1)

你也可以尝试轻微改编Nesim's answer

SELECT p.name, GROUP_CONCAT(t.name) AS Name list
FROM Park p
        INNER JOIN ParkTags pt ON pt.fk_park_id = p.id
        INNER JOIN Tag t ON t.id = pt.fk_tag_id
WHERE   t.name in ('Biking','Hiking')
GROUP BY p.name
HAVING COUNT(DISTINCT t.id) = 2

答案 4 :(得分:0)

SELECT
    Parks.Name
FROM
    Park 
WHERE 
    EXISTS (SELECT * FROM ParkTags b WHERE b.Tag = 'Hiking' AND b.Name = Park.Name)
    AND EXISTS (SELECT * FROM ParkTags c WHERE c.Tag = 'Biking' AND c.Name = Park.Name)

那样的东西? 您正在检查是否存在匹配的标签 这不会很好地扩展....