First() 函数使用啥顺序?

Posted

技术标签:

【中文标题】First() 函数使用啥顺序?【英文标题】:What order is used by First() function?First() 函数使用什么顺序? 【发布时间】:2012-11-30 18:59:37 【问题描述】:

为什么以下两个查询返回相同的结果?

SELECT FIRST(score) FROM (SELECT score FROM scores ORDER BY score ASC)
SELECT FIRST(score) FROM (SELECT score FROM scores ORDER BY score DESC)

考虑到我手动指定子查询的顺序,这很令人困惑。

【问题讨论】:

【参考方案1】:

子查询中结果的顺序是无关紧要的,除非您在子查询中使用 TOP,而您在这里没有这样做。大多数 SQL 变体不允许这种语法——例如,在子查询中使用 ORDER BY 会在 SQL Server 中引发错误。

您的***查询没有 ORDER BY,因此在 that 查询的上下文中未定义 FIRST 或 TOP 1 的概念。

在reference docs,微软声明(强调我的):

因为记录通常不会按特定顺序返回(除非 查询包括一个 ORDER BY 子句),这些返回的记录 函数将是任意的

【讨论】:

我没有访问权限在这里进行测试,您可能对 FIRST() 函数是正确的。我的回答的“肉”是第一段——子查询中的 ORDER BY 是无关紧要的,并且在大多数方言中都是错误的。我将编辑我的回复。 但是包含 Order By 子句要求 Order By 中的所有字段也都在聚合表达式中。但是,如果 Order By 包含多个字段,则将这些字段放入聚合函数或 Group By 子句本质上会破坏 First() 的聚合行为,因为它为所有字段的唯一组合生成了多行。所以 First() 函数仅在对 same, single 字段进行排序时才有用……但它等效于 Min() 和 Max() 函数。因此,答案对于原始问题来说已经足够了,但并不普遍适用。【参考方案2】:

直接回答问题:

Access 会忽略大多数子查询中的ORDER BY 子句。我相信(但无法证明)这是由于查询优化器中的错误/限制,尽管它没有在任何地方记录(我可以找到)。我已经使用 Access 2007 和 Access 2016 测试了很多 SQL 来得出这个结论。

使示例按预期工作:

TOP 100 PERCENT 添加到子查询中:

SELECT FIRST(score) FROM (SELECT TOP 100 PERCENT score FROM scores ORDER BY score ASC)
SELECT FIRST(score) FROM (SELECT TOP 100 PERCENT score FROM scores ORDER BY score DESC)

何时使用First/Last 而不是Max/Min

当您想要使用这种方法而不是更简单的 MinMax 聚合函数时,一个很好的例子是当您想要来自同一记录的另一个字段时,例如,如果基础 scores 表还举行了names玩家和rounds游戏,你可以在每个round中获得最佳和最差玩家的namescore这样:

SELECT
  round, FIRST(name) AS best, FIRST(score) AS highscore, LAST(name) AS worst, LAST(score) AS lowscore
FROM
  (SELECT TOP 100 PERCENT * FROM scores ORDER BY score DESC)
GROUP BY
  round

【讨论】:

但是SELECT TOP 1 * FROM scores ORDER BY score ASC不是更容易吗?我从来没有找到 First() 的真正应用,除了可能在“只给我任何价值,我不需要聚合”的情况下,例如在一些交叉表查询中。 @Andre 如果你的意思是在子查询中,是的,但我倾向于选择TOP 100 PERCENT,因为这也适用于外部查询中有GROUP BY 子句的一般情况,即我想要每个组中的 First 值,而不仅仅是整个查询中的第一个值。我唯一一次使用First 是我通常使用分析/窗口函数(如我的上一个示例)但Access 不支持它们的地方。另请注意,Access 中的 TOP 1 实际上返回多行,例如如果有多个玩家得分相同。 实际上我的意思是替换整个查询。但是——还要注意,Access 中的 TOP 1 实际上返回多行相同的值——我不知道这一点:-o。我想我只将它与唯一/关键列一起使用。【参考方案3】:

您的陈述是SELECT Min(Score) FROM ScoresSELECT Max(Score) FROM Scores完美功能等价物。 如果您真的想检索第一个和最后一个分数,您将需要一个 AutoNumber 或一个 DateTime 字段来指示输入顺序。然后你可以查询:

SELECT First(Score), Last(Score) FROM Scores ORDER BY MySortKey

如果您坚持自己的问题,正确的语法应该是SELECT FIRST(score) FROM (SELECT score FROM scores) ORDER BY score ASC, 或者,简化后,SELECT FIRST(score) FROM scores ORDER BY score ASC

【讨论】:

@HansUp:该代码用于说明其前面的段落。我编辑了我的回复,将名称 GameID 更改为 MySortKey。显然,它需要在表中具有该名称的字段或替换SQL语句中的名称... 为什么到目前为止对这个问题的唯一有效回复收到 -1 ? +1:好点。我没有恶意。但除了 Null 的情况,我坚持认为我的答案是好的,而且这个问题在某种程度上毫无意义。

以上是关于First() 函数使用啥顺序?的主要内容,如果未能解决你的问题,请参考以下文章

我不明白函数 foo 和 bar 将按啥顺序执行? [复制]

如何将upper_bound与成对向量一起使用,按pair.second的递增顺序排列,然后pair.first?

Greenplum中的First_value窗口函数

c++ 中reverse函数用法

spark 能执行udf 不能执行udaf,啥原因

在嵌套函数中修改变量顺序