0

这是我的查询有问题的部分:

SELECT
    (SELECT id FROM users WHERE name = 'John') as competitor_id,
    (SELECT MIN(duration)
        FROM
            (SELECT duration FROM attempts
                WHERE userid=competitor_id ORDER BY created DESC LIMIT 1,1
            ) x
    ) as best_time

在执行时,它会抛出此错误:

#1054 - 'where 子句'中的未知列 'competitor_id'

看起来派生表“x”看不到父表的查询别名competitor_id。有什么方法可以创建某种全局别名,所有派生表都可以使用它?

我知道我可以competitor_id直接在 WHERE 子句中将查询用作子查询并完全避免使用别名,但我的实际查询要大得多,我需要competitor_id在更多子查询和派生表中使用,所以如果我会这样做效率会很低多次使用相同的子查询。

4

3 回答 3

0

您可能不需要在 select 语句中使用派生表,以下不是完成同样的事情吗?

SELECT
   users.id as competitor_id,
   MIN(duration) as best_time
FROM users
inner join attempts on users.id = attempts.user_id
WHERE name = 'John'
group by users.id
于 2013-06-06T20:24:56.213 回答
0

之所以会出现错误,是因为选择输出子句中引入的标识符不能从该子句中的其他任何地方引用 - 基本上,对于 SQL,标识符/列被推出不是向下(或跨越)。

但是,即使有可能,以这种方式编写查询也不好。在用户和尝试之间使用 JOIN(在用户 ID 上),然后根据名称进行过滤。然后,SQL 查询计划器将采用高级关系代数并为其编写一个有效的计划:) 请注意,这里不需要手动排序或限制,因为组上的聚合 (MIN) 可以处理这些。

SELECT u.id, u.name, MIN(a.duration) as duration
FROM users u
-- match up each attempt per user
JOIN attempts a
ON a.userid = u.id
-- only show users with this name
WHERE u.name = 'John'
-- group so we get the min duration *per user*
-- (name is included so it can be in the output clause)
GROUP BY u.id, u.name
于 2013-06-06T20:25:11.287 回答
0

关于您的查询的某些内容似乎很奇怪。最里面的子查询是选择一行,然后您将使用min(duration). min 是不必要的,因为只有一行。您可以将查询表述为:

SELECT u.id as competitor_id, a.duration as best_time
from users u left outer join
     attempts a
     on u.id = a.userid
where u.name = 'John'
order by a.created desc
limit 1, 1;

这似乎是您的查询试图做的事情。但是,这可能不是您的意图。它可能是最近的时间。(如果你使用的是 MySQL,那么limit 1, 1实际上是取第二个最近的记录)。为了获得最小的持续时间(大概是“最好的”),你会这样做:

SELECT u.id as competitor_id, min(a.duration) as best_time
from users u left outer join
     attempts a
     on u.id = a.userid
where u.name = 'John'

添加 agroup by u.id将确保这恰好返回一行。

于 2013-06-06T21:05:28.023 回答