2

我一定有星期五的情况......假设我有以下表格和数据:

+------------+
| 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

我的预期输出是只获得冰河世纪公园。运行该查询返回零个结果。如果我在条件中将 AND 更改为 OR,则结果是所有三个公园。

谢谢。

4

5 回答 5

2

Tag.name 不能同时具有值​​“Biking”和“Hiking”。

于 2012-04-27T22:19:31.217 回答
2

嗯,我看到的第一个问题是你想返回任何有所有标签的公园,但是你使用 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 子句才能使其恰到好处,但它会沿着这些方向发展。让我知道事情的后续...

于 2012-04-28T03:09:36.507 回答
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
于 2012-04-27T22:29:50.127 回答
1

您也可以尝试稍微改编一下Nesim 的回答

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
于 2012-04-28T00:16:22.963 回答
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)

类似的东西?您正在检查是否存在匹配的标签 这将无法很好地扩展......

于 2012-04-27T22:27:27.313 回答