关于sql:SQL-SELECT-查询语句-用法详解

7次阅读

共计 12328 个字符,预计需要花费 31 分钟才能阅读完成。

SQL 概述

SQL 的全称是 Structured Query Language(结构化查询语言),是最早于 1970 年代提出并广泛应用于拜访和治理关系型数据库(如 Oracle/MySQL)的规范计算机语言。基于 SQL 的全面弱小的性能及简略易用的个性,其历经 50 年风雨始终长盛不衰;很多近年来才疾速倒退起来的大数据处理系统如 Presto/Flink/Spark/Hive 等也实现了 SQL 或类 SQL 的语言。

基于具体的性能能够对 SQL 做进一步的细分,罕用的有:

  • 数据定义语言(DDL,Data Definition Language):创立新表或批改、删除表,关键字包含 CREATE、ALTER 和 DROP 等
  • 数据操作语言(DML,Data Manipulation Language):用于增加、批改和删除数据,关键字包含 INSERT、UPDATE 和 DELETE 等
  • 数据查询语言(DQL,Data Query Language):用于从表中取得数据,关键字是 SELECT

理论利用中,咱们通常是编写 SQL 语句,提交给数据库或大数据系统来执行,而后获取执行后果;有几个容易搞迷糊的概念如下:

  • Statement:语句,通常指整个 SQL 文本
  • Clause:子句,通常指 SQL 文本中的一部分,如 From 子句、Where 子句、Group By 子句
  • Query:查问,通常指 SQL 文本在零碎中的一次执行实例
  • Database:库,一个库能够有多个表;含意相似的有:模式(Schema)
  • Table:表,一个表能够有很多行;含意相似的有:关系(Relation)
  • Row:行,一行能够有很多列;含意相似的有:记录(Record)、条目(Item)
  • Column,列,不再细分的具体值;含意相似的有:字段(Field)

须要强调的是,不同的数据库或大数据系统中的 SQL 会有肯定的实现差别或特有的扩大性能,本文着重于介绍通识性的概念和用法,理论利用时请联合浏览相干零碎的官网文档。

SQL 查问语句

SQL 查问语句用于从零个或多个表中检索数据行,其能够蕴含子查问语句,还能够用 UNION 等将多个 SELECT 语句组合起来获取后果,也能够用 WITH 子句定义在 SELECT 中可拜访的公共表表达式(CTE,Common Table Expressions)。

OLTP 畛域谋求 SQL 查问语句简略高效,很多性能个性都会防止应用,甚至不惜拆分屡次执行以最大化数据库系统的并发能力;然而,在大数据、OLAP 畛域尽管也很期待查问能很快执行实现,但查问语句中往往间接夹杂着数据分析型业务逻辑或者 ETL 需要,从而导致查问语句变得十分长且简单;因而咱们来具体整顿一下组成简单查问语句的各个子句,熟练掌握这些子句能力比拟容易看懂并写出满足需要的简单查问 SQL。

SQL 查问语句的根本语法结构如下:

[WITH with_query [, ...] ]
SELECT [ALL | DISTINCT] select_expr [, ...]
[FROM from_item [, ...] ]
[WHERE condition]
[GROUP BY [ ALL | DISTINCT] grouping_element [, ...] ]
[HAVING condition]
[WINDOW window_name AS ( window_definition) [, ...] ]
[{ UNION | INTERSECT | EXCEPT} [ALL | DISTINCT] select ]
[ORDER BY {column_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]]
[LIMIT {[offset,] row_count | row_count OFFSET offset}] 

SELECT 子句

SELECT 子句是查问语句中必不可少的局部,由 SELECT 关键字及至多一个标识要检索列的表达式形成,多个表达式之间以英文逗号分隔;反对的表达式包含但不限于如下状况:

  • 字面量,如 SELECT 1, “hello”
  • 所有列的简写,如 SELECT * FROM …
  • 限定表名或表别名的列,如 SELECT t1.name, t2.* FROM t1, table2 as t2
  • 给选定的列指定别名,如 SELECT name as alias_name FROM …
  • 用反引号包裹列名或限定表名,如 SELECT name, t1.age FROM t1
  • 运算表达式,如 SELECT 1+1, age+10 FROM …
  • 对列值做运算的函数,如 SELECT CONCAT(last_name,’, ‘,first_name) FROM …
  • 关键字 ALL/DISTINCT 限定是否返回反复行,默认是 ALL 返回所有行,如 SELECT DISTINCT name FROM …

运算符与函数

后面提到简单查问往往夹杂着业务逻辑或 ETL 需要,因而在 SELECT 子句中对原始列数据值的解决是必不可少的。要灵便高效的解决数据值就须要有大量运算符与函数,罕用的运算符与函数列举如下:

  • 算术运算符:+, -, *, /, DIV, %/MOD
  • 数值函数:ABS、FLOOR、CRC32、RAND、LOG、SIN、COS、TAN 等等
  • 日期与理论函数:STR_TO_DATE、DATE_FORMAT、ADDDATE、CURDATE、TIMESTAMP 等等
  • 字符串函数:CONCAT、LEFT、LENGTH、LIKE、LTRIM、REPLACE、SPLIT、TRIM、UPPER 等等
  • 位操作符与函数:&, ~, |, ^, >>, <<
  • CAST 类型转换函数:CAST(expr AS type)
  • 控制流函数:CASE WHEN、IF、IFNULL、NULLIF 等等
  • 聚合函数:GROUP BY 子句中介绍
  • 窗口函数:WINDOW 子句中介绍
  • 其余函数:JSON、GEO、IP、正则、加解密、压缩 等等

FROM 子句

FROM 子句用于指定从哪些表中检索数据;如指定多个表则阐明应用了连贯 Join(联结查问也是 Join),反对的书写形式有:

  • 不指定表 SELECT 1, “hello”
  • 指定表名、视图名、长期表名 SELECT … FROM t1、SELECT … FROM v1、SELECT … FROM with1
  • 指定表别名 SELECT … FROM table2 as t2
  • 多表联结查问 SELECT … FROM t1, t2, t3
  • 括号蕴含的子查问 SELECT … FROM (SELECT … FROM …)
  • 多表连贯查问,JOIN 指定连贯的左右表,ON 指定连贯字段 SELECT … FROM t1 JOIN t2 ON t1.id1 = t2.id2
  • 指定内联表 SELECT * FROM (VALUES 13, 42)

JOIN 连贯

对于 JOIN 连贯查问,更具体的语法格局如下:

table_name join_type table_name [ON join_condition | USING ( join_column [, ...] ) ]

join_type 有以下几种具体的连贯形式:

  • [INNER] JOIN:内连贯,也叫等值连贯,只返回两个表中联结字段相等的行
  • LEFT [OUTER] JOIN:左(外)连贯,返回包含左表中的所有记录和右表中联结字段相等的记录
  • RIGHT [OUTER] JOIN:右(外)连贯,返回包含右表中的所有记录和左表中联结字段相等的记录
  • FULL [OUTER] JOIN:全(外)连贯,返回包含左表和右表中的所有记录
  • CROSS JOIN:穿插连贯,返回两个表的笛卡尔积,返回后果的行数等于两个表行数的乘积

USING 用于简化两个表具备雷同的连贯字段时书写,如上面两种写法是等价的:

  • SELECT * FROM t1 JOIN t2 ON t1.c1 = t2.c1 AND t1.c2 = t2.c2
  • SELECT * FROM t1 JOIN t2 USING (c1, c2)

VALUES 内联表

VALUES 用于创立一个没有列名的匿名表,然而能够应用带有列别名的 AS 子句来命名表和列,用法如下:

  • 单个列:SELECT * FROM (VALUES 1, 2, 3)
  • 多个列:SELECT * FROM (VALUES (1,’a’), (2,’b’), (3,’c’))
  • 给列命名:SELECT * FROM (VALUES (1,’a’), (2,’b’), (3,’c’)) as t(id, name)

WHERE 子句

WHERE 子句用于指定抉择数据行时必须满足的一个或多个条件;WHERE 条件是一个表达式,计算结果为 true 则抉择该行,没有 WHERE 子句则抉择所有行。Where 条件中能够应用除分组聚合函数外的零碎反对的函数,表达式罕用写法如下:

  • 单个比拟条件:id = 1、id >= 1、id > 1、id <= 1、id < 1、id <> 1、id != 1
  • AND 多个条件:id = 1 AND name = “peter”、id = 1 && name = “peter”
  • OR 多个条件:id = 1 OR id = 2、id = 1 || id = 2
  • 嵌套多个条件:(id = 1 OR id = 2) AND name = “peter”
  • IN/NOT IN:id IN (1,2,3)、id NOT IN (1,2,3)
  • IS NULL / IS NOT NULL:name IS NULL、id IS NOT NULL
  • BETWEEN AND:id BETWEEN 10 AND 100
  • LIKE:name LIKE “pet*”
  • EXISTS/NOT EXISTS:EXISTS (SELECT …)、NOT EXISTS (SELECT …)

GROUP BY 子句

GROUP BY 子句用于指定依据某列或某几列对查问后果进行分组,通常是为了分组后对数据做聚合 (Aggregation) 运算;用法举例:

  • 按单个字段分组计算总数:SELECT name, COUNT(*) FROM orders GROUP BY name
  • 按多个字段分组计算平均数:SELECT name, city, AVG(age) FROM users GROUP BY name, city;
  • GROUP BY 子句中应用序号来援用所需列:SELECT name, city, AVG(age) FROM users GROUP BY 1, 2;

留神:局部零碎的实现中 SELECT 子句中必须应用规范聚合函数(SUM/AVG/COUNT/ARBITRARY 等)解决非分组的列,即所有 SELECT 的列必须是聚合函数或 GROUP BY 子句中呈现的列,否则会报错;而有些零碎的实现会对于不在 GROUP BY 子句中且没有用聚合函数解决的列随机出一行数据。

GROUPING SETS

GROUPING SETS 用于在同一个查问中指定多个 GROUP BY 的汇合,作用相当于多个 GROUP BY 查问的 UNION ALL 组合,不属于单个 GROUP BY 的列被设置为 NULL;但如果数据源数据会变动,多个 UNION ALL 因为屡次读取数据所以可能并不等价。

如不思考数据变动,上面两个 SQL 等价:

# sql 1
SELECT origin_state, origin_zip, destination_state, sum(package_weight)
FROM shipping
GROUP BY GROUPING SETS ((origin_state),
    (origin_state, origin_zip),
    (destination_state));

# sql 2
SELECT origin_state, NULL, NULL, sum(package_weight)
FROM shipping GROUP BY origin_state
UNION ALL
SELECT origin_state, origin_zip, NULL, sum(package_weight)
FROM shipping GROUP BY origin_state, origin_zip
UNION ALL
SELECT NULL, NULL, destination_state, sum(package_weight)
FROM shipping GROUP BY destination_state;

CUBE

CUBE 用于列出所有可能的分组集,上面两个 SQL 等同:

# sql 1
SELECT origin_state, destination_state, sum(package_weight)
FROM shipping
GROUP BY CUBE (origin_state, destination_state);

# sql 2
SELECT origin_state, destination_state, sum(package_weight)
FROM shipping
GROUP BY GROUPING SETS ((origin_state, destination_state),
    (origin_state),
    (destination_state),
    ());

ROLLUP

ROLLUP 用于以层级的形式列出分组集,上面两个 SQL 等同:

# sql 1
SELECT origin_state, origin_zip, sum(package_weight)
FROM shipping
GROUP BY ROLLUP (origin_state, origin_zip);

# sql 2
SELECT origin_state, origin_zip, sum(package_weight)
FROM shipping
GROUP BY GROUPING SETS ((origin_state, origin_zip), (origin_state), ());

GROUPING() 函数

GROUPING() 函数 用于返回一个转换为十进制的二进制位的汇合,批示分组中呈现哪些列,也就是能够用来标记该行后果是属于哪个 GROUPING SET。它必须与 GROUPING SETS、CUBE、ROLLUP 或 GROUP BY 一起应用,其参数必须与相应 GROUPING SETS、CUBE、ROLLUP 或 GROUP BY 子句中援用的列准确匹配。

GROUPING(col1, ..., colN) -> bigint

为了计算特定行的二进制位的汇合,将位调配给参数列,最左边的列是最低无效位。对于给定的分组,如果对应的列蕴含在分组中,则该位设置为 0,否则设置为 1。例如上面的查问,第一个分组只包含 origin_state 列,而不包含 origin_zip 和 destination_state 列;为该分组结构的位集是 011,其中最高无效位示意 origin_state。

SELECT origin_state, origin_zip, destination_state, SUM(package_weight),
       GROUPING(origin_state, origin_zip, destination_state)
FROM shipping
GROUP BY GROUPING SETS ((origin_state),                        #  011 => 3
        (origin_state, origin_zip),            #  001 => 1
        (destination_state));                #  110 => 6

聚合运算函数

罕用的聚合运算函数有:

  • ARBITRARY:随机返回一组数据中的任意一个值
  • AVG:该函数用于计算平均值
  • COUNT:该函数用于计算记录数
  • MAX:该函数用于计算最大值
  • MIN:该函数用于计算最小值
  • SUM:该函数用于计算汇总值
  • GROUP_CONCAT:该函数用于将 GROUP BY 返回后果中属于同一个分组的值连接起来,返回一个字符串后果
  • STD 或 STDDEV:返回数值的样本标准差
  • STDDEV_POP:返回数值的总体标准差
  • STDDEV_SAMP:返回一组数值(整数、小数或浮点)的样本标准差。
  • VAR_POP(规范 SQL 函数):返回一组数值(整数、小数或浮点)的总体方差
  • VAR_SAMP:返回一组数值(整数、小数或浮点)的样本方差

一些有用的个性:

  • COUNT(*)(针对全表)将返回表格中所有存在的行的总数包含值为 NULL 的行
  • COUNT(列名)(针对某一列)将返回表格中某一列除去 NULL 以外的所有行的总数
  • COUNT(DISTINCT 列名),失去的后果将是除去值为 NULL 和反复数据后的后果

    • 如 COUNT(DISTINCT orderstatus) 计算不反复且不为 NULL 的订单状态有多少个
  • SUM 空行为 NULL,SUM(NULL) 为 NULL,SUM(0) 为 0
  • COUNT 空行为 0,COUNT(NULL) 为 0,COUNT(0) 为 0
  • 有 GROUP BY 时,空后果被分为 0 个分组,求 COUNT 输入空
  • 无 GROUP BY 时,空后果在默认分组,求 COUNT 输入 0

HAVING 子句

HAVING 子句 用于指定过滤分组行(GROUP BY 后的行)条件;WHERE 子句会在利用 GROUP BY 之前就过滤掉数据行,而 HAVING 子句则过滤 GROUP BY 创立的分组行,因而其条件表达式中的列必须是 GROUP BY 子句中呈现的分组列、解决分组列的函数、解决其余列的聚合函数。用法如下:

  • 分组列:… GROUP BY name HAVING (name = “peter”)
  • 解决分组列的函数:… GROUP BY name HAVING (UPPER(name) = “PETER” )
  • 解决其余列的聚合函数:… GROUP BY name HAVING (name = “peter” or AVG(age) > 20 )
  • 没有 GOURP BY 时全局聚合函数:… HAVING (AVG(age) > 20 )

WINDOW 子句

WINDOW 子句 用于定义一个能够在 OVER 关键字触发窗口函数时援用的窗口;也能够将窗口定义间接写在 OVER 关键字之后而不应用 WINDOW 子句,如下两个示例语句是等价的:

# sql 1
SELECT
  val,
  ROW_NUMBER() OVER w AS 'row_number',
  RANK()       OVER w AS 'rank',
  DENSE_RANK() OVER w AS 'dense_rank'
FROM numbers
WINDOW w AS (ORDER BY val);

# sql 2
SELECT
  val,
  ROW_NUMBER() OVER (ORDER BY val) AS 'row_number',
  RANK()       OVER (ORDER BY val) AS 'rank',
  DENSE_RANK() OVER (ORDER BY val) AS 'dense_rank'
FROM numbers;

WINDOW 子句书写在在 HAVING 子句之后、ORDER BY 子句之前,同样窗口函数也是在 HAVING 子句和 ORDER BY 子句之间运行,语法如下:

WINDOW window_name AS (window_spec) [, window_name AS (window_spec)] ...

# window_spec
[window_name] [partition_clause] [order_clause] [frame_clause]

# partition_clause + order_clause + frame_clause
PARTITION BY a ORDER BY b RANGE|ROWS BETWEEN start AND end

窗口定义蕴含以下三个局部

  • 分区标准:用于将输出行扩散到不同的分区中,过程和 GROUP BY 子句的扩散过程类似
  • 排序标准:决定输出数据行在窗口函数中执行的程序
  • 窗口区间:指定计算数据的窗口边界。窗口区间反对 RANGE、ROWS 两种模式:

    • RANGE 依照计算列值的范畴进行定义,ROWS 依照计算列的行数进行范畴定义
    • RANGE、ROWS 中能够应用 BETWEEN start AND end 指定边界可取值:

      • CURRENT ROW,以后行
      • N PRECEDING,前 n 行
      • UNBOUNDED PRECEDING,直到第 1 行
      • N FOLLOWING,后 n 行
      • UNBOUNDED FOLLOWING,直到最初 1 行

查问示例:

SELECT year, country, profit,
    SUM(profit) OVER (PARTITION BY country ORDER BY year ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS slidewindow 
FROM testwindow;

罕用窗口运算函数:

  • 聚合函数
  • 排序函数

    • CUME_DIST:返回一组数值中每个值的累计散布
    • RANK:返回数据集中每个值的排名
    • DENSE_RANK:返回一组数值中每个数值的排名
    • NTILE:将每个窗口分区的数据扩散到桶号从 1 到 n 的 n 个桶中
    • ROW_NUMBER:依据行在窗口分区内的程序,为每行数据返回一个惟一的有序行号,行号从 1 开始
    • PERCENT_RANK:返回数据集中每个数据的排名百分比,其后果由 (r – 1) / (n – 1) 计算得出。其中 r 为 RANK()计算的以后行排名,n 为以后窗口分区内总的行数
  • 值函数

    • FIRST_VALUE:返回窗口分区第 1 行的值
    • LAST_VALUE 返回窗口分区最初 1 行的值
    • LAG:返回窗口内间隔以后行之前偏移 offset 后的值
    • LEAD:返回窗口内间隔以后行偏移 offset 后的值
    • NTH_VALUE:返回窗口内偏移指定 offset 后的值,偏移量从 1 开始

ORDER BY 子句

ORDER BY 子句用于指定一个或多个表达式来对后果集进行排序,在 GROUP BY 或 HAVING 子句之后执行;更具体的语法如下:

ORDER BY expression [ASC | DESC] [NULLS { FIRST | LAST} ] [, ...]

用法举例:

  • 单个列:ORDER BY id ASC
  • 多个列:ORDER BY id ASC, status DESC
  • 指定 NULL 值排在最后面:ORDER BY id ASC NULLS FIRST
  • 应用序号来援用所需列:SELECT name, city … ORDER BY 1, 2;

LIMIT 子句

LIMIT 子句用于限度后果集中的行数,LIMIT 子句能够和 ORDER BY 子句一起应用,对后果集排序后取前多少个,也就是 TOP N;还能够指定 offset 来跳过后果集后面的行用于查问后果分页;对于分布式系统来说,如果没有和 ORDER BY 子句配合应用,屡次执行返回的数据将会是不同的;LIMIT ALL 与省略 LIMIT 子句雷同;用法举例:

  • 不限度行数:SELECT * FROM orders LIMIT ALL
  • 独自应用:SELECT * FROM orders LIMIT 5
  • 和 ORDER BY 配合应用:SELECT * FROM orders ORDER BY id DESC LIMIT 5
  • 指定 offeset 跳过行:SELECT * FROM orders LIMIT 100, 5
  • 应用 OFFSET 子句跳过行:SELECT * FROM orders OFFSET 100 LIMIT 5

WITH 子句

WITH 子句用于定义一个或者多个在主查问中应用的命名长期表,以扁平化嵌套查问或简化子查问。在局部零碎的实现中,WITH 定义的长期表能够作为 CTE(通用表表达式 Common Table Express)从而只需执行一次以进步性能,但也有的零碎只是将其对应的 SQL 内联到用到的中央从而会被执行屡次,具体须要查看对应零碎的文档。

在类 MySQL 零碎的语法中,WITH 子句通常放在 SELECT、UPDATE、DELETE 语句之前,对于蕴含 SELECT 语句的语句 则是紧挨着 SELECT:

  • WITH…SELECT…
  • WITH…UPDATE…
  • WITH…DELETE…
  • SELECT…WHERE id IN(WITH…SELECT…)…
  • SELECT * FROM (WITH … SELECT …) AS dt …
  • INSERT…WITH…SELECT…
  • REPLACE…WITH…SELECT…
  • CREATE TABLE…WITH…SELECT…
  • CREATE VIEW…WITH…SELECT…
  • EXPLAIN…WITH…SELECT…

上面的等价语句展现了 WITH 的用法

# sql 1
SELECT a, b
FROM (SELECT a, MAX(b) AS b FROM t GROUP BY a
) AS x;

# sql 2
WITH x AS (SELECT a, MAX(b) AS b FROM t GROUP BY a)
SELECT a, b FROM x;

WITH 子句可用于多子查问:

WITH
  t1 AS (SELECT a, MAX(b) AS b FROM x GROUP BY a),
  t2 AS (SELECT a, AVG(d) AS d FROM y GROUP BY a)
SELECT t1.*, t2.*
FROM t1
JOIN t2 ON t1.a = t2.a;

WITH 子句中定义的关系能够相互连贯

WITH
  x AS (SELECT a FROM t),
  y AS (SELECT a AS b FROM x),
  z AS (SELECT b AS c FROM y)
SELECT c FROM z;

子查问

子查问是一条语句中的 SELECT 语句;

标量子查问

标量子查问是和外围查问不相干且只返回零行或一行一列的子查问,标量子查问产生多个行或多个列是谬误的,如果没有产生行则返回值为 NULL。标量子查问通常用于和外围查问的某个列做比拟,反对 = > < >= <= <> != <=> 等比拟运算符:

SELECT name FROM nation
WHERE regionkey = (SELECT max(regionkey) FROM region)

IN、ANY/SOME、ALL 子查问

IN 用于判断子查问产生的任何值是否有等于所提供的表达式,IN 前面的子查问必须恰好生成一个列:

SELECT name FROM nation WHERE regionkey IN (SELECT regionkey FROM region)

ANY 关键字必须跟在比拟操作符前面,意思是“如果子查问返回的列中的任何值的比拟后果为 TRUE,则返回 TRUE”,SOME 是 ANY 的别名 :

SELECT name FROM nation WHERE regionkey = ANY (SELECT regionkey FROM region); # 子查问里 = ANY 和 IN 等价
SELECT name FROM nation WHERE regionkey > SOME (SELECT regionkey FROM region);

ALL 关键字也必须跟在比拟操作符前面,意思是“如果子查问返回的列中的所有值的比拟后果都是 TRUE,则返回 TRUE。”例如:

SELECT s1 FROM t1 WHERE s1 > ALL (SELECT s1 FROM t2);

# NOT IN 与 <> ALL 等价
SELECT s1 FROM t1 WHERE s1 <> ALL (SELECT s1 FROM t2); 
SELECT s1 FROM t1 WHERE s1 NOT IN (SELECT s1 FROM t2);

EXISTS 和 NOT EXISTS 子查问

如果子查问返回任何行,EXISTS 子查问为 TRUE,NOT EXISTS 子查问为 FALSE:
SELECT column1 FROM t1 WHERE EXISTS (SELECT * FROM t2);
下面的例子中如果 t2 蕴含任何行,即便是只有 NULL 值的行,EXISTS 条件为 TRUE;这样的查问实际上没有什么意义,通常 EXISTS/NOT EXISTS 子查问中的条件总是和里面的查问无关:

SELECT DISTINCT store_type FROM stores WHERE EXISTS (SELECT * FROM cities_stores WHERE cities_stores.store_type = stores.store_type);

关联子查问

如下面例子中,当子查问援用子查问之外的列时称为关联子查问。逻辑上来说,关联子查问将对四周查问中的每一行计算子查问,在子查问的任何单个求值过程中,援用的列都是常量。关联子查问有时候会比较复杂,局部零碎的实现对关联查问可能反对并不欠缺,这里不做过多开展,请查阅相干零碎的文档。

SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM t2 WHERE t2.column2 = t1.column2);

# 多层时从里到外寻找关联列,如上面语句 最内层的 x.column2 找到是 t2 的列
SELECT column1 FROM t1 AS x
  WHERE x.column1 = (SELECT column1 FROM t2 AS x
    WHERE x.column1 = (SELECT column1 FROM t3
      WHERE x.column2 = t3.column1));

汇合查问

汇合查问是指将多个 SELECT 语句的后果组合成一个后果集,有 UNION、INTERSECT 和 EXCEPT 三种汇合运算。汇合运算将 null 值作为一般值解决,即如有两行数据的列值都为 null 会被认为是反复行。

  • UNION:返回两个查问表达式的汇合运算。
  • UNION ALL:ALL 关键字用于保留 UNION 中产生的反复行。
  • INTERSECT:返回只有在两个汇合中同时呈现的行,返回后果将删除两个汇合中的反复行。
  • EXCEPT:先删除两个汇合中反复的数据行,返回只在第一个汇合中呈现且不在第二个汇合中呈现的行。

    SELECT * FROM t1 UNION SELECT * FROM t2;
    SELECT * FROM t1 UNION ALL SELECT * FROM t2;
    SELECT * FROM t1 INTERSECT SELECT * FROM t2;
    SELECT * FROM t1 EXCEPT SELECT * FROM t2;

要将 ORDER BY 或 LIMIT 子句利用于单个 SELECT,请将 SELECT 用括号括起来,并将子句放在括号中:

(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);

单个语句中的 ORDER BY 并不意味着这些行在最终后果中呈现的程序,UNION 在默认状况下会生成无序的行集;如果下面的语句有 ORDER BY 没有 LIMIT,则 ORDER BY 其实没有意义能够优化掉。要应用 ORDER BY 或 LIMIT 子句对整个 UNION 后果进行排序或限度,请将各个 SELECT 语句括起来,并将 ORDER BY 或 LIMIT 放在最初一个语句的前面:

(SELECT a FROM t1 WHERE a=10 AND B=1)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2)
ORDER BY a LIMIT 10;

参考资料

  • Presto SELECT 文档:https://prestodb.io/docs/curr…
  • PostgresSQL SELECT 文档:http://postgres.cn/docs/14/sq…
  • MySQL SELECT Statement 文档 : https://dev.mysql.com/doc/ref…
  • AnalyticDB MySQL SELECT 文档:https://help.aliyun.com/docum…
正文完
 0