基于三个数据库表的查询始终返回零结果


Query based on three database tables always returns zero results

我有一个包含三个表的数据库:

地方:

id    |  name  |  latitude  | longitude  |
------|--------|------------|------------|
1     | place1 | 11.123456  | 76.123456  |
------|--------|------------|------------|
2     | place2 | 23.123456  | 65.123456  |
etc ...

categorized_places:

id    | place_id | cat_id |
------|----------|--------|
1     |    1     |   2    |
------|----------|--------|
2     |    2     |   1    |
etc ...

places_visited:

id    | user_name | user_email | place_id |
------|-----------|------------|----------|
1     |   user_1  | x@mail.com |    2     |
------|-----------|------------|----------|
2     |   user_2  | y@mail.com |    2     |

还有第四个命名类别,但这并不重要。

我正在尝试从地点表中过滤地点,以向用户显示他/她尚未访问过的最近地点。

$cur_cat 在上一页上设置,用户可以在其中选择他/她想要访问的地方类型。

$cur_user 和 $cur_user_email 基于 $_SESSION 变量

$max_lat、$max_lon、$min_lat 和 $min_lon 基于用户当前位置

我在 php(使用 PDO(中使用此代码,但它总是返回零结果:

$get_places = $db->prepare("
    SELECT
        places.id,
        places.name,
        places.latitude,
        places.longitude
    FROM
        places,
        categorized_places,
        places_visited
    WHERE
        places.id = categorized_places.place_id
        AND categorized_places.cat_id = '$cur_cat'
        AND places.latitude <= '$max_lat'
        AND places.latitude >= '$min_lat'
        AND places.longitude <= '$max_lon'
        AND places.longitude >= '$min_lon'
        AND places_visited.user_name = '$cur_user'
        AND places_visited.user_email = '$cur_user_email'
        AND places.id != places_visited.place_id
");
$get_places->execute();

代码始终显示 0 个结果,并且不会引发任何错误。我还确定,这些位置还没有出现在places_visited表中。

我已经盯着这个看了很长时间了,我只是想不出错误。任何帮助将不胜感激!

您的查询正在执行内部联接。 因此,它只能返回用户访问过的地方。 它无法返回用户未访问过的地方。 在继续之前,这里有一个简单的规则:切勿from子句中使用逗号。 ANSI 标准的显式JOIN语法已经存在了二十多年,您应该使用它。 实际上,在这种情况下,您需要它,因为您需要一个外部连接:

SELECT p.id, p.name, p.latitude, p.longitude
FROM places p INNER JOIN
     categorized_places cp
     ON p.id = cp.place_id LEFT JOIN
     places_visited pv
     ON pv.place_id = p.id AND
        pv.user_name = '$cur_user' AND
        pv.user_email = '$cur_user_email'          
WHERE cp.cat_id = '$cur_cat' AND
      p.latitude <= '$max_lat' AND
      p.latitude >= '$min_lat' AND
      p.longitude <= '$max_lon' AND
      p.longitude >= '$min_lon' AND
      pv.place_id IS NULL;

这样做的作用是使用外部连接将条件与访问的所有位置相匹配。 然后条件pv.place_id IS NULL选择尚未访问的那些。 请注意,places_visited表上的条件位于ON子句中。 其他两个表的条件保留在WHERE子句中。 通常,当使用 LEFT OUTER JOIN 时,第一个表上的过滤器保留在 WHERE 子句中。 第二个表上的筛选器位于 ON 子句中。

我还引入了表别名。 这些有助于使查询更易于编写和阅读。