本文共 3222 字,大约阅读时间需要 10 分钟。
在数据库查询中,SELECT语句是最常用的数据检索命令,其内部包含了多个关键字,每个关键字都有特定的作用和执行顺序。本文将从定义顺序、执行顺序以及实际操作的角度,详细解析SELECT语句的工作原理。
SELECT语句的基本结构如下:
SELECT [DISTINCT] [列名列表] FROM [左表] [LEFT|RIGHT|FULL] JOIN [右表] ON [连接条件]WHERE [条件] GROUP BY [分组列] HAVING [过滤条件] ORDER BY [排序列] LIMIT [限制条数];
SELECT语句的核心是选择需要返回的列。在实际执行过程中,数据库首先会处理SELECT列表,确定需要获取哪些列。例如:
SELECT customer_id, COUNT(order_id) AS total_ordersFROM table1 AS aLEFT JOIN table2 AS b ON a.customer_id = b.customer_idWHERE a.city = 'hangzhou'GROUP BY a.customer_idHAVING COUNT(b.order_id) < 2ORDER BY total_orders DESC;
SELECT语句的执行过程可以分为以下几个关键步骤:
FROM语句执行(笛卡尔积)
根据FROM关键字,数据库首先会生成左表和右表的笛卡尔积,得到一个虚拟表VT1。例如:customer_id | city | order_id | customer_id |
---|---|---|---|
163 | hangzhou | 1 | 163 |
... | ... | ... | ... |
ON条件过滤
接着,数据库会根据ON条件(连接条件)过滤掉不符合条件的数据,生成虚拟表VT2。例如:customer_id | city | order_id | customer_id |
---|---|---|---|
163 | hangzhou | 1 | 163 |
163 | hangzhou | 2 | 163 |
... | ... | ... | ... |
外部行的添加(如有)
如果是LEFT JOIN、RIGHT JOIN或FULL JOIN,数据库会添加外部行。例如,左连接会保留左表未匹配的记录,并将右表匹配的记录连接到这些左表记录中。WHERE过滤
数据库会对已经生成的虚拟表(如VT3)进行WHERE条件过滤,保留符合条件的记录。例如:customer_id | city | order_id | customer_id |
---|---|---|---|
163 | hangzhou | 1 | 163 |
tx | hangzhou | 6 | tx |
GROUP BY分组
数据库会对WHERE结果生成的虚拟表(如VT4)进行分组,默认只保留组内第一条记录。例如:customer_id | city | order_id | customer_id |
---|---|---|---|
163 | hangzhou | 1 | 163 |
baidu | hangzhou | NULL | NULL |
tx | hangzhou | 6 | tx |
HAVING过滤
最后,数据库会根据HAVING条件过滤分组后的虚拟表(如VT5)。例如:customer_id | city | order_id | customer_id |
---|---|---|---|
baidu | hangzhou | NULL | NULL |
tx | hangzhou | 6 | tx |
SELECT列选择
在上述基础上,数据库才会执行SELECT列选择,生成临时表(如VT6)。例如:customer_id | total_orders |
---|---|
baidu | 0 |
tx | 1 |
DISTINCT去重(如有)
如果有DISTINCT关键字,数据库会去除重复的记录,生成去重后的临时表(如VT7)。ORDER BY排序
数据库会根据指定的排序列(如total_orders DESC),生成最终的排序结果(如VT8)。LIMIT限制
最后,数据库会根据LIMIT子句限制返回的行数,生成最终的查询结果。在实际操作中,需要准备表结构和数据。以下是常用的步骤:
创建测试数据库:
create database TestDB;
创建测试表:
CREATE TABLE table1 ( customer_id VARCHAR(10) NOT NULL, city VARCHAR(10) NOT NULL, PRIMARY KEY(customer_id)) ENGINE=INNODB DEFAULT CHARSET=UTF8;CREATE TABLE table2 ( order_id INT NOT NULL AUTO_INCREMENT, customer_id VARCHAR(10), PRIMARY KEY(order_id)) ENGINE=INNODB DEFAULT CHARSET=UTF8;
插入测试数据:
INSERT INTO table1(customer_id, city) VALUES('163','hangzhou');INSERT INTO table1(customer_id,city) VALUES('9you','shanghai');INSERT INTO table1(customer_id,city) VALUES('tx','hangzhou');INSERT INTO table1(customer_id,city) VALUES('baidu','hangzhou');INSERT INTO table2(customer_id) VALUES('163');INSERT INTO table2(customer_id) VALUES('163');INSERT INTO table2(customer_id) VALUES('9you');INSERT INTO table2(customer_id) VALUES('9you');INSERT INTO table2(customer_id) VALUES('9you');INSERT INTO table2(customer_id) VALUES('tx');INSERT INTO table2(customer_id) VALUES(NULL);
根据以上准备工作,以下是测试查询语句:
SELECT a.customer_id, COUNT(b.order_id) AS total_ordersFROM table1 AS aLEFT JOIN table2 AS b ON a.customer_id = b.customer_idWHERE a.city = 'hangzhou'GROUP BY a.customer_idHAVING COUNT(b.order_id) < 2ORDER BY total_orders DESC;
在实际执行过程中,数据库会通过生成多个虚拟表(VT1至VT8)来完成查询。以下是详细的执行过程:
FROM语句执行(笛卡尔积)
ON条件过滤
外部行的添加(如有)
WHERE过滤
GROUP BY分组
HAVING过滤
SELECT列选择
DISTINCT去重(如有)
ORDER BY排序
LIMIT限制
通过以上步骤,可以清晰地看到SELECT语句的执行顺序和过程。理解这一点对优化数据库查询和写出高效的SQL语句至关重要。
转载地址:http://iabfk.baihongyu.com/