语法

SELECT 的官方文档:https://dev.mysql.com/doc/refman/5.7/en/select.html

  1. SELECT
  2. [ALL | DISTINCT | DISTINCTROW ]
  3. [HIGH_PRIORITY]
  4. [STRAIGHT_JOIN]
  5. [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
  6. [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
  7. select_expr [, select_expr] ...
  8. [into_option]
  9. [FROM table_references
  10. [PARTITION partition_list]]
  11. [WHERE where_condition]
  12. [GROUP BY {col_name | expr | position}
  13. [ASC | DESC], ... [WITH ROLLUP]]
  14. [HAVING where_condition]
  15. [ORDER BY {col_name | expr | position}
  16. [ASC | DESC], ...]
  17. [LIMIT {[offset,] row_count | row_count OFFSET offset}]
  18. [PROCEDURE procedure_name(argument_list)]
  19. [into_option]
  20. [FOR UPDATE | LOCK IN SHARE MODE]
  21. into_option: {
  22. INTO OUTFILE 'file_name'
  23. [CHARACTER SET charset_name]
  24. export_options
  25. | INTO DUMPFILE 'file_name'
  26. | INTO var_name [, var_name] ...
  27. }

WHERE

WHERE 是将查询出来的结果,通过 WHERE 后面的条件(condition),对结果进行过滤。

  1. mysql> select * from employees where emp_no > 30000 emp_no limit 4; -- 不加order bylimit是不确定的SQL
  2. +--------+------------+------------+-----------+--------+------------+
  3. | emp_no | birth_date | first_name | last_name | gender | hire_date |
  4. +--------+------------+------------+-----------+--------+------------+
  5. | 30001 | 1953-03-27 | Izaskun | Morton | M | 1988-05-21 |
  6. | 30002 | 1960-08-23 | Branimir | Snedden | M | 1998-09-24 |
  7. | 30003 | 1952-11-25 | Takahito | Vilarrasa | M | 1990-08-22 |
  8. | 30004 | 1957-11-26 | Lucian | Penttonen | F | 1992-10-08 |
  9. +--------+------------+------------+-----------+--------+------------+
  10. 4 rows in set (0.00 sec)
  11. mysql> select * from employees where emp_no > 40000 order by emp_no limit 4;
  12. +--------+------------+------------+-----------+--------+------------+
  13. | emp_no | birth_date | first_name | last_name | gender | hire_date |
  14. +--------+------------+------------+-----------+--------+------------+
  15. | 40001 | 1956-03-28 | Akemi | Maliniak | F | 1987-08-06 |
  16. | 40002 | 1960-03-15 | Nakhoon | Badr | M | 1990-02-13 |
  17. | 40003 | 1960-01-26 | Jacopo | Marshall | F | 1991-09-30 |
  18. | 40004 | 1955-09-09 | Anneke | Stiles | F | 1986-03-05 |
  19. +--------+------------+------------+-----------+--------+------------+
  20. 4 rows in set (0.02 sec)
  21. mysql> select * from employees
  22. -> where emp_no > 40000
  23. -> and hire_date > '1991-01-01' -- 可以用 and 进行 逻辑与
  24. -> order by emp_no limit 4;
  25. +--------+------------+------------+------------+--------+------------+
  26. | emp_no | birth_date | first_name | last_name | gender | hire_date |
  27. +--------+------------+------------+------------+--------+------------+
  28. | 40003 | 1960-01-26 | Jacopo | Marshall | F | 1991-09-30 |
  29. | 40005 | 1961-02-27 | Zsolt | Fairtlough | F | 1991-07-08 |
  30. | 40012 | 1955-02-07 | Chinhyun | Ozeri | F | 1995-08-12 |
  31. | 40015 | 1964-10-08 | Ioana | Lemarechal | M | 1997-08-07 |
  32. +--------+------------+------------+------------+--------+------------+
  33. 4 rows in set (0.00 sec)
  34. mysql> select * from employees
  35. -> where (emp_no > 40000 and birth_date > '1961-01-01') -- 使用()明确条件的逻辑规则
  36. -> or (emp_no > 40000 and hire_date > '1991-01-01') -- 可以使用 or 逻辑或
  37. -> order by emp_no limit 5;
  38. +--------+------------+------------+------------+--------+------------+
  39. | emp_no | birth_date | first_name | last_name | gender | hire_date |
  40. +--------+------------+------------+------------+--------+------------+
  41. | 40003 | 1960-01-26 | Jacopo | Marshall | F | 1991-09-30 |
  42. | 40005 | 1961-02-27 | Zsolt | Fairtlough | F | 1991-07-08 |
  43. | 40006 | 1962-11-07 | Basim | Panienski | F | 1986-12-27 |
  44. | 40012 | 1955-02-07 | Chinhyun | Ozeri | F | 1995-08-12 |
  45. | 40015 | 1964-10-08 | Ioana | Lemarechal | M | 1997-08-07 |
  46. +--------+------------+------------+------------+--------+------------+
  47. 5 rows in set (0.00 sec)

JOIN

image.png

INNER JOIN

  1. --
  2. -- ANSI SQL 89
  3. -- 关联employees表和titles
  4. -- 要求是 employeesemp_no 等于 titlesemp_no
  5. --
  6. mysql> select * from employees,titles where employees.emp_no = titles.emp_no limit 5;
  7. +--------+------------+------------+-----------+--------+------------+--------+-----------------+------------+------------+
  8. | emp_no | birth_date | first_name | last_name | gender | hire_date | emp_no | title | from_date | to_date |
  9. +--------+------------+------------+-----------+--------+------------+--------+-----------------+------------+------------+
  10. | 10001 | 1953-09-02 | Georgi | Facello | M | 1986-06-26 | 10001 | Senior Engineer | 1986-06-26 | 9999-01-01 |
  11. | 10002 | 1964-06-02 | Bezalel | Simmel | F | 1985-11-21 | 10002 | Staff | 1996-08-03 | 9999-01-01 |
  12. | 10003 | 1959-12-03 | Parto | Bamford | M | 1986-08-28 | 10003 | Senior Engineer | 1995-12-03 | 9999-01-01 |
  13. | 10004 | 1954-05-01 | Chirstian | Koblick | M | 1986-12-01 | 10004 | Engineer | 1986-12-01 | 1995-12-01 |
  14. | 10004 | 1954-05-01 | Chirstian | Koblick | M | 1986-12-01 | 10004 | Senior Engineer | 1995-12-01 | 9999-01-01 |
  15. +--------+------------+------------+-----------+--------+------------+--------+-----------------+------------+------------+
  16. 5 rows in set (0.00 sec)
  17. --
  18. -- 在上面的基础上只显示emp_no,名字,性别和职位名称
  19. --
  20. mysql> select emp_no, concat(last_name,' ', first_name), gender, title
  21. -> from employees,titles
  22. -> where employees.emp_no = titles.emp_no limit 5;
  23. ERROR 1052 (23000): Column 'emp_no' in field list is ambiguous -- 报错了,原因是emp_no两个表都有
  24. mysql> select employees.emp_no, -- 指定了employees
  25. -> concat(last_name,' ', first_name), gender, title
  26. -> from employees,titles
  27. -> where employees.emp_no = titles.emp_no limit 5;
  28. +--------+-----------------------------------+--------+-----------------+
  29. | emp_no | concat(last_name,' ', first_name) | gender | title |
  30. +--------+-----------------------------------+--------+-----------------+
  31. | 10001 | Facello Georgi | M | Senior Engineer |
  32. | 10002 | Simmel Bezalel | F | Staff |
  33. | 10003 | Bamford Parto | M | Senior Engineer |
  34. | 10004 | Koblick Chirstian | M | Engineer |
  35. | 10004 | Koblick Chirstian | M | Senior Engineer |
  36. +--------+-----------------------------------+--------+-----------------+
  37. mysql> select employees.emp_no,
  38. -> concat(last_name,' ', first_name) as emp_name, gender, title -- 对名字的列取一个别名叫emp_name
  39. -> from employees,titles
  40. -> where employees.emp_no = titles.emp_no limit 5;
  41. +--------+-------------------+--------+-----------------+
  42. | emp_no | emp_name | gender | title | -- 这里就显示了emp_name
  43. +--------+-------------------+--------+-----------------+
  44. | 10001 | Facello Georgi | M | Senior Engineer |
  45. | 10002 | Simmel Bezalel | F | Staff |
  46. | 10003 | Bamford Parto | M | Senior Engineer |
  47. | 10004 | Koblick Chirstian | M | Engineer |
  48. | 10004 | Koblick Chirstian | M | Senior Engineer |
  49. +--------+-------------------+--------+-----------------+
  50. 5 rows in set (0.00 sec)
  51. mysql> select e.emp_no, -- 使用表的别名
  52. -> concat(last_name,' ', first_name) as emp_name, gender, title
  53. -> from employees as e,titles as t -- 对表做别名
  54. -> where e.emp_no = t.emp_no limit 5; -- 使用报表的别名
  55. +--------+-------------------+--------+-----------------+
  56. | emp_no | emp_name | gender | title |
  57. +--------+-------------------+--------+-----------------+
  58. | 10001 | Facello Georgi | M | Senior Engineer |
  59. | 10002 | Simmel Bezalel | F | Staff |
  60. | 10003 | Bamford Parto | M | Senior Engineer |
  61. | 10004 | Koblick Chirstian | M | Engineer |
  62. | 10004 | Koblick Chirstian | M | Senior Engineer |
  63. +--------+-------------------+--------+-----------------+
  64. 5 rows in set (0.00 sec)
  65. --
  66. -- ANSI SQL 92
  67. -- inner join ... on ...语法
  68. --
  69. mysql> select e.emp_no,
  70. -> concat(last_name,' ', first_name) as emp_name, gender, title
  71. -> from employees as e inner join titles as t -- inner join 可以省略inner关键字
  72. -> on e.emp_no = t.emp_no limit 5; -- 配合join使用on
  73. +--------+-------------------+--------+-----------------+
  74. | emp_no | emp_name | gender | title |
  75. +--------+-------------------+--------+-----------------+
  76. | 10001 | Facello Georgi | M | Senior Engineer |
  77. | 10002 | Simmel Bezalel | F | Staff |
  78. | 10003 | Bamford Parto | M | Senior Engineer |
  79. | 10004 | Koblick Chirstian | M | Engineer |
  80. | 10004 | Koblick Chirstian | M | Senior Engineer |
  81. +--------+-------------------+--------+-----------------+
  82. 5 rows in set (0.00 sec)
  83. --
  84. -- 上面两种语句在效率上其实是一样的,只是语法上的区别
  85. --
  86. --- 第一种
  87. mysql> explain select e.emp_no,
  88. -> concat(last_name,' ', first_name) as emp_name, gender, title
  89. -> from employees as e,titles as t
  90. -> where e.emp_no = t.emp_no limit 5;
  91. +----+-------------+-------+------------+------+---------------+---------+---------+--------------------+--------+----------+-------------+
  92. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  93. +----+-------------+-------+------------+------+---------------+---------+---------+--------------------+--------+----------+-------------+
  94. | 1 | SIMPLE | e | NULL | ALL | PRIMARY | NULL | NULL | NULL | 298124 | 100.00 | NULL |
  95. | 1 | SIMPLE | t | NULL | ref | PRIMARY | PRIMARY | 4 | employees.e.emp_no | 1 | 100.00 | Using index |
  96. +----+-------------+-------+------------+------+---------------+---------+---------+--------------------+--------+----------+-------------+
  97. 2 rows in set, 1 warning (0.00 sec)
  98. --- 第二种
  99. mysql> explain select e.emp_no,
  100. -> concat(last_name,' ', first_name) as emp_name, gender, title
  101. -> from employees as e inner join titles as t
  102. -> on e.emp_no = t.emp_no limit 5;
  103. +----+-------------+-------+------------+------+---------------+---------+---------+--------------------+--------+----------+-------------+
  104. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  105. +----+-------------+-------+------------+------+---------------+---------+---------+--------------------+--------+----------+-------------+
  106. | 1 | SIMPLE | e | NULL | ALL | PRIMARY | NULL | NULL | NULL | 298124 | 100.00 | NULL |
  107. | 1 | SIMPLE | t | NULL | ref | PRIMARY | PRIMARY | 4 | employees.e.emp_no | 1 | 100.00 | Using index |
  108. +----+-------------+-------+------------+------+---------------+---------+---------+--------------------+--------+----------+-------------+
  109. 2 rows in set, 1 warning (0.00 sec)
  110. -- 通过explain看两条语句的执行计划,发现是一样的,所以性能上是一样的,只是语法的不同

OUTER JOIN

  1. --
  2. -- 左连接 left join
  3. --
  4. mysql> use burn_test
  5. Reading table information for completion of table and column names
  6. You can turn off this feature to get a quicker startup with -A
  7. Database changed
  8. mysql> create table test_left_join_1(a int);
  9. Query OK, 0 rows affected (0.16 sec)
  10. mysql> create table test_left_join_2(b int);
  11. Query OK, 0 rows affected (0.14 sec)
  12. mysql> insert into test_left_join_1 values (1);
  13. Query OK, 1 row affected (0.03 sec)
  14. mysql> insert into test_left_join_1 values (2);
  15. Query OK, 1 row affected (0.03 sec)
  16. mysql> insert into test_left_join_2 values (1);
  17. Query OK, 1 row affected (0.03 sec)
  18. mysql> select * from test_left_join_1;
  19. +------+
  20. | a |
  21. +------+
  22. | 1 |
  23. | 2 |
  24. +------+
  25. 2 rows in set (0.00 sec)
  26. mysql> select * from test_left_join_2;
  27. +------+
  28. | b |
  29. +------+
  30. | 1 |
  31. +------+
  32. 1 row in set (0.00 sec)
  33. mysql> select * from
  34. -> test_left_join_1 as t1
  35. -> left join -- 使用left join
  36. -> test_left_join_2 as t2
  37. -> on t1.a = t2.b;
  38. +------+------+
  39. | a | b |
  40. +------+------+
  41. | 1 | 1 | -- 满足条件的,显示t2中该条记录的值
  42. | 2 | NULL | -- 不满足条件的,用NULL填充
  43. +------+------+
  44. 2 rows in set (0.00 sec)
  45. -- left join 左表 left join 右表 on 条件;
  46. -- 左表全部显示,右表是匹配表,
  47. -- 如果右表的某条记录满足 [on 条件] 匹配,则该记录显示
  48. -- 如果右表的某条记录 满足 匹配,则该记录显示NULL
  49. --
  50. -- 右连接 right join (继续使用test_left_join_12两张表)
  51. --
  52. mysql> select * from
  53. -> test_left_join_1 as t1
  54. -> right join -- 使用right join
  55. -> test_left_join_2 as t2
  56. -> on t1.a = t2.b;
  57. +------+------+
  58. | a | b |
  59. +------+------+
  60. | 1 | 1 | -- 右表(t2)全部显示
  61. +------+------+
  62. 1 row in set (0.00 sec)
  63. -- right join 左表 right join 右表 on 条件
  64. -- 右表全部显示,左边是匹配表
  65. -- 同样和left join,满足则显示,不满足且右表中有值,则填充NULL
  66. mysql> insert into test_left_join_2 values (3); -- t2 中再增加一条记录
  67. Query OK, 1 row affected (0.03 sec)
  68. mysql> select * from
  69. -> test_left_join_1 as t1
  70. -> right join
  71. -> test_left_join_2 as t2
  72. -> on t1.a = t2.b;
  73. +------+------+
  74. | a | b |
  75. +------+------+
  76. | 1 | 1 |
  77. | NULL | 3 | -- 右表存在,左表没有,用NULL填充
  78. +------+------+
  79. 2 rows in set (0.00 sec)
  80. --
  81. -- 查找在t1表,而不在t2表的数据
  82. --
  83. mysql> select * from
  84. -> test_left_join_1 as t1
  85. -> left join
  86. -> test_left_join_2 as t2
  87. -> on t1.a = t2.b where t2.b is null;
  88. +------+------+
  89. | a | b |
  90. +------+------+
  91. | 2 | NULL | -- 数据1 t1t2中都有,所以不显示
  92. +------+------+
  93. 1 row in set (0.00 sec)
  94. -- left join left outer join , outer关键字可以省略
  95. -- right join right outer join , outer 关键字可以省略
  96. -- join无论inner还是outer,列名不需要一样,甚至列的类型也可以不一样,会进行转换。
  97. -- 一般情况下,表设计合理,需要关联的字段类型应该是一样的
  98. --
  99. -- 查找哪些员工不是经理
  100. --
  101. mysql> select e.emp_no,
  102. -> concat(last_name,' ', first_name) as emp_name, gender, d.dept_no
  103. -> from employees as e left join dept_manager as d
  104. -> on e.emp_no = d.emp_no
  105. -> where d.emp_no is null limit 5;
  106. +--------+-------------------+--------+---------+
  107. | emp_no | emp_name | gender | dept_no | -- dept_nodept_manager的字段
  108. +--------+-------------------+--------+---------+
  109. | 10001 | Facello Georgi | M | NULL |
  110. | 10002 | Simmel Bezalel | F | NULL |
  111. | 10003 | Bamford Parto | M | NULL |
  112. | 10004 | Koblick Chirstian | M | NULL |
  113. | 10005 | Maliniak Kyoichi | M | NULL |
  114. +--------+-------------------+--------+---------+
  115. 5 rows in set (0.00 sec)
  116. -- inner join中,过滤条件放在where或者on中都是可以的
  117. -- outer join 条件放在whereon中是不一样的
  118. mysql> select * from
  119. -> test_left_join_1 as t1
  120. -> left join
  121. -> test_left_join_2 as t2
  122. -> on t1.a = t2.b
  123. -> where t2.b is null;
  124. +------+------+
  125. | a | b |
  126. +------+------+
  127. | 2 | NULL |
  128. +------+------+
  129. 1 row in set (0.00 sec)
  130. mysql> select * from
  131. -> test_left_join_1 as t1
  132. -> left join
  133. -> test_left_join_2 as t2
  134. -> on t1.a = t2.b
  135. -> and t2.b is null; -- 除了a=b, 还要找到b=null的,但是b里面没有null,所有a全部显示,b全为null
  136. +------+------+
  137. | a | b |
  138. +------+------+
  139. | 1 | NULL |
  140. | 2 | NULL |
  141. +------+------+
  142. 2 rows in set (0.00 sec)
  143. -- ON 参与outer join的结果的生成,而where只是对结果的一个过滤

GROUP BY

  1. --
  2. -- 找出同一个部门的员工数量
  3. --
  4. mysql> select dept_no, count(dept_no) -- count是得到数量,这里就是分组函数
  5. -> from dept_emp
  6. -> group by dept_no; -- 通过 dept_no 分组
  7. +---------+----------------+
  8. | dept_no | count(dept_no) |
  9. +---------+----------------+
  10. | d001 | 20211 |
  11. | d002 | 17346 |
  12. | d003 | 17786 |
  13. | d004 | 73485 |
  14. | d005 | 85707 |
  15. | d006 | 20117 |
  16. | d007 | 52245 |
  17. | d008 | 21126 |
  18. | d009 | 23580 |
  19. +---------+----------------+
  20. 9 rows in set (0.10 sec)
  21. --
  22. -- 选出部门人数 > 50000
  23. --
  24. mysql> select dept_no, count(dept_no)
  25. -> from dept_emp
  26. -> group by dept_no
  27. -> having count(dept_no) > 50000; -- 如果是对分组的聚合函数做过滤,使用having,用where报语法错误
  28. +---------+----------------+
  29. | dept_no | count(dept_no) |
  30. +---------+----------------+
  31. | d004 | 73485 |
  32. | d005 | 85707 |
  33. | d007 | 52245 |
  34. +---------+----------------+
  35. 3 rows in set (0.09 sec)
  36. --
  37. -- 每个用户每个月产生的订单数目
  38. --
  39. mysql> desc orders;
  40. +-----------------+-------------+------+-----+---------+-------+
  41. | Field | Type | Null | Key | Default | Extra |
  42. +-----------------+-------------+------+-----+---------+-------+
  43. | o_orderkey | int(11) | NO | PRI | NULL | | -- 订单ID
  44. | o_custkey | int(11) | YES | MUL | NULL | | -- 客户ID
  45. | o_orderstatus | char(1) | YES | | NULL | |
  46. | o_totalprice | double | YES | | NULL | |
  47. | o_orderDATE | date | YES | MUL | NULL | | -- 订单日期
  48. | o_orderpriority | char(15) | YES | | NULL | |
  49. | o_clerk | char(15) | YES | | NULL | |
  50. | o_shippriority | int(11) | YES | | NULL | |
  51. | o_comment | varchar(79) | YES | | NULL | |
  52. +-----------------+-------------+------+-----+---------+-------+
  53. 9 rows in set (0.00 sec)
  54. mysql> select o_orderkey, o_custkey, o_orderDATE from orders limit 3;
  55. +------------+-----------+-------------+
  56. | o_orderkey | o_custkey | o_orderDATE |
  57. +------------+-----------+-------------+
  58. | 1 | 36901 | 1996-01-02 |
  59. | 2 | 78002 | 1996-12-01 |
  60. | 3 | 123314 | 1993-10-14 |
  61. +------------+-----------+-------------+
  62. 3 rows in set (0.00 sec)
  63. --
  64. -- 查找客户每年每月产生的订单数
  65. --
  66. mysql> select o_custkey, count(o_orderkey), -> year(o_orderDATE), month(o_orderDATE)
  67. -> from orders
  68. -> group by o_custkey, year(o_orderDATE), month(o_orderDATE)
  69. -> limit 10;
  70. +-----------+-------------------+-------------------+--------------------+
  71. | o_custkey | count(o_orderkey) | year(o_orderDATE) | month(o_orderDATE) |
  72. +-----------+-------------------+-------------------+--------------------+
  73. | 1 | 1 | 1992 | 4 |
  74. | 1 | 1 | 1992 | 8 |
  75. | 1 | 1 | 1996 | 6 |
  76. | 1 | 1 | 1996 | 7 |
  77. | 1 | 1 | 1996 | 12 |
  78. | 1 | 1 | 1997 | 3 |
  79. | 2 | 1 | 1992 | 4 |
  80. | 2 | 1 | 1994 | 5 |
  81. | 2 | 1 | 1994 | 8 |
  82. | 2 | 1 | 1994 | 12 |
  83. +-----------+-------------------+-------------------+--------------------+
  84. 10 rows in set (8.97 sec)
  85. -- 使用 date_format 函数
  86. mysql> select o_custkey, count(o_orderkey),
  87. -> date_format(o_orderDATE, '%Y-%m') as date
  88. -> from orders
  89. -> group by o_custkey, date_format(o_orderDATE, '%Y-%m')
  90. -> limit 10;
  91. +-----------+-------------------+---------+
  92. | o_custkey | count(o_orderkey) | date |
  93. +-----------+-------------------+---------+
  94. | 1 | 1 | 1992-04 |
  95. | 1 | 1 | 1992-08 |
  96. | 1 | 1 | 1996-06 |
  97. | 1 | 1 | 1996-07 |
  98. | 1 | 1 | 1996-12 |
  99. | 1 | 1 | 1997-03 |
  100. | 2 | 1 | 1992-04 |
  101. | 2 | 1 | 1994-05 |
  102. | 2 | 1 | 1994-08 |
  103. | 2 | 1 | 1994-12 |
  104. +-----------+-------------------+---------+
  105. 10 rows in set (11.46 sec)

LIMIT & ORDER BY

  1. mysql> select * from employees limit 1; -- employees 随机 取出一条数据,结果是不确定的
  2. +--------+------------+------------+-----------+--------+------------+
  3. | emp_no | birth_date | first_name | last_name | gender | hire_date |
  4. +--------+------------+------------+-----------+--------+------------+
  5. | 10001 | 1953-09-02 | Georgi | Facello | M | 1986-06-26 |
  6. +--------+------------+------------+-----------+--------+------------+
  7. 1 row in set (0.00 sec)
  8. --
  9. -- order by col_name 根据某列的值进行排序
  10. -- asc 升序(default)
  11. -- desc 降序
  12. --
  13. mysql> select * from employees order by emp_no asc limit 1; -- 使用order by col_name asc进行升序排序
  14. +--------+------------+------------+-----------+--------+------------+
  15. | emp_no | birth_date | first_name | last_name | gender | hire_date |
  16. +--------+------------+------------+-----------+--------+------------+
  17. | 10001 | 1953-09-02 | Georgi | Facello | M | 1986-06-26 |
  18. +--------+------------+------------+-----------+--------+------------+
  19. 1 row in set (0.00 sec)
  20. mysql> select * from employees order by emp_no limit 1; -- 默认就是升序的
  21. +--------+------------+------------+-----------+--------+------------+
  22. | emp_no | birth_date | first_name | last_name | gender | hire_date |
  23. +--------+------------+------------+-----------+--------+------------+
  24. | 10001 | 1953-09-02 | Georgi | Facello | M | 1986-06-26 | -- 结果和上面一致
  25. +--------+------------+------------+-----------+--------+------------+
  26. 1 row in set (0.00 sec)
  27. mysql> select * from employees order by emp_no desc limit 1; -- desc表示降序
  28. +--------+------------+------------+-----------+--------+------------+
  29. | emp_no | birth_date | first_name | last_name | gender | hire_date |
  30. +--------+------------+------------+-----------+--------+------------+
  31. | 499999 | 1958-05-01 | Sachin | Tsukuda | M | 1997-11-30 | -- 降序显示
  32. +--------+------------+------------+-----------+--------+------------+
  33. -- 通过order by排序后 limit 1 才是确定的
  34. 1 row in set (0.00 sec)
  35. mysql> show create table employees\G
  36. *************************** 1. row ***************************
  37. Table: employees
  38. Create Table: CREATE TABLE `employees` (
  39. `emp_no` int(11) NOT NULL,
  40. `birth_date` date NOT NULL,
  41. `first_name` varchar(14) NOT NULL,
  42. `last_name` varchar(16) NOT NULL,
  43. `gender` enum('M','F') NOT NULL,
  44. `hire_date` date NOT NULL,
  45. PRIMARY KEY (`emp_no`) -- emp_no 是主键,order by 主键 不会创建临时表的,主键(索引)本身有序
  46. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
  47. 1 row in set (0.00 sec)
  48. mysql> select * from employees order by emp_no asc limit 5,5; -- limit start, offset
  49. -- 从第5 开始取,取5条出来
  50. +--------+------------+------------+-----------+--------+------------+
  51. | emp_no | birth_date | first_name | last_name | gender | hire_date |
  52. +--------+------------+------------+-----------+--------+------------+
  53. | 10006 | 1953-04-20 | Anneke | Preusig | F | 1989-06-02 |
  54. | 10007 | 1957-05-23 | Tzvetan | Zielinski | F | 1989-02-10 |
  55. | 10008 | 1958-02-19 | Saniya | Kalloufi | M | 1994-09-15 |
  56. | 10009 | 1952-04-19 | Sumant | Peac | F | 1985-02-18 |
  57. | 10010 | 1963-06-01 | Duangkaew | Piveteau | F | 1989-08-24 |
  58. +--------+------------+------------+-----------+--------+------------+
  59. 5 rows in set (0.00 sec)
  60. -- 以上这个语法有一种分页的效果,但是会随着start的增加,性能会下降,因为会扫描表(从 1 start)
  61. -- 相对比较推荐的方法
  62. mysql> select * from employees where emp_no > 20000 order by emp_no limit 5;
  63. +--------+------------+------------+-----------+--------+------------+
  64. | emp_no | birth_date | first_name | last_name | gender | hire_date |
  65. +--------+------------+------------+-----------+--------+------------+
  66. | 20001 | 1962-05-16 | Atreye | Eppinger | M | 1990-04-18 |
  67. | 20002 | 1955-12-25 | Jaber | Brender | M | 1988-01-26 |
  68. | 20003 | 1953-04-11 | Munehiko | Coors | F | 1991-02-07 |
  69. | 20004 | 1952-03-07 | Radoslaw | Pfau | M | 1995-11-24 |
  70. | 20005 | 1956-02-20 | Licheng | Przulj | M | 1992-07-17 |
  71. +--------+------------+------------+-----------+--------+------------+
  72. 5 rows in set (0.00 sec)
  73. -- (当然推荐把热数据放cache里,比如Redis

ORDER BY 是把已经查询好的结果集进行排序。

UNION

官方文档:https://dev.mysql.com/doc/refman/5.7/en/union.html

UNION 的作用是将两个查询的结果集进行合并。
UNION 必须由两条或两条以上的 SELECT 语句组成,语句之间用关键字 UNION 分隔。
UNION 中的每个查询必须包含相同的列(类型相同或可以隐式转换)、表达式或聚集函数。

  1. mysql> create table test_union_1(a int, b int);
  2. Query OK, 0 rows affected (0.18 sec)
  3. mysql> create table test_union_2(a int, c int);
  4. Query OK, 0 rows affected (0.15 sec)
  5. mysql> insert into test_union_1 values(1, 2), (3, 4), (5, 6), (10, 20);
  6. Query OK, 4 rows affected (0.06 sec)
  7. Records: 4 Duplicates: 0 Warnings: 0
  8. mysql> insert into test_union_2 values(10, 20), (30, 40), (50, 60);
  9. Query OK, 3 rows affected (0.03 sec)
  10. Records: 3 Duplicates: 0 Warnings: 0
  11. mysql> select * from test_union_1;
  12. +------+------+
  13. | a | b |
  14. +------+------+
  15. | 1 | 2 |
  16. | 3 | 4 |
  17. | 5 | 6 |
  18. | 10 | 20 | -- test_union_1 中的10, 20
  19. +------+------+
  20. 4 rows in set (0.00 sec)
  21. mysql> select * from test_union_2;
  22. +------+------+
  23. | a | c |
  24. +------+------+
  25. | 10 | 20 | -- test_union_2 中的10, 20
  26. | 30 | 40 |
  27. | 50 | 60 |
  28. +------+------+
  29. 3 rows in set (0.00 sec)
  30. mysql> select a, b as t from test_union_1
  31. -> union
  32. -> select * from test_union_2;
  33. +------+------+
  34. | a | t |
  35. +------+------+
  36. | 1 | 2 |
  37. | 3 | 4 |
  38. | 5 | 6 |
  39. | 10 | 20 | -- 只出现了一次 10, 20union会去重
  40. | 30 | 40 |
  41. | 50 | 60 |
  42. +------+------+
  43. 6 rows in set (0.00 sec)
  44. mysql> select a, b as t from test_union_1
  45. -> union all -- 使用 union all 可以不去重
  46. -> select * from test_union_2;
  47. +------+------+
  48. | a | t |
  49. +------+------+
  50. | 1 | 2 |
  51. | 3 | 4 |
  52. | 5 | 6 |
  53. | 10 | 20 | -- test_union_1 中的10, 20
  54. | 10 | 20 | -- test_union_2 中的10, 20
  55. | 30 | 40 |
  56. | 50 | 60 |
  57. +------+------+
  58. 7 rows in set (0.00 sec)
  59. mysql> select a, b as t from test_union_1 where a > 2
  60. -> union
  61. -> select * from test_union_2 where c > 50; -- 使用where过滤也可以
  62. +------+------+
  63. | a | t |
  64. +------+------+
  65. | 3 | 4 |
  66. | 5 | 6 |
  67. | 10 | 20 |
  68. | 50 | 60 |
  69. +------+------+
  70. 4 rows in set (0.00 sec)

:::warning 如果知道数据本身具有唯一性,没有重复,则建议使用 union all,因为 union 会做去重操作,性能会比 union all 要低。 :::

作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/vs0y6s 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。