跳至内容
SQL

QUALIFY:那个您从未意识到自己需要的 SQL 过滤语句

了解 SQL 中必不可少却不太常见的 QUALIFY 子句。理解其语法、用法,以及它与其他 SQL 过滤方法的不同之处。
Kurtis Pykes 's photo
Kurtis Pykes
已更新 · 8分钟 阅读

使用 AI 探索

ChatGPTClaudePerplexity

创建您的免费账户

实践并学习路径你的进步。

使用 Google 继续
继续操作即表示您接受我们的《使用条款》和《隐私政策》,并同意您的数据存储在美国。

结构化查询语言(SQL)是世界上最重要的编程语言之一,广泛应用于数据科学家和数据工程师的日常工作中。 

随着越来越多的人依赖数据驱动业务,对 SQL 专业技能的需求这些年只增不减。好在这门语言易学且成熟,拥有庞大的用户社区,可以在您遇到问题时提供支持。

本文将介绍 SQL 语言中的一个特定子句——QUALIFY。阅读完后,您将了解:

  • QUALIFY 的基本概念与语法
  • 何时使用 QUALIFY 子句
  • 它与其他过滤方法有何不同。

SQL QUALIFY 子句的基本概念与语法

QUALIFY 是用于筛选窗口函数结果的子句。因此,要成功使用 QUALIFY,SELECT 列表或 QUALIFY 子句中必须至少包含一个窗口函数——只有布尔表达式计算为 TRUE 的行才会返回。

提示:查看SQL 窗口函数速查表。

如果没有 QUALIFY,要对窗口函数的结果进行过滤就需要嵌套。SQL 开发者通常建议尽量避免嵌套查询,因为这会降低代码的可读性,并增加调试与协作的复杂度。

换言之,QUALIFY 子句的主要目的就是简化对窗口函数结果进行过滤的查询;这意味着 QUALIFY 会在窗口函数计算完成之后再进行求值。

包含 QUALIFY 子句的查询通常按以下顺序执行:

  • FROM
  • WHERE
  • GROUP BY 和聚合
  • HAVING
  • WINDOW
  • QUALIFY
  • DISTINCT
  • ORDER BY
  • LIMIT

QUALIFY 语句的一般语法如下:

QUALIFY <predicate>

其通用形式类似于:

SELECT <column_list>
  FROM <data_source>
  [GROUP BY ...]
  [HAVING ...]
  QUALIFY <predicate>
  [ ... ]

注:<predicate> 是在聚合与窗口函数计算完成后用于过滤结果的表达式。

何时使用 SQL QUALIFY

QUALIFY 子句与 HAVING 子句有些相似,因为它也能避免为实现过滤而编写子查询。比如,您可以用 QUALIFY 来筛选分析函数(基于一组行计算聚合值的函数)的结果。

为更清楚地说明何时使用 QUALIFY,来看一个简短情境:

假设您是一名数据科学家,某位相关方希望获取每位客户的最近一次登录信息。您的初始查询可能是这样的:

SELECT 
  user_id, 
  ip, 
  country_code,
  os,
  RANK() over (
    PARTITION BY user_id ORDER BY log_datetime DESC
  ) as previous_logins
FROM login_logs
WHERE TRUE 

这是个不错的开始,但它并不能满足需求方的要求,因为它会返回所有登录记录,而不只是最近一次。要返回最后一次登录,我们需要加上过滤条件。

SQL 新手可能会误用 WHERE 子句来过滤,如下所示:

SELECT 
  user_id, 
  ip, 
  country_code,
  os,
  RANK() over (
    PARTITION BY user_id ORDER BY log_datetime DESC
  ) AS previous_logins
FROM login_logs
WHERE TRUE 
  AND last_login = 1

遗憾的是,这段代码无法执行;即便尝试使用 GROUP BY 和 HAVING 也一样。

原因在于上一节提到的执行顺序。

WHERE、GROUP BY 和 HAVING 都在窗口函数之前求值;也就是说,它们无法过滤窗口函数的结果,因为在这三个子句运行时,窗口函数还未被计算,自然“无从得知”。

让过滤发生在窗口函数之后的一种方法是使用公用表表达式(CTE)。

代码可以这样写:

WITH 
logins AS (
  SELECT 
      user_id, 
      ip, 
      country_code,
      os,
      RANK() OVER (
        PARTITION BY user_id ORDER BY log_datetime DESC
      ) AS previous_logins
  FROM login_logs
  WHERE TRUE
)

SELECT user_id, ip, country_code, os 
FROM logins
WHERE previous_logins = 1

从技术上讲,这段代码是正确的——它能顺利执行,并返回需求方想要的结果。

不过,我们引入了两个查询,还多了几行代码;如果这种模式经常重复,就会显得累赘。

解决该问题的最佳做法是使用 QUALIFY。

代码如下:

-- Starter code from @Jiho Choi on StackOverflow 
SELECT 
  user_id, 
  ip, 
  country_code,
  os,
  RANK() over (
    PARTITION BY user_id ORDER BY log_datetime DESC
  ) as previous_logins
FROM login_logs
WHERE TRUE 
QUALIFY previous_logins = 1

这个方案之所以可行,是因为在 SQL 的执行顺序中,QUALIFY 会在窗口函数之后求值,这意味着它“知道”窗口函数的存在,因此可以在同一条查询中对其进行过滤。

您可能会好奇,除了减少代码行数,QUALIFY 还有哪些好处?答案是并没有明显的性能优势。

我们使用的 CTE 方案与 QUALIFY 方案的执行时间相近,因此很难说 QUALIFY 带来了显著的性能提升。

其主要优势在于使用体验更好:代码更少,更易读。

将 SQL QUALIFY 与其他过滤方法进行比较

此时,您已经知道 QUALIFY 子句是 SQL 中可用的另一种过滤方法,也清楚何时该使用它。

那么,QUALIFY 与其他过滤方法有何不同?

让我们回顾各类过滤方法。

WHERE 子句

WHERE 用于筛选表中的记录,即对行进行操作。我们在需要提取满足特定条件的记录时使用它。比如,想按照某人的年龄过滤数据集。代码如下:

SELECT name, gender, height, weight, age 
FROM gym_members_info 
WHERE age < 23; 

关于 WHERE 子句的要点如下:

  1. 用于基于特定条件过滤记录。
  2. 在行上执行操作。
  3. 可以不与 GROUP BY 搭配使用。
  4. 可用于 SELECT、UPDATE、DELETE 语句。

下面与 HAVING 子句对比。

HAVING 子句

HAVING 用于基于特定条件,筛选由 GROUP BY 子句定义的各组记录。因此,WHERE 与 HAVING 最显著的区别在于,HAVING 需要存在 GROUP BY 子句才能成功求值。

其主要好处是,您可以将 HAVING 应用于聚合后的部分分组,而在 WHERE 中无法做到这一点。

例如:

SELECT gender, AVG(height) 
FROM gym_members_info
GROUP BY gender 
HAVING AVG(height) > 170 

上述代码将返回平均身高大于 170 厘米的性别分组;换句话说,HAVING 执行的是列级操作。

另一个需要注意的是,与 WHERE 不同,HAVING 只能用于 SELECT 语句。

QUALIFY 子句

QUALIFY 与 HAVING 类似,但它用于对窗口函数的结果进行过滤;而 HAVING 则用于对聚合函数和 GROUP BY 子句的结果进行过滤——进一步了解如何使用 GROUP BY。

如果我们想知道各年龄组中身高最高者的信息,可以用窗口函数进行计算,再用 QUALIFY 子句过滤结果,只保留每个年龄组中身高最高的人。

代码如下:

SELECT name, gender, height, weight, age 
RANK() over (
    PARTITION BY age ORDER BY height DESC
  ) as ranked_ages
FROM gym_members_info
WHERE TRUE
QUALIFY ranked_ages = 1

本质上,QUALIFY 子句指定了一个条件表达式,用于筛选已按照用户指定条件计算完成的有序分析函数的输出。

结论与进阶学习

SQL 在典型的数据科学工作流程中扮演着重要角色;掌握诸如 QUALIFY 子句等有用操作非常有帮助,因为它能让您写出更整洁的代码,便于他人与您协作。

如果您想精进 SQL 技能,推荐查看以下资源:


Kurtis Pykes 's photo
Author
Kurtis Pykes
LinkedIn
主题
SQL

从今天开始您的 SQL 学习之旅!

课程

SQL 入门

2 小时
1.6M
两小时学会用 SQL 创建和查询关系型数据库。
查看详情开始课程

课程

SQL 中级

4 小时
529.3K
在每一步都有实践查询陪伴,这门课程教你立即用自己的 SQL 代码分析数据所需的一切!

创建您的免费账户

实践并学习路径你的进步。

使用 Google 继续
继续操作即表示您接受我们的《使用条款》和《隐私政策》,并同意您的数据存储在美国。
查看更多