当您只需要一个用于加入的表名时,为什么还要有一个子查询?
我也不清楚为什么您的查询中有一个GROUP BY
子句。GROUP BY
通常与MAX
or之类的聚合函数一起使用COUNT
,但您没有这些。
这个怎么样?它可能会解决您的问题。
SELECT people.id, people.name, MAX(visits.year) year
FROM people
JOIN visits ON people.id = visits.id_people
GROUP BY people.id, people.name
如果您需要显示此人、最近一次访问以及最近一次访问的注释,您将不得不再次将访问表显式连接到摘要查询(虚拟表),就像这样。
SELECT a.id, a.name, a.year, v.note
FROM (
SELECT people.id, people.name, MAX(visits.year) year
FROM people
JOIN visits ON people.id = visits.id_people
GROUP BY people.id, people.name
)a
JOIN visits v ON (a.id = v.id_people and a.year = v.year)
去小提琴:http ://www.sqlfiddle.com/#!2/d67fc/20/0
如果您需要向从未访问过的人展示一些东西,您应该尝试JOIN
在我的声明中使用 切换项目LEFT JOIN
。
正如其他人所写,ORDER BY
子查询中的子句不是标准的,并且会产生不可预测的结果。在您的情况下,它使优化器感到困惑。
编辑:GROUP BY
是一把大锤子。除非你需要,否则不要使用它。而且,除非您在查询中使用聚合函数,否则不要使用它。
请注意,如果您在最近一年的某个人的访问中拥有多行,则此查询将为该人生成多行,为该年的每次访问生成一行。如果您只需要每人一行,并且您不需要访问记录,那么第一个查询就可以解决问题。如果您在一年内对一个人进行了多次访问,而您只需要最近的一次,则必须确定哪一行是最新的。通常它将是具有最高 ID 号的那个,但只有您自己知道这一点。在这种情况下,我在您的小提琴中添加了另一个人。http://www.sqlfiddle.com/#!2/4f644/2/0
这是复杂的。但是:如果您的visits.id 编号是自动分配的并且它们始终按时间顺序排列,您可以简单地报告最高的访问id,并保证您将获得最近的一年。这将是一个非常有效的查询。
SELECT p.id, p.name, v.year, v.note
FROM (
SELECT id_people, max(id) id
FROM visits
GROUP BY id_people
)m
JOIN people p ON (p.id = m.id_people)
JOIN visits v ON (m.id = v.id)
http://www.sqlfiddle.com/#!2/4f644/1/0 但这不是您的示例设置方式。因此,您需要另一种方法来消除您最近访问的歧义,这样您每人只需获得一行。我们可以使用的唯一技巧是使用最大的 id 号。
因此,根据这个定义,我们需要从您的表中获取最新的 visit.id 编号列表。该查询使用 MAX(year)...GROUP BY(id_people) 嵌套在 MAX(id)...GROUP BY(id_people) 查询中来做到这一点。
SELECT v.id_people,
MAX(v.id) id
FROM (
SELECT id_people,
MAX(year) year
FROM visits
GROUP BY id_people
)p
JOIN visits v ON (p.id_people = v.id_people AND p.year = v.year)
GROUP BY v.id_people
整体查询(http://www.sqlfiddle.com/#!2/c2da2/1/0)是这样的。
SELECT p.id, p.name, v.year, v.note
FROM (
SELECT v.id_people,
MAX(v.id) id
FROM (
SELECT id_people,
MAX(year) year
FROM visits
GROUP BY id_people
)p
JOIN visits v ON ( p.id_people = v.id_people
AND p.year = v.year)
GROUP BY v.id_people
)m
JOIN people p ON (m.id_people = p.id)
JOIN visits v ON (m.id = v.id)
SQL 中的消歧是一项很难学习的事情,因为您需要一些时间来理解 DBMS 中的行没有固有顺序的想法。