板凳-------Mysql cookbook学习 (十--7)

第8章:生成摘要

8.0 引言

sql 复制代码
mysql> select * from states order by name;
+----------------+--------+------------+----------+
| name           | abbrev | statehood  | pop      |
+----------------+--------+------------+----------+
| Alabama        | AL     | 1819-12-14 |  5039877 |
| Alaska         | AK     | 1959-01-03 |   732673 |
| Arizona        | AZ     | 1912-02-14 |  7276316 |
| Arkansas       | AR     | 1836-06-15 |  3025891 |
| California     | CA     | 1850-09-09 | 39237836 |
| Colorado       | CO     | 1876-08-01 |  5812069 |
| Connecticut    | CT     | 1788-01-09 |  3605597 |
| Delaware       | DE     | 1787-12-07 |  1003384 |
| Florida        | FL     | 1845-03-03 | 21781128 |
| Georgia        | GA     | 1788-01-02 | 10799566 |
| Hawaii         | HI     | 1959-08-21 |  1441553 |
| Idaho          | ID     | 1890-07-03 |  1900923 |
| Illinois       | IL     | 1818-12-03 | 12671469 |
| Indiana        | IN     | 1816-12-11 |  6805985 |
| Iowa           | IA     | 1846-12-28 |  3193079 |
| Kansas         | KS     | 1861-01-29 |  2934582 |
| Kentucky       | KY     | 1792-06-01 |  4509394 |
| Louisiana      | LA     | 1812-04-30 |  4624047 |
| Maine          | ME     | 1820-03-15 |  1372247 |
| Maryland       | MD     | 1788-04-28 |  6165129 |
| Massachusetts  | MA     | 1788-02-06 |  6984723 |
| Michigan       | MI     | 1837-01-26 | 10050811 |
| Minnesota      | MN     | 1858-05-11 |  5707390 |
| Mississippi    | MS     | 1817-12-10 |  2949965 |
| Missouri       | MO     | 1821-08-10 |  6168187 |
| Montana        | MT     | 1889-11-08 |  1104271 |
| Nebraska       | NE     | 1867-03-01 |  1963692 |
| Nevada         | NV     | 1864-10-31 |  3143991 |
| New Hampshire  | NH     | 1788-06-21 |  1388992 |
| New Jersey     | NJ     | 1787-12-18 |  9267130 |
| New Mexico     | NM     | 1912-01-06 |  2115877 |
| New York       | NY     | 1788-07-26 | 19835913 |
| North Carolina | NC     | 1789-11-21 | 10551162 |
| North Dakota   | ND     | 1889-11-02 |   774948 |
| Ohio           | OH     | 1803-03-01 | 11780017 |
| Oklahoma       | OK     | 1907-11-16 |  3986639 |
| Oregon         | OR     | 1859-02-14 |  4246155 |
| Pennsylvania   | PA     | 1787-12-12 | 12964056 |
| Rhode Island   | RI     | 1790-05-29 |  1095610 |
| South Carolina | SC     | 1788-05-23 |  5190705 |
| South Dakota   | SD     | 1889-11-02 |   895376 |
| Tennessee      | TN     | 1796-06-01 |  6975218 |
| Texas          | TX     | 1845-12-29 | 29527941 |
| Utah           | UT     | 1896-01-04 |  3337975 |
| Vermont        | VT     | 1791-03-04 |   645570 |
| Virginia       | VA     | 1788-06-25 |  8642274 |
| Washington     | WA     | 1889-11-11 |  7738692 |
| West Virginia  | WV     | 1863-06-20 |  1782959 |
| Wisconsin      | WI     | 1848-05-29 |  5895908 |
| Wyoming        | WY     | 1890-07-10 |   578803 |
+----------------+--------+------------+----------+
50 rows in set (0.02 sec)

8.1 使用count函数生成摘要

sql 复制代码
mysql> select count(*) from driver_log;
+----------+
| count(*) |
+----------+
|       10 |
+----------+
1 row in set (0.01 sec)

mysql> select count(*) from states;
+----------+
| count(*) |
+----------+
|       50 |
+----------+
1 row in set (0.00 sec)

mysql> select table_rows from information_schema.tables
    -> where table_schema='cookbook' and table_name = 'states';
+------------+
| TABLE_ROWS |
+------------+
|         50 |
+------------+
1 row in set (0.05 sec)

mysql> select count(*) from driver_log where miles > 200;
+----------+
| count(*) |
+----------+
|        4 |
+----------+
1 row in set (0.00 sec)

mysql> select count(*) from driver_log where name = 'Suzi';
+----------+
| count(*) |
+----------+
|        2 |
+----------+
1 row in set (0.00 sec)

mysql> select count(*) from states where statehood < '1900-01-01';
+----------+
| count(*) |
+----------+
|       45 |
+----------+
1 row in set (0.01 sec)

mysql> select count(*) from states where statehood < '1900-01-01';
+----------+
| count(*) |
+----------+
|       45 |
+----------+
1 row in set (0.00 sec)

mysql> select count(*) from states
    -> where statehood between '1800-01-01' and '1899-12-31';
+----------+
| count(*) |
+----------+
|       29 |
+----------+
1 row in set (0.00 sec)

mysql> select
    -> count(if(dayofweek(trav_date)=7, 1, null)) as 'Saturday tripe',
    -> count(if(dayofweek(trav_date)=1, 1, null)) as 'Sunday trips'
    -> from driver_log;
+----------------+--------------+
| Saturday tripe | Sunday trips |
+----------------+--------------+
|              3 |            1 |
+----------------+--------------+
1 row in set (0.00 sec)

mysql> select
    -> count(if(dayofweek(trav_date) in (1, 7), 1, null)) as 'weekend trips',
    -> count(if(dayofweek(trav_date) in (1, 7), null, 1)) as 'weekday trips'
    -> from driver_log;
+---------------+---------------+
| weekend trips | weekday trips |
+---------------+---------------+
|             4 |             6 |
+---------------+---------------+
1 row in set (0.00 sec)

mysql> create view trip_summary_view as
    -> select
    -> count(if(dayofweek(trav_date) in(1, 7), 1, null)) as 'weekend trips',
    -> count(if(dayofweek(trav_date) in(1, 7), null, 1)) as 'weekday trips'
    -> from driver_log;
Query OK, 0 rows affected (0.03 sec)

mysql> select * from trip_summary_view;
+---------------+---------------+
| weekend trips | weekday trips |
+---------------+---------------+
|             4 |             6 |
+---------------+---------------+
1 row in set (0.01 sec)

8.2 使用min()和max()函数生成摘要

sql 复制代码
mysql> select
    -> min(t) as earliest, max(t) as latest,
    -> min(size) as smallest, max(size) as largest
    -> from mail;
+---------------------+---------------------+----------+---------+
| earliest            | latest              | smallest | largest |
+---------------------+---------------------+----------+---------+
| 2006-05-11 10:15:08 | 2006-05-19 22:21:51 |      271 | 2394482 |
+---------------------+---------------------+----------+---------+
1 row in set (0.01 sec)

mysql> select
    -> min(miles) as shortest, max(miles) as longest
    -> from driver_log;
+----------+---------+
| shortest | longest |
+----------+---------+
|       79 |     502 |
+----------+---------+
1 row in set (0.00 sec)

mysql> select
    -> min(pop) as 'fewest people', max(pop) as 'most people'
    -> from states;
+---------------+-------------+
| fewest people | most people |
+---------------+-------------+
|        578803 |    39237836 |
+---------------+-------------+
1 row in set (0.00 sec)

mysql> select min(name), max(name) from states;
+-----------+-----------+
| min(name) | max(name) |
+-----------+-----------+
| Alabama   | Wyoming   |
+-----------+-----------+
1 row in set (0.00 sec)

mysql> select
    -> min(char_length(name)) as shortest,
    -> max(char_length(name)) as longest
    -> from states;
+----------+---------+
| shortest | longest |
+----------+---------+
|        4 |      14 |
+----------+---------+
1 row in set (0.00 sec)

8.3 使用sum()和avg()函数生成摘要

sql 复制代码
mysql> select
    -> sum(size) as 'total traffic',
    -> avg(size) as 'average message size'
    -> from mail;
+---------------+----------------------+
| total traffic | average message size |
+---------------+----------------------+
|       3798185 |          237386.5625 |
+---------------+----------------------+
1 row in set (0.00 sec)

mysql> select
    -> sum(miles) as 'total miles',
    -> avg(miles) as 'average_mile/day'
    -> from driver_log;
+-------------+------------------+
| total miles | average_mile/day |
+-------------+------------------+
|        2166 |         216.6000 |
+-------------+------------------+
1 row in set (0.00 sec)

mysql> select sum(pop) from states;
+-----------+
| sum(pop)  |
+-----------+
| 331223695 |
+-----------+
1 row in set (0.00 sec)

mysql> select t1 from time_val;
+----------+
| t1       |
+----------+
| 15:00:00 |
| 05:01:30 |
| 12:30:20 |
+----------+
3 rows in set (0.01 sec)

mysql> select sum(time_to_sec(t1)) as 'total seconds',
    -> sec_to_time(sum(time_to_sec(t1))) as 'total time'
    -> from time_val;
+---------------+------------+
| total seconds | total time |
+---------------+------------+
|        117110 | 32:31:50   |
+---------------+------------+
1 row in set (0.01 sec)

8.4 使用distinct函数消除重复

sql 复制代码
mysql> select distinct name from driver_log order by name;
+-------+
| name  |
+-------+
| Ben   |
| Henry |
| Suzi  |
+-------+
3 rows in set (0.00 sec)

mysql> select name from driver_log;
+-------+
| name  |
+-------+
| Ben   |
| Suzi  |
| Henry |
| Henry |
| Ben   |
| Henry |
| Suzi  |
| Henry |
| Ben   |
| Henry |
+-------+
10 rows in set (0.00 sec)

mysql> select count(distinct name) from driver_log;
+----------------------+
| count(distinct name) |
+----------------------+
|                    3 |
+----------------------+
1 row in set (0.00 sec)

mysql> select distinct srcuser, dstuser from mail
    -> order by srcuser, dstuser;
+---------+---------+
| srcuser | dstuser |
+---------+---------+
| barb    | barb    |
| barb    | tricia  |
| gene    | barb    |
| gene    | gene    |
| gene    | tricia  |
| phil    | barb    |
| phil    | phil    |
| phil    | tricia  |
| tricia  | gene    |
| tricia  | phil    |
+---------+---------+
10 rows in set (0.00 sec)

mysql> select count(distinct srcuser, dstuser) from mail;
+----------------------------------+
| count(distinct srcuser, dstuser) |
+----------------------------------+
|                               10 |
+----------------------------------+
1 row in set (0.00 sec)

mysql> select count(distinct hour(t)) from mail;
+-------------------------+
| count(distinct hour(t)) |
+-------------------------+
|                      12 |
+-------------------------+
1 row in set (0.00 sec)

mysql> select distinct hour(t) as hour from mail order by hour;
+------+
| hour |
+------+
|    7 |
|    8 |
|    9 |
|   10 |
|   11 |
|   12 |
|   13 |
|   14 |
|   15 |
|   17 |
|   22 |
|   23 |
+------+
12 rows in set (0.00 sec)

8.5 查找数值相关的最大值和最小值

sql 复制代码
mysql> select max(pop) from states;
+----------+
| max(pop) |
+----------+
| 39237836 |
+----------+
1 row in set (0.00 sec)

mysql> select max(pop), name from states where pop = max(pop);
ERROR 1111 (HY000): Invalid use of group function
mysql> set @max=(select max(pop) from states);
Query OK, 0 rows affected (0.01 sec)

mysql> select pop as 'highest population', name from states where  pop = @max;
+--------------------+------------+
| highest population | name       |
+--------------------+------------+
|           39237836 | California |
+--------------------+------------+
1 row in set (0.00 sec)

mysql> select pop as 'highest population', name from states
    -> where pop = (select max(pop) from states);
+--------------------+------------+
| highest population | name       |
+--------------------+------------+
|           39237836 | California |
+--------------------+------------+
1 row in set (0.00 sec)

mysql> select min(char_length(vtext)) from kjv;
+-------------------------+
| min(char_length(vtext)) |
+-------------------------+
|                      11 |
+-------------------------+
1 row in set (0.11 sec)

mysql> select bname, cnum, vnum, vtext from kjv
    -> where char_length(vtext) = (select min(char_length(vtext)) from kjv);
+-------+------+------+-------------+
| bname | cnum | vnum | vtext       |
+-------+------+------+-------------+
| John  |   11 |   35 | Jesus wept. |
+-------+------+------+-------------+
1 row in set (0.09 sec)

mysql> select * from t;
+------+
| val  |
+------+
| 3    |
| 100  |
| NULL |
| NULL |
| 9    |
+------+
5 rows in set (0.00 sec)

mysql> drop table if exists ts;
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> create table ts select max(pop) as maxpop from states;
Query OK, 1 row affected (0.05 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> select states.* from states inner join ts on states.pop = ts.maxpop;
+------------+--------+------------+----------+
| name       | abbrev | statehood  | pop      |
+------------+--------+------------+----------+
| California | CA     | 1850-09-09 | 39237836 |
+------------+--------+------------+----------+
1 row in set (0.01 sec)

8.6 控制min()函数和max()函数的字符串大小写区分

sql 复制代码
mysql> use employees;
Database changed

mysql> show create table employees;
+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table     | Create Table                                                                                                                                                                                                                                                                                                           |
+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| employees | CREATE TABLE `employees` (
  `emp_no` int NOT NULL,
  `birth_date` date NOT NULL,
  `first_name` varchar(14) NOT NULL,
  `last_name` varchar(16) NOT NULL,
  `gender` enum('M','F') NOT NULL,
  `hire_date` date NOT NULL,
  PRIMARY KEY (`emp_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT
    ->     MAX(last_name COLLATE utf8mb4_bin) AS max_last_name,
    ->     MIN(last_name COLLATE utf8mb4_bin) AS min_last_name
    -> FROM employees;
+---------------+---------------+
| max_last_name | min_last_name |
+---------------+---------------+
| dAstous       | Aamodt        |
+---------------+---------------+
1 row in set (0.31 sec)

mysql> CREATE TABLE tb1 (
    ->     col_a INT(11) DEFAULT NULL,
    ->     col_b CHAR(10) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL,
    ->     col_c CHAR(10) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL,
    ->     col_d CHAR(10) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL,
    ->     KEY col_a (col_a),
    ->     KEY col_b (col_b)
    -> ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Query OK, 0 rows affected, 1 warning (0.02 sec)

mysql> INSERT INTO tb1 (col_a, col_b, col_c, col_d) VALUES
    -> (1, 'Apple', 'Red', 'FRUIT'),
    -> (2, 'Banana', 'Yellow', 'FRUIT'),
    -> (3, 'Dog', 'Brown', 'ANIMAL'),
    -> (4, 'Sky', 'Blue', 'NATURE'),
    -> (5, 'Sun', 'Yellow', 'NATURE'),
    -> (6, 'Coffee', 'Black', 'DRINK'),
    -> (7, 'Snow', 'White', 'WEATHER'),
    -> (8, 'Cat', 'Gray', 'ANIMAL'),
    -> (9, 'Rose', 'Pink', 'FLOWER'),
    -> (10, 'Book', 'Green', 'OBJECT');
Query OK, 10 rows affected (0.01 sec)
Records: 10  Duplicates: 0  Warnings: 0

mysql> select * from tbl;
ERROR 1146 (42S02): Table 'employees.tbl' doesn't exist
mysql> show tables;
+----------------------+
| Tables_in_employees  |
+----------------------+
| current_dept_emp     |
| data_quality_monitor |
| data_quality_results |
| departments          |
| dept_emp             |
| dept_emp_latest_date |
| dept_manager         |
| employees            |
| news                 |
| salaries             |
| t                    |
| tb1                  |
| test                 |
| titles               |
+----------------------+
14 rows in set (0.00 sec)

mysql> SELECT * FROM tb1 ORDER BY col_a;
+-------+--------+--------+---------+
| col_a | col_b  | col_c  | col_d   |
+-------+--------+--------+---------+
|     1 | Apple  | Red    | FRUIT   |
|     2 | Banana | Yellow | FRUIT   |
|     3 | Dog    | Brown  | ANIMAL  |
|     4 | Sky    | Blue   | NATURE  |
|     5 | Sun    | Yellow | NATURE  |
|     6 | Coffee | Black  | DRINK   |
|     7 | Snow   | White  | WEATHER |
|     8 | Cat    | Gray   | ANIMAL  |
|     9 | Rose   | Pink   | FLOWER  |
|    10 | Book   | Green  | OBJECT  |
+-------+--------+--------+---------+
10 rows in set (0.00 sec)

mysql> -- 不区分大小写的查询(col_b列)
mysql> SELECT * FROM tb1 WHERE col_b = 'apple';
+-------+-------+-------+-------+
| col_a | col_b | col_c | col_d |
+-------+-------+-------+-------+
|     1 | Apple | Red   | FRUIT |
+-------+-------+-------+-------+
1 row in set (0.00 sec)

mysql> use cookbook;
Database changed
mysql> DROP TABLE IF EXISTS tb1;
Query OK, 0 rows affected, 1 warning (0.02 sec)

mysql> CREATE TABLE tb1 (
    ->     col_a INT DEFAULT NULL,
    ->     col_b CHAR(10) CHARACTER SET gbk COLLATE gbk_chinese_ci DEFAULT NULL,
    ->     col_c CHAR(10) CHARACTER SET gbk COLLATE gbk_chinese_ci DEFAULT NULL,
    ->     col_d CHAR(10) CHARACTER SET gbk COLLATE gbk_bin DEFAULT NULL,
    ->     KEY (col_a),
    ->     KEY (col_b)
    -> ) ENGINE=MyISAM DEFAULT CHARSET=gbk;
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO tb1 (col_a, col_b, col_c, col_d) VALUES
    -> (1, 'Apple', 'Red', 'FRUIT'),
    -> (2, 'Banana', 'Yellow', 'FRUIT'),
    -> (3, 'Dog', 'Brown', 'ANIMAL'),
    -> (4, 'Sky', 'Blue', 'NATURE'),
    -> (5, 'Sun', 'Yellow', 'NATURE'),
    -> (6, 'Coffee', 'Black', 'DRINK'),
    -> (7, 'Snow', 'White', 'WEATHER'),
    -> (8, 'Cat', 'Gray', 'ANIMAL'),
    -> (9, 'Rose', 'Pink', 'FLOWER'),
    -> (10, 'Book', 'Green', 'OBJECT');
Query OK, 10 rows affected (0.01 sec)
Records: 10  Duplicates: 0  Warnings: 0

mysql> show create table tbl;
ERROR 1146 (42S02): Table 'cookbook.tbl' doesn't exist
mysql> SELECT * FROM tb1 ORDER BY col_a;
+-------+--------+--------+---------+
| col_a | col_b  | col_c  | col_d   |
+-------+--------+--------+---------+
|     1 | Apple  | Red    | FRUIT   |
|     2 | Banana | Yellow | FRUIT   |
|     3 | Dog    | Brown  | ANIMAL  |
|     4 | Sky    | Blue   | NATURE  |
|     5 | Sun    | Yellow | NATURE  |
|     6 | Coffee | Black  | DRINK   |
|     7 | Snow   | White  | WEATHER |
|     8 | Cat    | Gray   | ANIMAL  |
|     9 | Rose   | Pink   | FLOWER  |
|    10 | Book   | Green  | OBJECT  |
+-------+--------+--------+---------+
10 rows in set (0.00 sec)

mysql> SELECT
    ->     MIN(col_b COLLATE gbk_chinese_ci) AS min_val,
    ->     MAX(col_b COLLATE gbk_chinese_ci) AS max_val
    -> FROM tb1;
+---------+---------+
| min_val | max_val |
+---------+---------+
| Apple   | Sun     |
+---------+---------+
1 row in set (0.00 sec)

mysql> SELECT
    ->     MIN(col_b COLLATE gbk_bin) AS min_val_bin,
    ->     MAX(col_b COLLATE gbk_bin) AS max_val_bin
    -> FROM tb1;
+-------------+-------------+
| min_val_bin | max_val_bin |
+-------------+-------------+
| Apple       | Sun         |
+-------------+-------------+
1 row in set (0.00 sec)

mysql> INSERT INTO tb1 VALUES
    -> (11, 'apple', 'red', 'fruit'),
    -> (12, 'book', 'blue', 'object');
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM tb1 WHERE col_b = 'Apple';
+-------+-------+-------+-------+
| col_a | col_b | col_c | col_d |
+-------+-------+-------+-------+
|     1 | Apple | Red   | FRUIT |
|    11 | apple | red   | fruit |
+-------+-------+-------+-------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM tb1 WHERE col_d = 'FRUIT' COLLATE gbk_bin;
+-------+--------+--------+-------+
| col_a | col_b  | col_c  | col_d |
+-------+--------+--------+-------+
|     1 | Apple  | Red    | FRUIT |
|     2 | Banana | Yellow | FRUIT |
+-------+--------+--------+-------+
2 rows in set (0.00 sec)

mysql> EXPLAIN SELECT * FROM tb1 WHERE col_b = 'Apple';
+----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key   | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | tb1   | NULL       | ref  | col_b         | col_b | 21      | const |    2 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> EXPLAIN SELECT * FROM tb1 WHERE col_a = 5;
+----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key   | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | tb1   | NULL       | ref  | col_a         | col_a | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+-------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> SELECT col_a,
    ->        CONVERT(col_b USING utf8mb4) AS col_b_utf8,
    ->        col_d
    -> FROM tb1
    -> WHERE col_a < 5;
+-------+------------+--------+
| col_a | col_b_utf8 | col_d  |
+-------+------------+--------+
|     1 | Apple      | FRUIT  |
|     2 | Banana     | FRUIT  |
|     3 | Dog        | ANIMAL |
|     4 | Sky        | NATURE |
+-------+------------+--------+
4 rows in set (0.00 sec)

mysql> -- 测试索引边界
mysql> INSERT INTO tb1 VALUES
    -> (0, '0_test', 'color', 'TYPE'),
    -> (2147483647, 'z_test', 'color', 'TYPE');  -- INT最大值
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql>
mysql> -- 验证索引扫描
mysql> EXPLAIN SELECT * FROM tb1 WHERE col_a BETWEEN 1 AND 10;
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type  | possible_keys | key   | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | tb1   | NULL       | range | col_a         | col_a | 5       | NULL |    9 |   100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

mysql> -- 混合排序规则查询
mysql> SELECT col_a, col_b
    -> FROM tb1
    -> WHERE col_b = 'apple' COLLATE gbk_bin;  -- 强制区分大小写
+-------+-------+
| col_a | col_b |
+-------+-------+
|    11 | apple |
+-------+-------+
1 row in set (0.00 sec)

mysql>
mysql> -- 与默认排序规则对比
mysql> SELECT col_a, col_b
    -> FROM tb1
    -> WHERE col_b = 'apple';  -- 不区分大小写
+-------+-------+
| col_a | col_b |
+-------+-------+
|     1 | Apple |
|    11 | apple |
+-------+-------+
2 rows in set (0.00 sec)

mysql> -- 创建大容量测试数据(约10万行)
mysql> INSERT INTO tb1
    -> SELECT
    ->     n+10,
    ->     CONCAT('item', n),
    ->     'color',
    ->     CASE WHEN n%2=0 THEN 'TYPE_A' ELSE 'TYPE_B' END
    -> FROM (
    ->     SELECT a.N + b.N*10 + c.N*100 + d.N*1000 + e.N*10000 AS n
    ->     FROM (SELECT 0 AS N UNION SELECT 1 UNION...SELECT 9) a,
    ->          (SELECT 0 AS N UNION...SELECT 9) b,
    ->          (SELECT 0 AS N UNION...SELECT 9) c,
    ->          (SELECT 0 AS N UNION...SELECT 9) d,
    ->          (SELECT 0 AS N UNION...SELECT 9) e
    ->     LIMIT 100000
    -> ) t;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '...SELECT 9) a,
         (SELECT 0 AS N UNION...SELECT 9) b,
         (SELECT 0 ' at line 9
mysql>
mysql> -- 索引效率测试
mysql> ANALYZE TABLE tb1;
+--------------+---------+----------+----------+
| Table        | Op      | Msg_type | Msg_text |
+--------------+---------+----------+----------+
| cookbook.tb1 | analyze | status   | OK       |
+--------------+---------+----------+----------+
1 row in set (0.01 sec)

mysql> EXPLAIN SELECT * FROM tb1 WHERE col_b LIKE 'item1%';
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type  | possible_keys | key   | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | tb1   | NULL       | range | col_b         | col_b | 21      | NULL |    1 |   100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

生产环境建议
索引优化

ALTER TABLE tb1 MODIFY col_b CHAR(10) CHARACTER SET gbk COLLATE gbk_bin;
-- 重建索引以提高区分大小写查询性能
ALTER TABLE tb1 DROP INDEX col_b, ADD INDEX (col_b);
字符集统一

-- 建议全表使用utf8mb4(如果系统支持)
ALTER TABLE tb1 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs;
监控建议

-- 定期检查索引使用情况
SELECT index_name, rows_read
FROM information_schema.table_io_waits_summary_by_index_usage
WHERE object_schema = 'cookbook' AND object_name = 'tb1';

mysql> -- 查看表结构确认列名
mysql> DESCRIBE tb1;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| col_a | int      | YES  | MUL | NULL    |       |
| col_b | char(10) | YES  | MUL | NULL    |       |
| col_c | char(10) | YES  |     | NULL    |       |
| col_d | char(10) | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
4 rows in set (0.01 sec)

mysql>
mysql> -- 正确的最小/最大值查询(区分大小写)
mysql> SELECT
    ->     MIN(col_b COLLATE gbk_bin) AS min_value,
    ->     MAX(col_b COLLATE gbk_bin) AS max_value
    -> FROM tb1;
+-----------+-----------+
| min_value | max_value |
+-----------+-----------+
| 0_test    | z_test    |
+-----------+-----------+
1 row in set (0.00 sec)

mysql>
mysql> -- 不区分大小写的查询
mysql> SELECT
    ->     MIN(col_b) AS min_value_ci,  -- 默认使用gbk_chinese_ci
    ->     MAX(col_b) AS max_value_ci
    -> FROM tb1;
+--------------+--------------+
| min_value_ci | max_value_ci |
+--------------+--------------+
| 0_test       | z_test       |
+--------------+--------------+
1 row in set (0.00 sec)

8.7 将摘要划分为子群

sql 复制代码
mysql> select count(*) from mail;
+----------+
| count(*) |
+----------+
|       16 |
+----------+
1 row in set (0.00 sec)

mysql> select srcuser, count(*) from mail
    -> group by srcuser;
+---------+----------+
| srcuser | count(*) |
+---------+----------+
| barb    |        3 |
| tricia  |        2 |
| phil    |        5 |
| gene    |        6 |
+---------+----------+
4 rows in set (0.00 sec)

mysql> select srcuser,
    -> sum(size) as 'total bytes',
    -> avg(size) as ' bytes per message'
    -> from mail group by srcuser;
+---------+-------------+-------------------+
| srcuser | total bytes | bytes per message |
+---------+-------------+-------------------+
| barb    |      156696 |        52232.0000 |
| tricia  |     2589407 |      1294703.5000 |
| phil    |       18974 |         3794.8000 |
| gene    |     1033108 |       172184.6667 |
+---------+-------------+-------------------+
4 rows in set, 1 warning (0.00 sec)

mysql> select srcuser, srchost ,count(srcuser) from mail
    -> group by srcuser, srchost;
+---------+---------+----------------+
| srcuser | srchost | count(srcuser) |
+---------+---------+----------------+
| barb    | saturn  |              2 |
| tricia  | mars    |              1 |
| phil    | mars    |              3 |
| gene    | venus   |              2 |
| barb    | venus   |              1 |
| tricia  | saturn  |              1 |
| gene    | mars    |              2 |
| phil    | venus   |              2 |
| gene    | saturn  |              2 |
+---------+---------+----------------+
9 rows in set (0.00 sec)

mysql> select srcuser, max(size), max(t) from mail group by srcuser;
+---------+-----------+---------------------+
| srcuser | max(size) | max(t)              |
+---------+-----------+---------------------+
| barb    |     98151 | 2006-05-14 14:42:21 |
| tricia  |   2394482 | 2006-05-14 17:03:01 |
| phil    |     10294 | 2006-05-17 12:49:23 |
| gene    |    998532 | 2006-05-19 22:21:51 |
+---------+-----------+---------------------+
4 rows in set (0.00 sec)

mysql> select srcuser, dstuser, max(size) from mail group by srcuser,dstuser;
+---------+---------+-----------+
| srcuser | dstuser | max(size) |
+---------+---------+-----------+
| barb    | tricia  |     58274 |
| tricia  | gene    |    194925 |
| phil    | phil    |      1048 |
| gene    | barb    |      2291 |
| phil    | tricia  |      5781 |
| barb    | barb    |     98151 |
| tricia  | phil    |   2394482 |
| gene    | gene    |     23992 |
| gene    | tricia  |    998532 |
| phil    | barb    |     10294 |
+---------+---------+-----------+
10 rows in set (0.00 sec)

mysql> select name, max(miles) as 'longest trip'
    -> from driver_log group by name;
+-------+--------------+
| name  | longest trip |
+-------+--------------+
| Ben   |          152 |
| Suzi  |          502 |
| Henry |          300 |
+-------+--------------+
3 rows in set (0.00 sec)

mysql> SELECT name, trav_date, miles AS 'longest trip'
    -> FROM (
    ->     SELECT
    ->         name,
    ->         trav_date,
    ->         miles,
    ->         RANK() OVER (PARTITION BY name ORDER BY miles DESC) AS rnk
    ->     FROM driver_log
    -> ) t
    -> WHERE rnk = 1;
+-------+------------+--------------+
| name  | trav_date  | longest trip |
+-------+------------+--------------+
| Ben   | 2014-07-30 |          152 |
| Henry | 2014-07-29 |          300 |
| Suzi  | 2014-08-02 |          502 |
+-------+------------+--------------+
3 rows in set (0.00 sec)

mysql> SELECT d1.name, d1.trav_date, d1.miles AS 'longest trip'
    -> FROM driver_log d1
    -> JOIN (
    ->     SELECT name, MAX(miles) AS max_miles
    ->     FROM driver_log
    ->     GROUP BY name
    -> ) d2 ON d1.name = d2.name AND d1.miles = d2.max_miles;
+-------+------------+--------------+
| name  | trav_date  | longest trip |
+-------+------------+--------------+
| Ben   | 2014-07-30 |          152 |
| Henry | 2014-07-29 |          300 |
| Suzi  | 2014-08-02 |          502 |
+-------+------------+--------------+
3 rows in set (0.00 sec)

mysql> -- 临时禁用ONLY_FULL_GROUP_BY
mysql> SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
Query OK, 0 rows affected (0.01 sec)

mysql>
mysql> -- 执行原查询
mysql> SELECT name, trav_date, MAX(miles) AS 'longest trip'
    -> FROM driver_log
    -> GROUP BY name;
+-------+------------+--------------+
| name  | trav_date  | longest trip |
+-------+------------+--------------+
| Ben   | 2014-07-30 |          152 |
| Suzi  | 2014-07-29 |          502 |
| Henry | 2014-07-29 |          300 |
+-------+------------+--------------+
3 rows in set (0.00 sec)

mysql>
mysql> -- 恢复原设置
mysql> SET SESSION sql_mode=@@global.sql_mode;
Query OK, 0 rows affected (0.00 sec)
方案对比
方案	优点	缺点	适用场景
子查询	兼容性好,所有MySQL版本支持	SQL稍复杂	所有环境
窗口函数	语法简洁	需要MySQL 8.0+	新版MySQL
修改sql_mode	简单	违反SQL标准	临时分析

mysql> create table ttt
    -> select name, max(miles) as miles from driver_log group by name;
Query OK, 3 rows affected (0.05 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select d.name, d.trav_date, d.miles as 'longest trip'
    -> from driver_log as d inner join ttt using (name, miles) order by name;
+-------+------------+--------------+
| name  | trav_date  | longest trip |
+-------+------------+--------------+
| Ben   | 2014-07-30 |          152 |
| Henry | 2014-07-29 |          300 |
| Suzi  | 2014-08-02 |          502 |
+-------+------------+--------------+
3 rows in set (0.00 sec)

8.8 摘要与空值

sql 复制代码
mysql> select subject, test, score from expt order by subject, test;
+---------+------+-------+
| subject | test | score |
+---------+------+-------+
| Jane    | A    |    47 |
| Jane    | B    |    50 |
| Jane    | C    |  NULL |
| Jane    | D    |  NULL |
| Marvin  | A    |    52 |
| Marvin  | B    |    45 |
| Marvin  | C    |    53 |
| Marvin  | D    |  NULL |
+---------+------+-------+
8 rows in set (0.01 sec)

mysql> select subject,
    -> count(score) as n,
    -> sum(score) as total,
    -> avg(score) as average,
    -> min(score) as lowest,
    -> max(score) as highest
    -> from expt group by subject;
+---------+---+-------+---------+--------+---------+
| subject | n | total | average | lowest | highest |
+---------+---+-------+---------+--------+---------+
| Jane    | 2 |    97 | 48.5000 |     47 |      50 |
| Marvin  | 3 |   150 | 50.0000 |     45 |      53 |
+---------+---+-------+---------+--------+---------+
2 rows in set (0.00 sec)
相关推荐
TDengine (老段)4 分钟前
TDengine 数学函数 FLOOR 用户手册
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
Olrookie24 分钟前
若依前后端分离版学习笔记(二十)——实现滑块验证码(vue3)
java·前端·笔记·后端·学习·vue·ruoyi
请你喝好果汁64133 分钟前
Conda_bashrc 初始化机制学习笔记
笔记·学习·conda
大气层煮月亮42 分钟前
Oracle EBS ERP开发——报表生成Excel标准模板设计
数据库·oracle·excel
云和数据.ChenGuang1 小时前
达梦数据库的命名空间
数据库·oracle
maxruan1 小时前
PyTorch学习
人工智能·pytorch·python·学习
三三木木七1 小时前
mysql拒绝连接
数据库·mysql
蹦跶的小羊羔1 小时前
sql数据库语法
数据库·sql
唐古乌梁海2 小时前
【mysql】InnoDB的聚簇索引和非聚簇索引工作原理
数据库·mysql
我变秃了也没变强2 小时前
pgsql配置密码复杂度策略
数据库·postgresql