MySQL十部曲之六:数据操作语句(DML)

文章目录

  • 前言
  • 语法约定
  • DELETE
  • INSERT
  • SELECT
    • 查询列表
    • SELECT 选项
    • 子句
      • FROM
      • WHERE
      • ORDER BY
      • GROUP BY
      • HAVING
      • WINDOW
      • LIMIT
      • FOR
    • SELECT ... INTO
    • 连接查询
      • CROSS JOIN和INNER JOIN
      • ON和USING
      • OUTER JOIN
      • NATURE JOIN
    • 子查询
      • 标量子查询
      • 使用子查询进行比较
      • 带有ANY、IN或SOME的子查询
      • 带有ALL的子查询
      • 行子查询
      • 带有EXISTS或NOT EXISTS的子查询
      • 关联子查询
      • 派生表
      • 横向派生表
      • 子查询的限制
    • 集操作(UNION、INTERSECT和EXCEPT)
  • UPDATE

前言

本文翻译自官方文档。

语法约定

方括号[]表示可选词或语句,例如,在下面的语句中,IF EXISTS是可选的:

DROP DTABLE [IF EXISTS] tab1_name

当一个语法元素由多个备选项组成时,这些备选项由竖条|分隔。当可以从一组选项中选择一个成员时,备选项列在方括号内:

TRIM([[BOTH | LEADING | TRAILING] [remstr] FROM] str)

当必须从一组选项中选择一个成员时,备选项在大括号{}中列出:

{DESCRIBE | DESC} tbl_name [col_name | wild]

省略号表示省略语句的某一部分,通常是为了提供更复杂语法的更短版本。例如,SELECT…INTO OUTFILESELECT语句形式的简写。省略号还可以表示语句的前一个语法元素可以重复。在下面的示例中,可以给出多个reset_option值,每个值在第一个值之后以逗号开头:

RESET reset_option [,reset_option] ...

DELETE

DELETE是一条DML语句,用于从表中删除行,并返回删除的行数。

DELETE FROM tbl_name [[AS] tbl_alias]
    [WHERE where_condition]
    [ORDER BY ...]
    [LIMIT row_count]
  • WHERE:可选WHERE子句中的条件确定要删除哪些行。如果没有WHERE子句,则删除所有行。
  • ORDER BY:如果指定了ORDER BY子句,则按指定的顺序删除行。
  • LIMIT:LIMIT子句对可以删除的行数设置了限制。

DELETE语句注意事项如下:

  • 不能在子查询中从表中删除并从同一表中进行选择。
  • 如果删除包含AUTO_INCREMENT列最大值的行,则该值不会在MyISAM或InnoDB表中重用。
  • 如果在autocommit模式下使用DELETE FROM tbl_name删除表中的所有行,则除InnoDB和MyISAM外的所有存储引擎都将重新开始该顺序。

INSERT

INSERT语句将新行插入到现有表中。

INSERT 
    [INTO] tbl_name
    { VALUES (value_list) [, (value_list)] ... }

INSERT 
    [INTO] tbl_name
    SET assignment_list
	
INSERT 
    [INTO] tbl_name
    { SELECT ... 
      | TABLE table_name 
      | VALUES row_constructor_list
    }
	
value:
    {expr | DEFAULT}

value_list:
    value [, value] ...

row_constructor_list:
    ROW(value_list)[, ROW(value_list)][, ...]

assignment:
    col_name = 
          value
        | [tbl_name.]col_name

assignment_list:
    assignment [, assignment] ...

插入行的列和值可以通过以下规则对应:

  • tbl_name后面提供用括号括起来的以逗号分隔的列名列表。在这种情况下,每个指定列的值必须被提供。
  • 如果没有指定列名列表,所有列的值都必须按顺序被提供。
  • SET子句通过名称显式地指示列,以及为每个列分配的值。

列值可以通过几种方式给出:

  • 如果未启用严格SQL模式,则未显式给定值的任何列都将被设置为其默认值。如果启用严格SQL模式,如果INSERT语句没有为没有默认值的每个列指定显式值,则会生成错误。
  • 如果列名列表和值列表都是空的,INSERT将创建一行,每一列都设置为默认值:
INSERT INTO tbl_name () VALUES();
  • 使用关键字DEFAULT显式地将列设置为默认值。在表达式中,您可以使用DEFAULT(col_name)为列col_name生成默认值。
  • 如果表达式expr数据类型与列数据类型不匹配,MySQL将根据列类型进行类型转换。
  • 表达式expr可以引用先前在值列表中设置的任何列。例如,你可以这样做,因为col2的值引用了col1,它之前已经被赋值:
INSERT INTO tbl_name (col1,col2) VALUES(15,col1*2);
  • 引用包含AUTO_INCREMENT值的列会出现异常。因为AUTO_INCREMENT值是在其他值赋值之后生成的,所以对赋值中的AUTO_INCREMENT列的任何引用都会返回0。

插入语句会有以下返回值:

Records: N1 Duplicates: N2 Warnings: N3
  • Records:表示语句处理的行数。(这不一定是实际插入的行数)
  • Duplicate:表示无法插入的行数,因为它们会重复某些现有的唯一索引值。
  • Warnings:表示以某种方式出现问题的插入列值的尝试次数。

使用INSERT ... SELECT,可以从SELECT语句的结果中快速插入许多行到表中,SELECT语句可以从一个或多个表中进行选择。例如:

INSERT INTO tbl_temp2 (fld_id)
  SELECT tbl_temp1.fld_order_id
  FROM tbl_temp1 WHERE tbl_temp1.fld_order_id > 100;

从MySQL 8.0.19开始,你可以用TABLE语句代替SELECT语句,如下所示:

INSERT INTO ta TABLE tb;

TABLE tb相当于SELECT * FROM tb。当将源表中的所有列插入目标表时,它非常有用,并且不需要使用WHERE进行过滤。此外,可以使用ORDER BY对来自TABLE的行按一个或多个列排序,并且可以使用LIMIT子句限制插入的行数。

SELECT

SELECT用于从一个或多个表中选择的行。

SELECT
    [ALL | DISTINCT]
    select_expr [, select_expr] ...
    [into_option]
    [FROM table_references
    [WHERE where_condition]
    [GROUP BY {col_name | expr}, ... [WITH ROLLUP]]
    [HAVING where_condition]
    [WINDOW window_name AS (window_spec) [, window_name AS (window_spec)] ...]
    [ORDER BY {col_name | expr} [ASC | DESC], ... [WITH ROLLUP]]
    [LIMIT {[offset,] row_count | row_count}]
    [into_option]
    [FOR {UPDATE | SHARE}
        [OF tbl_name [, tbl_name] ...]
        [NOWAIT | SKIP LOCKED]]
    [into_option]

into_option: {
    INTO OUTFILE 'file_name'
        [CHARACTER SET charset_name]
        export_options
  | INTO DUMPFILE 'file_name'
  | INTO var_name [, var_name] ...
}

SELECT还可以用于检索不引用任何表而计算出来的行。

mysql> SELECT 1 + 1;
        -> 2

在不引用表的情况下,允许指定DUAL作为虚拟表名。DUAL纯粹是为了方便那些要求所有SELECT语句都应该有FROM和其他可能的子句的人:

mysql> SELECT 1 + 1 FROM DUAL;
        -> 2

查询列表

select_expr子句包含一个查询列表,该列表指示要检索哪些列。该子句可以指定一个列或表达式,或者可以使用*简写:

  • 只包含一个不限定的*的查询列表可以用来从所有表中选择所有列:
  • tbl_name.*可以作为限定的简写来选择指定表中的所有列。
  • 如果一个表有不可见的列,*tbl_name.*将不会包含它们。

可以使用alias_nameselect_expr指定别名。别名用作表达式的列名,可以在GROUP BYORDER BYHAVING子句中使用。例如:

SELECT CONCAT(last_name,', ',first_name) AS full_name
  FROM mytable ORDER BY full_name;

SELECT 选项

ALLDISTINCT修饰符指定是否应该返回重复的行。ALL(默认值)指定应该返回所有匹配的行,包括重复的行。DISTINCT指定从结果集中删除重复行。同时指定两个修饰符是错误的。

STRAIGHT_JOIN强制优化器按照表在FROM子句中列出的顺序连接表。如果优化器以非最优顺序连接表,则可以使用它来加快查询速度。

子句

一般来说,所使用的子句必须完全按照语法描述中显示的顺序排列。

FROM

FROM table_references子句指示要从中检索行的表。如果指定了多个表,则执行连接查询。对于指定的每个表,您可以选择指定一个别名。

tbl_name [[AS] alias] [index_hint]

index_hint提供了有关如何在查询处理期间选择索引的信息。

可以将默认数据库中的表引用为tbl_namedb_name.tbl_name显式指定数据库。可以将列引用为col_nametbl_name.col_namedb_name.tbl_name.col_name。通常不需要这么做,除非该引用具有二义性。

WHERE

如果给定WHERE子句,则指示行必须满足的一个或多个条件才能被选中。where_condition是一个表达式,对于要选择的每一行,其计算结果为true。如果没有WHERE子句,语句将选择所有行。在WHERE表达式中,您可以使用MySQL支持的任何函数和操作符,除了聚合函数。

ORDER BY

ORDER BY用于排序要输出的列,可以在ORDER BY子句中使用列名和列别名:

SELECT college, region, seed FROM tournament
  ORDER BY region, seed;

SELECT college, region AS r, seed AS s FROM tournament
  ORDER BY r, s;

ORDER BY默认为升序,这可以使用ASC关键字显式指定。要按反向顺序排序,请将DESC关键字添加到要排序的ORDER BY子句中的列名的后边。

当您使用ORDER BYSELECT中的列进行排序时,服务器仅使用max_sort_length系统变量指示的初始字节数对值进行排序。

GROUP BY

GROUP BY子句用于将查询结果分组,SQL-92及更早版本的查询不允许在查询列表、HAVINGORDER BY内引用未在GROUP BY子句中使用的非聚合列。SQL:1999及以后版本在特定情况下允许使用非聚合列。

MySQL实现了功能依赖检测。如果启用了ONLY_FULL_GROUP_BY SQL模式(默认),MySQL会遵循SQL-92标准。

当启用了SQL的ONLY_FULL_GROUP_BY模式时,MySQL也允许没有在GROUP BY子句中命名的非聚合列,只要该列被限制为单个值,如下例所示:

mysql> CREATE TABLE mytable (
    ->    id INT UNSIGNED NOT NULL PRIMARY KEY,
    ->    a VARCHAR(10),
    ->    b INT
    -> );

mysql> INSERT INTO mytable
    -> VALUES (1, 'abc', 1000),
    ->        (2, 'abc', 2000),
    ->        (3, 'def', 4000);

mysql> SET SESSION sql_mode = sys.list_add(@@session.sql_mode, 'ONLY_FULL_GROUP_BY');

mysql> SELECT a, SUM(b) FROM mytable WHERE a = 'abc';
+------+--------+
| a    | SUM(b) |
+------+--------+
| abc  |   3000 |
+------+--------+

当使用ONLY_FULL_GROUP_BY时,也可能在SELECT列表中有多个非聚合列。在这种情况下,每个这样的列必须在WHERE子句中被限制为单个值,并且所有这样的限制条件必须通过逻辑与连接,如下所示:

mysql> DROP TABLE IF EXISTS mytable;

mysql> CREATE TABLE mytable (
    ->    id INT UNSIGNED NOT NULL PRIMARY KEY,
    ->    a VARCHAR(10),
    ->    b VARCHAR(10),
    ->    c INT
    -> );

mysql> INSERT INTO mytable
    -> VALUES (1, 'abc', 'qrs', 1000),
    ->        (2, 'abc', 'tuv', 2000),
    ->        (3, 'def', 'qrs', 4000),
    ->        (4, 'def', 'tuv', 8000),
    ->        (5, 'abc', 'qrs', 16000),
    ->        (6, 'def', 'tuv', 32000);

mysql> SELECT @@session.sql_mode;
+---------------------------------------------------------------+
| @@session.sql_mode                                            |
+---------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION |
+---------------------------------------------------------------+

mysql> SELECT a, b, SUM(c) FROM mytable
    ->     WHERE a = 'abc' AND b = 'qrs';
+------+------+--------+
| a    | b    | SUM(c) |
+------+------+--------+
| abc  | qrs  |  17000 |
+------+------+--------+

如果禁用了ONLY_FULL_GROUP_BY,MySQL不在遵循SQL-92标准。在这种情况下,服务器可以从每个组中自由选择任何值,所以除非它们相同,否则所选择的值是不确定的,这可能不是你想要的。

HAVING

HAVING子句和WHERE子句一样,指定了选择条件。WHERE子句为查询列表中的列指定条件,但不能引用聚合函数。HAVING子句指定组的条件,组通常由GROUP BY子句指定。查询结果只包含满足HAVING条件的组。如果没有GROUP BY,所有行隐式地形成一个组。

SQL标准要求HAVING必须只引用GROUP BY子句中的列或聚合函数中使用的列。然而,MySQL支持对这种行为的扩展,并允许HAVING引用SELECT列表中的列和外部子查询中的列。

WINDOW

WINDOW子句定义了可由窗口函数引用的命名窗口。

LIMIT

LIMIT子句可用于约束SELECT语句返回的行数。LIMIT接受一个或两个数字参数,它们必须都是非负整数常量,但有以下例外:

使用两个参数,第一个参数指定要返回的第一行的偏移量,第二个参数指定要返回的最大行数。初始行的偏移量为0:

SELECT * FROM tbl LIMIT 5,10;  # Retrieve rows 6-15

要检索从某个偏移量到结果集末尾的所有行,可以为第二个参数使用较大的数字。这个语句检索从第96行到最后一行的所有行:

SELECT * FROM tbl LIMIT 95,18446744073709551615;

通过一个参数,该值指定从结果集的开头返回的行数:

SELECT * FROM tbl LIMIT 5;     # Retrieve first 5 rows

FOR

如果对使用页锁或行锁的存储引擎使用FOR UPDATE,则查询检查的行将被写锁,直到当前事务结束。

FOR SHARE设置共享锁,允许其他事务读取检查的行,但不能更新或删除它们。

NOWAIT导致立即执行FOR UPDATEFOR SHARE查询,如果由于另一个事务持有的锁而无法获得行锁,则返回错误。

SKIP LOCKED导致立即执行FOR UPDATEFOR SHARE查询,排除结果集中被另一个事务锁定的行。

NOWAITSKIP LOCKED选项对于基于语句的复制是不安全的。

OF tbl_name适用于对命名表的UPDATESHARE查询。例如:

SELECT * FROM t1, t2 FOR SHARE OF t1 FOR UPDATE OF t2;

当省略OF tbl_name时,查询块所引用的所有表都被锁定。因此,将没有OF tbl_name的锁定子句与另一个锁定子句结合使用将返回错误。在多个锁子句中指定同一个表将返回错误。如果在SELECT语句中指定了别名作为表名,则锁子句只能使用该别名。如果SELECT语句没有显式指定别名,则锁定子句可能只指定实际的表名。

SELECT … INTO

SELECT…INTO形式可以将查询结果存储在变量或写入文件中。

  • SELECT ... INTO var_list :选择列值并将其存储到变量中。
  • SELECT ... INTO OUTFILE:将选定的行写入文件。可以指定列和行终止符以产生特定的输出格式。
  • SELECT ... INTO DUMPFILE:将单行写入文件而不进行任何格式化。

更多详情请看官方文档。

连接查询

MySQL支持以下JOIN语法,用于SELECT语句和多表DELETEUPDATE语句的table_references部分:

table_references:
    table_reference[, table_reference] ...

table_reference: {
    table_factor
  | joined_table
}

table_factor: {
  [LATERAL] table_subquery [AS] alias [(col_list)]
  | ( table_references )
}

joined_table: {
	table_reference CROSS JOIN table_factor 
  | table_reference INNER JOIN  table_factor [join_specification]
  | table_reference {LEFT|RIGHT} [OUTER] JOIN table_reference join_specification
  | table_reference NATURAL [INNER | {LEFT|RIGHT} [OUTER]] JOIN table_factor
}

join_specification: {
    ON search_condition
  | USING (join_column_list)
}

join_column_list:
    column_name [, column_name] ...

index_hint_list:
    index_hint [, index_hint] ...

index_hint: {
    USE {INDEX|KEY}
      [FOR {JOIN|ORDER BY|GROUP BY}] ([index_list])
  | {IGNORE|FORCE} {INDEX|KEY}
      [FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
}

index_list:
    index_name [, index_name] ...

下面的列表描述了编写JOIN时需要考虑的一般因素:

  • table_references表名可以使用别名tbl_name AS alias_name
  • table_subquery也称为FROM子句中的派生表或子查询。这样的子查询必须包含一个别名来为子查询结果提供一个表名,并且可以选择在括号中包含一个表列名列表。下面是一个简单的例子:
SELECT * FROM (SELECT 1, 2, 3) AS t1;
  • 在单个连接中可以引用的表的最大数量是61。这包括通过将FROM子句中的派生表和视图合并到外部查询块中来处理的连接。

请添加图片描述

CROSS JOIN和INNER JOIN

在标准SQL中,CROSS JOININNER JOIN的区别在于CROSS JOIN不能带有连接条件,而CROSS JOIN可以带有连接条件,除此之外,它们都会在指定的表之间产生笛卡尔积。但在MySQL中,CROSS JOININNOR JOINJOIN都是等价的,此外,,和它们在语义上也是等价的:

SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
                 ON (t2.a = t1.a AND t3.b = t1.b AND t4.c = t1.c)

SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)
                 ON (t2.a = t1.a AND t3.b = t1.b AND t4.c = t1.c)

但逗号操作符的优先级是最低的,因此连接表达式t1, t2 JOIN t3被解释为(t1, (t2 JOIN t3)),而不是((t1, t2) JOIN t3)。这会影响使用ON子句的语句,因为该子句只能引用连接操作数中的列,并且优先级会影响对这些操作数的解释。

CREATE TABLE t1 (i1 INT, j1 INT);
CREATE TABLE t2 (i2 INT, j2 INT);
CREATE TABLE t3 (i3 INT, j3 INT);
INSERT INTO t1 VALUES(1, 1);
INSERT INTO t2 VALUES(1, 1);
INSERT INTO t3 VALUES(1, 1);
SELECT * FROM t1, t2 JOIN t3 ON (t1.i1 = t3.i3);

JOIN优先于逗号操作符,因此ON子句的操作数是t2和t3,所以该语句是错误的。

同样的优先级解释也适用于将逗号操作符与INNER JOINCROSS JOINLEFT JOINRIGHT JOIN混合在一起的语句,所有这些语句的优先级都高于逗号操作符。

因此在编写语句时应该使用括号控制好优先级或避免使用逗号运算符。

ON和USING

ON一起使用的search_condition是可以在WHERE子句中使用的任何形式的条件表达式。通常,ON子句用于指定如何连接表的条件,而WHERE子句限制在结果集中包含哪些行。

USING(join_column_list)子句命名一个列列表,这些列必须同时存在于两个表中。如果表a和表b都包含c1、c2、c3列,下面的连接将比较两个表中对应的列:

a LEFT JOIN b USING (c1, c2, c3)

USING子句可以重写为比较对应列的ON子句。然而,尽管USINGON是相似的,但它们并不完全相同。考虑以下两个查询:

a LEFT JOIN b USING (c1, c2, c3)
a LEFT JOIN b ON a.c1 = b.c1 AND a.c2 = b.c2 AND a.c3 = b.c3

在确定哪些行满足连接条件方面,两个连接在语义上是相同的。

关于SELECT *展开显示哪些列,这两个连接在语义上并不相同。USING连接选择相应列的合并值,而ON连接选择所有表中的所有列。对于USING连接,SELECT *选择这些值:

COALESCE(a.c1, b.c1), COALESCE(a.c2, b.c2), COALESCE(a.c3, b.c3)

对于ON连接,SELECT *选择以下值:

a.c1, a.c2, a.c3, b.c1, b.c2, b.c3

使用内连接时,COALESCE(a.c1, b.c1)与a.c1或b.c1相同,因为两列具有相同的值。对于外部连接,两个列中的一个可以为NULL。该列将从结果中省略。

OUTER JOIN

如果在LEFT JOINONUSING部分中没有与右表匹配的行,则将所有列都设置为NULL的行用于右表。你可以使用这个事实来查找在另一个表中没有对应的行:

SELECT left_tbl.*
  FROM left_tbl LEFT JOIN right_tbl ON left_tbl.id = right_tbl.id
  WHERE right_tbl.id IS NULL;

RIGHT JOIN的工作原理类似于LEFT JOIN。为了保持代码跨数据库的可移植性,建议使用LEFT JOIN而不是RIGHT JOIN

NATURE JOIN

自然连接的冗余列不会出现,等价于使用USING的连接。MySQL根据标准SQL进行列合并和列排序,产生如下显示顺序:

  • 首先,按照第一个表中出现的顺序合并两个连接表的公共列
  • 第二,如果列在第一个表中是唯一的,按它们在该表中出现的顺序排列
  • 第三,如果列在第二个表中是唯一的,按它们在第二个表中出现的顺序排列

对于内连接,合并列定义的结果是:包含相同值列的某一列;对于外部连接,合并列定义的结果是:

  • 如果两列的值不同,则均包含
  • 如果两列的值相同,则包含某一列
  • 如果两列中有一列始终为NULL,则合并列包含非NULL列的值。

子查询

子查询是另一个语句中的SELECT语句。下面是子查询的一个例子:

SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);

在这个例子中,SELECT * FROM t1…是外部查询,(SELECT column1 FROM t2)是子查询。我们说子查询嵌套在外部查询中,实际上可以在其他子查询中嵌套更深的子查询。子查询必须始终出现在括号内。

子查询可以返回标量(单个值)、单行、单列或表。这些子查询称为标量子查询、列子查询、行子查询和表子查询。返回特定类型结果的子查询通常只能在某些上下文中使用。

标量子查询

在最简单的形式中,子查询是返回单个值的标量子查询。标量子查询是一个简单的操作数,您几乎可以在任何允许单列值或文字合法的地方使用它。例如:

CREATE TABLE t1 (s1 INT, s2 CHAR(5) NOT NULL);
INSERT INTO t1 VALUES(100, 'abcde');
SELECT (SELECT s2 FROM t1);

这个SELECT中的子查询返回单个值('abcde'),其数据类型为CHAR,长度为5,字符集和排序等于CREATE TABLE时的默认值。如果子查询结果为空,则结果为NULL。对于刚才显示的子查询,如果t1为空,结果将为NULL,即使s2不是NULL

使用子查询进行比较

通常使用以下形式使用子查询进行比较:

non_subquery_operand comparison_operator (subquery)

其中comparison_operator是这些操作符之一:

=  >  <  >=  <=  <>  !=  <=>

MySQL也允许这种结构:

non_subquery_operand LIKE (subquery)

带有ANY、IN或SOME的子查询

operand comparison_operator ANY (subquery)
operand IN (subquery)
operand comparison_operator SOME (subquery)

其中comparison_operator是这些操作符之一:

=  >  <  >=  <=  <>  != 

ANY关键字必须跟在比较运算符后面,表示“如果子查询返回的列中的任何一个值的比较为TRUE,则返回TRUE”。例如:

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

当与子查询一起使用时,单词IN= ANY的别名。因此,这两个语句是相同的:

SELECT s1 FROM t1 WHERE s1 = ANY (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 IN    (SELECT s1 FROM t2);

单词SOMEANY的别名。

带有ALL的子查询

operand comparison_operator ALL (subquery)

单词ALL必须跟在比较运算符后面,表示“如果子查询返回的列中的所有值的比较都为TRUE,则返回TRUE”。例如:

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

NOT IN<> ALL的别名。

行子查询

标量子查询或列子查询返回单个值或一列值。行子查询是返回单行的子查询变体,因此可以返回多个列值。行子查询比较的合法操作符是:

=  >  <  >=  <=  <>  !=  <=>

例如:

SELECT * FROM t1
  WHERE (col1,col2) = (SELECT col3, col4 FROM t2 WHERE id = 10);
SELECT * FROM t1
  WHERE ROW(col1,col2) = (SELECT col3, col4 FROM t2 WHERE id = 10);

带有EXISTS或NOT EXISTS的子查询

如果子查询返回任何行,则EXISTS子查询为TRUE, NOT EXISTS子查询为FALSE。例如:

SELECT column1 FROM t1 WHERE EXISTS (SELECT * FROM t2);

关联子查询

关联子查询是包含对出现在外部查询中的表的引用的子查询。例如:

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

派生表

派生表是在查询FROM子句范围内生成表的表达式。例如,SELECT语句FROM子句中的子查询是派生表:

SELECT ... FROM (subquery) [AS] tbl_name ...

[AS] tbl_name子句是强制性的,因为FROM子句中的每个表都必须有一个名称。派生表中的任何列都必须具有唯一的名称。或者,tbl_name后面可以跟一个带括号的派生表列的名称列表:

SELECT ... FROM (subquery) [AS] tbl_name (col_list) ...

横向派生表

派生表通常不能在同一个FROM子句中引用前面表的列。从MySQL 8.0.14开始,派生表可以定义为横向派生表,以指定允许这样的引用。

SELECT
  salesperson.name,
  max_sale.amount,
  max_sale.customer_name
FROM
  salesperson,
  LATERAL
  (SELECT amount, customer_name
    FROM all_sales
    WHERE all_sales.salesperson_id = salesperson.id
    ORDER BY amount DESC LIMIT 1)
  AS max_sale;

子查询的限制

  • 通常,不能在修改表的同时在子查询中从同一表中进行选择。
  • 仅部分支持行比较操作
  • MySQL不支持某些子查询LIMIT

集操作(UNION、INTERSECT和EXCEPT)

SQL集操作将多个查询块的结果合并为单个结果。查询块是返回结果集的任何SQL语句,例如SELECT。SQL标准定义了以下三种集合操作:

  • UNION:将来自两个查询块的所有结果合并为单个结果,省略任何重复项。
  • INTERSECT:只合并两个查询块的结果相同的行,省略任何重复的行。
  • EXCEPT:对于两个查询块A和B,返回A中不存在于B中的所有结果,省略任何重复的结果。

这些集合操作符都支持一个ALL修饰符,该修饰符会导致结果中包含重复项。

所有三个集操作符还支持DISTINCT关键字,该关键字抑制结果中的重复项。由于这是集操作符的默认行为,因此通常不需要显式指定DISTINCT

你应该知道,在UNIONEXCEPT之前,INTERSECT会被求值。这意味着,例如,TABLE x UNION TABLE y INTERSECT TABLE z总是被计算为TABLE x UNION (TABLE y INTERSECT TABLE z)

集操作结果的列名取自第一个查询块的列名。

mysql> CREATE TABLE t1 (x INT, y INT);
Query OK, 0 rows affected (0.04 sec)

mysql> INSERT INTO t1 VALUES ROW(4,-2), ROW(5,9);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> CREATE TABLE t2 (a INT, b INT);
Query OK, 0 rows affected (0.04 sec)

mysql> INSERT INTO t2 VALUES ROW(1,2), ROW(3,4);
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> TABLE t1 UNION TABLE t2;
+------+------+
| x    | y    |
+------+------+
|    4 |   -2 |
|    5 |    9 |
|    1 |    2 |
|    3 |    4 |
+------+------+
4 rows in set (0.00 sec)

mysql> TABLE t2 UNION TABLE t1;
+------+------+
| a    | b    |
+------+------+
|    1 |    2 |
|    3 |    4 |
|    4 |   -2 |
|    5 |    9 |
+------+------+
4 rows in set (0.00 sec)

要将ORDER BYLIMIT子句应用于作为联合、交集或其他集合操作的一部分的单个查询块,请将查询块括起来,将子句放在括号内,如下所示:

(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);

(TABLE t1 ORDER BY x LIMIT 10) 
INTERSECT 
(TABLE t2 ORDER BY a LIMIT 10);

要使用ORDER BY或LIMIT子句对集合操作的整个结果进行排序或限制,请将ORDER BY或LIMIT放在最后一条语句之后:

SELECT a FROM t1
EXCEPT
SELECT a FROM t2 WHERE a=11 AND b=2
ORDER BY a LIMIT 10;

TABLE t1
UNION 
TABLE t2
ORDER BY a LIMIT 10;

如果要排序的列有别名,ORDER BY子句必须引用别名,而不是列名。

UPDATE

UPDATE是一个DML语句,用于修改表中的行,返回实际更改的行数

UPDATE table_reference
    SET assignment_list
    [WHERE where_condition]
    [ORDER BY ...]
    [LIMIT row_count]

value:
    {expr | DEFAULT}

assignment:
    col_name = value

assignment_list:
    assignment [, assignment] ...

UPDATE语句用新值更新已命名表中现有行的列。SET子句指出要修改哪些列,以及应该给它们指定哪些值。每个值可以通过表达式给出,也可以通过关键字DEFAULT显式地设置列的默认值。如果给出了WHERE子句,它指定了标识要更新哪些行的条件。如果没有WHERE子句,则更新所有行。如果指定了ORDER BY子句,则按照指定的顺序更新行。LIMIT子句限制了可以更新的行数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/355373.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网站将http升级到https大概要多少费用

随着网络安全意识的不断提升&#xff0c;越来越多的网站正从传统的HTTP协议转向更安全的HTTPS协议。这一转变的核心在于部署SSL&#xff08;Secure Sockets Layer&#xff09;或TLS&#xff08;Transport Layer Security&#xff09;证书&#xff0c;以实现数据加密传输&#x…

docker 容器管理

文章目录 docker 容器管理容器基础容器概念可写的容器层容器的磁盘大小写时拷贝 容器操作容器创建和运行容器的启停查看容器信息进入容器操作删除容器基于容器创建镜像 容器限制限制容器内存限制容器CPU限制容器块IO带宽资源限制的实现机制动态修改容器配置 容器监控容器监控命…

热门应用滥用苹果 iPhone 推送通知,暗中窃取用户数据

移动研究人员 Tommy Mysk 近日揭露&#xff0c;部分热门应用利用 iPhone 推送通知功能秘密发送用户数据&#xff0c;这引发了用户隐私安全担忧。 许多 iOS 应用程序正在使用由推送通知触发的后台进程来收集设备的用户数据&#xff0c;从而有可能创建用于跟踪的指纹档案。 Mys…

【misc | CTF】攻防世界 2017_Dating_in_Singapore

天命&#xff1a;这次终于碰到了算是真正的misc题目了 下载附件&#xff0c;打开是PDF&#xff0c;我一开始以为是flag隐写在PDF里面了 虽然也不奇怪&#xff0c;应该是可以的&#xff0c;毕竟PDF有xss漏洞也是可以的 言归正传&#xff0c;打开PDF 看着新加坡的日历&#xff…

机器学习系列15:通过t-SNE可视化高维数据

t-SNE 的全称是 t-distributed stochastic neighbor embedding&#xff08;t-分布随机领域嵌入&#xff09;&#xff0c;这是一种非线性降维技术。而 PCA 和 LDA 是线性的降维技术。 t-SNE 通常用来在二维或者三维空间中可视化复杂数据集。 简单来说&#xff0c;t-SNE 试图发…

idea中Spring项目yml文件注释中文乱码问题

idea中spring项目yml文件中文乱码问题&#xff0c;如图&#xff1a; 当出现这种情况一般就是idae的配置问题&#xff0c;解决起来也是非常简单的。 按下面操作即可&#xff0c;如图&#xff1a; 解决方式&#xff1a; 1.进入设置 2.找到File Encodings&#xff0c;然后再将编…

PWN 常用工具-补充

目录 pwndbg 如何加载文件 如何运行到Main函数停止 如何查看程序的内存布局 查看内存地址存储的值 如何查看某个地址存储的指令 搜索字符串 打印 调试相关 断点相关 查看栈内数据 查看栈调用顺序 从程序回到gdb 修改内存中的值 file 可执行文件特征 动态链接文…

elementUI的el-select传递item对象或其他参数的2种方法

方法1 :value“item” 绑定对象 只要:value绑定item对象就可以 value-key"value" 必须是item里的一个属性&#xff0c;绑定值为对象类型时必填 <el-select v-model"value" placeholder"请选择" value-key"value" change"cha…

Day02-数据类型和运算符(基本数据类型转换,赋值运算符,算术运算符,关系运算符,逻辑运算符,条件运算符,位运算符,赋值运算符,运算符优先级,标点符号)

文章目录 Java基础语法学习目标1 基本数据类型转换&#xff08;Conversion&#xff09;&#xff08;掌握&#xff09;1.1 自动类型转换&#xff08;隐式类型转换&#xff09;1.2 强制类型转换&#xff08;显式类型转换&#xff09;1.3 基本数据类型与字符串类型的转换 2 运算符…

一起玩儿Proteus仿真(C51)——01. 仿真软件Proteus和开发软件Keil C51的安装

摘要&#xff1a;本文介绍仿真软件Proteus和开发软件Keil C51的安装 智能小车系列文章已经连续发布49期了。为了照顾更多读者的需求&#xff0c;从这周开始&#xff0c;新增加一个系列——Proteus仿真系列&#xff0c;这个系列的文章还是以一个个小的专题的形式&#xff0c;介绍…

数据结构(二)------单链表

制作不易&#xff0c;三连支持一下呗&#xff01;&#xff01;&#xff01; 文章目录 前言一.什么是链表二.链表的分类三.单链表的实现总结 前言 上一节&#xff0c;我们介绍了顺序表的实现与一些经典算法。 但是顺序表这个数据结构依然有不少缺陷&#xff1a; 1.顺序表指定…

(2)(2.9) Holybro Microhard P900无线电遥测设备

文章目录 前言 1 特点 2 规格 3 包装内包括 前言 Holybro Microhard Radio 集成了 microhard Pico 系列射频模块&#xff0c;能够在强大的拓扑结构中提供高性能无线串行通信&#xff0c;如点对点、点对多点和安全 Mesh&#xff08;P840 不提供 Mesh&#xff09;。 它采用跳…

多线程 之 静态代理

什么是静态代理&#xff1f; 静态代理是一种思想&#xff0c;找一个代理负责一些琐事&#xff0c;自己则专注于一件大事。 有哪些具体的表现&#xff1f; 在日常生活中做饭就是这样&#xff0c;会做饭的人需要做饭&#xff0c;那么其他的人就来帮他打杂&#xff0c;这样做饭的…

Sqli-labs-master第一关通关攻略

第一关基于错误的字符串/数字型注入 第一关打开&#xff0c;请输入id数值作为参数&#xff0c;那就输呗整个1&#xff0c;2&#xff0c;3看看效果 通过ID数值得变动&#xff0c;页面也随之发生变化&#xff0c;然后就是判断SQL语句是否拼接&#xff0c;是字符型还是数字型 输入…

DETR解读,将Transformer带入CV

论文出处 [2005.12872] End-to-End Object Detection with Transformers (arxiv.org) 一个前置知识 匈牙利算法&#xff1a;来源于二部图匹配&#xff0c;计算最小或最大匹配 算法操作&#xff1a;在n*n的矩阵中 减去行列最小值&#xff0c;更新矩阵&#xff08;此时行或者…

(蓝桥杯每日一题)求最长回文串

问题描述 给出一个长度为 n 的小写字符串&#xff0c;求一个最长的子串 S&#xff0c;满足SXY,X&#xff0c;Y>1&#xff0c;且X,Y 均为回文串。 输入格式 输入包括一行: 第一行是一个长度为 n 的小写字符串。 输出格式 输出包括一行&#xff1a; 一行一个整数&#xff0c;表…

Java设计模式-享元模式(12)

馆长准备了很多学习资料,其中包含java方面,jvm调优,spring / spring boot /spring cloud ,微服务,分布式,前端,js书籍资料,视频资料,以及各类常用软件工具,破解工具 等资源。请关注“IT技术馆”公众号,进行关注,馆长会每天更新资源和更新技术文章等。请大家多多关注…

Vue ECharts X轴 type为value的数据格式 + X轴固定间隔并向上取整十位数 - 附完整实例

echarts&#xff1a;一个基于 JavaScript 的开源可视化图表库。 目录 效果 一、介绍 1、官方文档&#xff1a;Apache ECharts 2、官方示例 二、准备工作 1、安装依赖包 2、示例版本 三、使用步骤 1、在单页面引入 echarts 2、指定容器并设置容器宽高 3、数据处理&am…

Java: javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

我们在平时练习的时候一般使用低版本的jdk来练习&#xff0c;以便了解不同版本jdk的区别&#xff0c;下面是我们练习中遇到的问题 >>> DefaultHttpClient mHttpClient new DefaultHttpClient(new BasicHttpParams()); ClientConnectionManager ccm mHttpClien…

【Vite+Vue3+TS】基于Vite+Vue3+TypeScript+ESLint+Prettier+Stylelint搭建项目(亲测超详细)

目 录 项目搭建步骤确定node版本使用Vite创建Vue3项目规范目录结构配置环境修改Vite配置文件集成路由工具Vue Router集成状态管理工具Pinia集成CSS预编译器Sassvite-plugin-svg-icons图标组件集成UI框架Element Plus集成HTTP 请求工具 Axios 项目代码规范集成ESLint配置集成Pre…