神奇的 SQL 之子查询

子查询讲子查询之前,我们先来看看视图,何谓视图 ? 视图是基于 SQL 语句的结果集的可视化的表,包含行和列,就像一个真实的表,但只是一张虚拟表,我们可以将其视作为一张普通的表;视图只供数据查询,不能进行数据更改,也不能保存数据,查询数据来源于我们的实体表;说的简单点,视图就是复杂 SELECT 语句的一个代号,为查询提供便利 。视图总是显示最近的数据,每当我们查询视图时,数据库引擎通过使用 SQL 语句来重建数据 。
那何谓子查询,它与视图又有何关系 ? 视图是持久化的 SELECT 语句,而子查询就是将定义视图的 SELECT 语句直接用于 FROM 子句当中,它是个一次性的视图,在 SELECT 语句执行完之后就会消失 。光说概念,可能还是不太好理解,我们来看下视图与子查询的具体示例,通过示例我们就能更好的理解了
假设我们有如下表
CREATE TABLE t_customer_credit ( id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增主键', login_name VARCHAR(50) NOT NULL COMMENT '登录名', credit_type TINYINT(1) NOT NULL COMMENT '额度类型,1:自由资金,2:冻结资金,3:优惠', amount DECIMAL(22,6) NOT NULL DEFAULT '0.00000' COMMENT '额度值', create_by VARCHAR(50) NOT NULL COMMENT '创建者', create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', update_by VARCHAR(50) NOT NULL COMMENT '修改者', PRIMARY KEY (id));INSERT INTO `t_customer_credit` VALUES (1, 'zhangsan', 1, 550.000000, 'system', '2019-7-7 11:30:09', '2019-7-8 20:21:05', 'system');INSERT INTO `t_customer_credit` VALUES (2, 'zhangsan', 2, 0.000000, 'system', '2019-7-7 11:30:09', '2019-7-7 11:30:09', 'system');INSERT INTO `t_customer_credit` VALUES (3, 'zhangsan', 3, 0.000000, 'system', '2019-7-7 11:30:09', '2019-7-7 11:30:09', 'system');INSERT INTO `t_customer_credit` VALUES (4, 'lisi', 1, 0.000000, 'system', '2019-7-7 11:30:09', '2019-7-7 11:30:09', 'system');INSERT INTO `t_customer_credit` VALUES (5, 'lisi', 2, 0.000000, 'system', '2019-7-7 11:30:09', '2019-7-7 11:30:09', 'system');INSERT INTO `t_customer_credit` VALUES (6, 'lisi', 3, 0.000000, 'system', '2019-7-7 11:30:09', '2019-7-7 11:30:09', 'system');以及如下 3 个视图
-- 自由资金DROP VIEW IF EXISTS view_free;CREATE VIEW view_free(login_name, freeAmount) AS SELECT login_name, amountFROM t_customer_creditWHERE credit_type = 1;-- 冻结资金DROP VIEW IF EXISTS view_freeze;CREATE VIEW view_freeze(login_name, freezeAmount) AS SELECT login_name, amountFROM t_customer_creditWHERE credit_type = 2;-- 优惠DROP VIEW IF EXISTS view_promotion;CREATE VIEW view_promotion(login_name, promotionAmount) AS SELECT login_name, amountFROM t_customer_creditWHERE credit_type = 3;那么我们可以用如下 SQL 来显示用户的三个额度
SELECT v1.login_name, v1.free_amount, v2.freeze_amount, v3.promotion_amount FROMview_free v1 LEFT JOIN view_freeze v2 ON v1.login_name = v2.login_nameLEFT JOIN view_promotion v3 ON v1.login_name = v3.login_name;

神奇的 SQL 之子查询

文章插图
 
换成子查询的方式,SQL 如下
SELECT free.login_name, free.freeAmount, freeze.freezeAmount, promotion.promotionAmountFROM ( SELECT login_name, amount freeAmount FROM t_customer_credit WHERE credit_type = 1) free LEFT JOIN( SELECT login_name, amount freezeAmount FROM t_customer_credit WHERE credit_type = 2) freeze ON free.login_name = freeze.login_nameLEFT JOIN( SELECT login_name, amount promotionAmount FROM t_customer_credit WHERE credit_type = 3) promotion ON free.login_name = promotion.login_name;注意 SQL 的执行顺序,子查询作为内层查询会首先执行;原则上子查询必须设定名称,所以我们尽量从处理内容的角度出发为子查询设定一个恰当的名称
普通子查询
上面讲到的子查询就是普通子查询,非要给个定义的话,就是返回多行结果的子查询 。这个在实际应用中还是用的非常多的,这个相信大家都比较熟悉,不做过多的说明,只举个简单例子
假设我们有商品表:t_commodity
DROP TABLE IF EXISTS t_commodity;CREATE TABLE t_commodity ( id INT(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', serial_number VARCHAR(32) NOT NULL COMMENT '编号', name VARCHAR(50) NOT NULL COMMENT '名称', category VARCHAR(50) NOT NULL COMMENT '类别', sell_unit_price DECIMAL(22,6) NOT NULL COMMENT '出售单价', purchase_unit_price DECIMAL(22,6) NOT NULL COMMENT '进货单价', create_time DATETIME NOT NULL COMMENT '创建时间', update_time DATETIME NOT NULL COMMENT '更新时间', primary key(id)) COMMENT '商品表';-- 初始数据INSERT INTO t_commodity(serial_number, name, category, sell_unit_price, purchase_unit_price, create_time, update_time)VALUES('0001', 'T恤衫', '衣服', '80', '20', NOW(), NOW()),('0002', '羽绒服', '衣服', '280.5', '100', NOW(), NOW()),('0003', '休闲裤', '裤子', '50', '15.5', NOW(), NOW()),('0004', '运动短裤', '裤子', '30', '10', NOW(), NOW()),('0005', '菜刀', '厨具', '35', '10', NOW(), NOW()),('0006', '锅铲', '厨具', '15', '6.5', NOW(), NOW()),('0007', '锅', '厨具', '60', '20', NOW(), NOW()),('0008', '电饭煲', '厨具', '240', '70', NOW(), NOW()),('0009', '打孔器', '办公用品', '50', '10.5', NOW(), NOW()),('0010', '文件架', '办公用品', '35', '13', NOW(), NOW()),('0011', '办公桌', '办公用品', '280', '120', NOW(), NOW()),('0012', '办公椅', '办公用品', '256', '100', NOW(), NOW());


推荐阅读