我有一个包含三个表的数据库:
地方:
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 |
还有第四个命名的类别,但它并不重要。
我正在尝试过滤place-table中的地点,以向用户显示他/她尚未访问过的最近的地方。
$ 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结果并且不会引发错误。我也确定,这些地方不在place_visited表中。
我已经盯着这看了很长时间,而我却无法弄清楚错误。 任何帮助将非常感谢!
答案 0 :(得分:0)
您的查询正在进行内部联接。因此,它只能返回用户访问过的地方。它无法返回用户未访问过的地方。在继续之前,这里有一个简单的规则:从不在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
子句中。
我还介绍了表别名。这些有助于使查询更容易编写和阅读。