子查询:在关系型数据库中,有时候检索信息是需要从多个表中去检索。子查询有时候就能够很灵活的去从各个关系表中取出我们所需的信息。
子查询使用注意:
子查询可以作为过滤条件,可以作为计算字段;
子查询的SELECT语句中只能检索单个列;
子查询比较灵活,且对嵌套的数目基本没有限制,但考虑到性能问题,同样的问题需求子查询不一定是最优的写法。
#测试数据表
SELECT A.costomid,A.cmname,A.country FROM costom A; -- 客户信息表
SELECT B.productid,B.pdname,B.price FROM product B; -- 产品价格表
SELECT C.ORDERID,C.CUSTOMID,C.PRODUCTID,C.SALE_NUM,C.ZTIME FROM new_order C; -- 订单表
#1、利用子查询过滤。查询订单明细中哪些是中国客户下的单
#解析:子查询的处理永远是自内向外的。利用子查询从客户表中查询中国客户的ID,返回作为C.CUSTOMID 的条件。
SELECT C.ORDERID,C.CUSTOMID,C.PRODUCTID,C.SALE_NUM,C.ZTIME FROM new_order C
WHERE 1=1
AND C.CUSTOMID in (SELECT A.costomid FROM costom A WHERE A.country='中国') ;
#2、利用子查询作为计算字段。查询客户表中每个客户的下单次数
SELECT A.costomid,A.cmname,A.country,
(SELECT COUNT(ORDERID) FROM new_order C WHERE C.CUSTOMID=A.costomid)AS ORDER_NUM
FROM costom A
子查询演示数据表:
/*
Navicat Premium Data Transfer
Source Server : mysql8.0
Source Server Type : MySQL
Source Server Version : 80028
Source Host : localhost:3306
Source Schema : 测试库2
Target Server Type : MySQL
Target Server Version : 80028
File Encoding : 65001
Date: 29/05/2022 14:24:27
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for costom
-- ----------------------------
DROP TABLE IF EXISTS `costom`;
CREATE TABLE `costom` (
`costomid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`cmname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`country` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of costom
-- ----------------------------
INSERT INTO `costom` VALUES ('C001', '客户A', '中国');
INSERT INTO `costom` VALUES ('C002', '客户B', '法国');
INSERT INTO `costom` VALUES ('C003', '客户C', '中国');
INSERT INTO `costom` VALUES ('C004', '客户D', '英国');
INSERT INTO `costom` VALUES ('C005', '客户E', '美国');
INSERT INTO `costom` VALUES ('C006', '客户F', '中国');
INSERT INTO `costom` VALUES ('C007', '客户G', '法国');
INSERT INTO `costom` VALUES ('C008', '客户H', '英国');
INSERT INTO `costom` VALUES ('C009', '客户I', '美国');
INSERT INTO `costom` VALUES ('C010', '客户H', '英国');
-- ----------------------------
-- Table structure for new_order
-- ----------------------------
DROP TABLE IF EXISTS `new_order`;
CREATE TABLE `new_order` (
`ORDERID` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`ZTIME` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`PRODUCTID` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`SALE_NUM` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`CUSTOMID` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of new_order
-- ----------------------------
INSERT INTO `new_order` VALUES ('O001', '2020-09-10', 'P010', '96', 'C008');
INSERT INTO `new_order` VALUES ('O002', '2020-08-29', 'P008', '38', 'C007');
INSERT INTO `new_order` VALUES ('O003', '2020-08-10', 'P007', '97', 'C008');
INSERT INTO `new_order` VALUES ('O004', '2020-09-27', 'P005', '62', 'C006');
INSERT INTO `new_order` VALUES ('O005', '2020-08-17', 'P007', '37', 'C009');
INSERT INTO `new_order` VALUES ('O006', '2020-09-06', 'P006', '3', 'C005');
INSERT INTO `new_order` VALUES ('O007', '2020-08-30', 'P009', '86', 'C007');
INSERT INTO `new_order` VALUES ('O008', '2020-09-04', 'P001', '34', 'C007');
INSERT INTO `new_order` VALUES ('O009', '2020-09-09', 'P003', '99', 'C004');
INSERT INTO `new_order` VALUES ('O010', '2020-09-06', 'P002', '65', 'C010');
INSERT INTO `new_order` VALUES ('O011', '2020-08-08', 'P005', '11', 'C002');
INSERT INTO `new_order` VALUES ('O012', '2020-09-20', 'P002', '3', 'C008');
INSERT INTO `new_order` VALUES ('O013', '2020-08-15', 'P004', '9', 'C004');
INSERT INTO `new_order` VALUES ('O014', '2020-08-28', 'P007', '99', 'C010');
INSERT INTO `new_order` VALUES ('O015', '2020-08-23', 'P003', '3', 'C005');
INSERT INTO `new_order` VALUES ('O016', '2020-08-08', 'P006', '51', 'C008');
INSERT INTO `new_order` VALUES ('O017', '2020-09-04', 'P009', '99', 'C002');
INSERT INTO `new_order` VALUES ('O018', '2020-08-12', 'P007', '86', 'C003');
INSERT INTO `new_order` VALUES ('O019', '2020-09-22', 'P001', '73', 'C005');
INSERT INTO `new_order` VALUES ('O020', '2020-08-03', 'P009', '22', 'C006');
INSERT INTO `new_order` VALUES ('O021', '2020-08-22', 'P007', '54', 'C006');
INSERT INTO `new_order` VALUES ('O022', '2020-09-29', 'P005', '59', 'C005');
INSERT INTO `new_order` VALUES ('O023', '2020-08-15', 'P003', '45', 'C006');
INSERT INTO `new_order` VALUES ('O024', '2020-09-12', 'P001', '10', 'C004');
INSERT INTO `new_order` VALUES ('O025', '2020-08-23', 'P004', '56', 'C008');
INSERT INTO `new_order` VALUES ('O026', '2020-09-17', 'P003', '57', 'C004');
INSERT INTO `new_order` VALUES ('O027', '2020-08-23', 'P002', '73', 'C003');
INSERT INTO `new_order` VALUES ('O028', '2020-09-22', 'P003', '50', 'C008');
INSERT INTO `new_order` VALUES ('O029', '2020-09-22', 'P003', '70', 'C007');
INSERT INTO `new_order` VALUES ('O030', '2020-08-13', 'P006', '15', 'C002');
-- ----------------------------
-- Table structure for product
-- ----------------------------
DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
`productid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`pdname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`price` decimal(10, 2) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of product
-- ----------------------------
INSERT INTO `product` VALUES ('P001', '产品A', 29.18);
INSERT INTO `product` VALUES ('P002', '产品B', 49.84);
INSERT INTO `product` VALUES ('P003', '产品C', 41.68);
INSERT INTO `product` VALUES ('P004', '产品D', 58.88);
INSERT INTO `product` VALUES ('P005', '产品E', 49.37);
INSERT INTO `product` VALUES ('P006', '产品F', 10.20);
INSERT INTO `product` VALUES ('P007', '产品G', 22.87);
INSERT INTO `product` VALUES ('P008', '产品H', 23.78);
INSERT INTO `product` VALUES ('P009', '产品I', 50.28);
INSERT INTO `product` VALUES ('P010', '产品J', 63.96);
SET FOREIGN_KEY_CHECKS = 1;
表联结:表联结分为内连结,外联结(左外连结,右外联结,全外联结)。
以下包括例子以及详细的解释。
#在使用联结时,一定要加上条件,标准格式后边条件使用ON筛选器,简单格式时WHERE子句限制条件,一般都是选用唯一主键作为关联条件,这样联结出来的是1对1的关系。
#不是1对1的也行,当联结表有多条对应主键的数据行时,那么数量少的表就会扩散。
#标准格式想要得到笛卡尔积的话,ON条件是1=1;简单格式得到笛卡尔积不写WHERE条件即可。
-- 1、标准格式与简单格式:ANSI SQL 规范一般选用标准格式。实际使用的话,看自己习惯使用哪一种。
-- 笛卡尔积
select t.STUNUM,t.`NAME`,t.AGE,c.CLASSNO,c.STUNUM,c.REMARK from student t
inner join class c on 1=1;
select t.STUNUM,t.`NAME`,t.AGE,c.CLASSNO,c.STUNUM,c.REMARK from student t,class c;
-- 2、内连接(标准写法,简单写法)
#内连接两个写法,带条件。返回两表都有的数据。
select t.STUNUM,t.`NAME`,t.AGE,c.CLASSNO,c.STUNUM,c.REMARK from student t
inner join class c on t.STUNUM=c.STUNUM;
select t.STUNUM,t.`NAME`,t.AGE,c.CLASSNO,c.STUNUM,c.REMARK from student t,class c WHERE t.STUNUM=c.STUNUM ;
-- 3、左外连接(LEFT JOIN),以左表为主返回右表中对应存在的数据,左表存在,右表没有时返回NULL。表交换位置例子。
select t.STUNUM,t.`NAME`,t.AGE,c.CLASSNO,c.STUNUM,c.REMARK from student t
left join class c on t.STUNUM=c.STUNUM;
select t.STUNUM,t.`NAME`,t.AGE,c.CLASSNO,c.STUNUM,c.REMARK from class c
left join student t on t.STUNUM=c.STUNUM ;
-- 4、右外连接(RIGHT JOIN),以右表为主返回右表中对应存在的数据,右表存在,左表没有时左表返回NULL。表交换位置例子
select c.STUNUM,c.REMARK,c.CLASSNO,t.STUNUM,t.`NAME`,t.AGE from class c
right join student t on t.STUNUM=c.STUNUM ;
select c.STUNUM,c.REMARK,c.CLASSNO,t.STUNUM,t.`NAME`,t.AGE from student t
right join class c on t.STUNUM=c.STUNUM ;
-- 全连接 mysql 中没有FULL JOIN 语法,使用LEFT JOIN UNION RIGHT JOIN 本质上的效果一样
select * from student t left join class c on t.STUNUM=c.STUNUM
union
select * from student t right join class c on t.STUNUM=c.STUNUM
表联结测试数据表:
/*
Navicat Premium Data Transfer
Source Server : mysql8.0
Source Server Type : MySQL
Source Server Version : 80028
Source Host : localhost:3306
Source Schema : 测试库1
Target Server Type : MySQL
Target Server Version : 80028
File Encoding : 65001
Date: 29/05/2022 14:26:43
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for class
-- ----------------------------
DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (
`CLASSNO` int(0) NULL DEFAULT NULL,
`STUNUM` int(0) NULL DEFAULT NULL,
`REMARK` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of class
-- ----------------------------
INSERT INTO `class` VALUES (3, 1105, '新生');
INSERT INTO `class` VALUES (1, 1102, '新生');
INSERT INTO `class` VALUES (2, 1103, '新生');
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`STUNUM` int(0) NULL DEFAULT NULL,
`NAME` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`AGE` int(0) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES (1101, '张三', 23);
INSERT INTO `student` VALUES (1102, '张二', 22);
INSERT INTO `student` VALUES (1103, '西奥', 21);
INSERT INTO `student` VALUES (1104, '西铁', 22);
INSERT INTO `student` VALUES (1105, '玛丽', 19);
SET FOREIGN_KEY_CHECKS = 1;
复合查询(组合查询):union,union all
当需要从多个表中返回相同结构的数据时,使用union比where方便得多。
使用注意:
union必须由两条或以上的select语句组成,语句之间用union关键字链接;
union中的每个查询部分需要包含相同的列、表达式或聚集函数(列的顺序无要求,主要是数量要相同);
列类型数据必须兼容,不必完全相同,但至少是dbms能够隐含转换的类型(例如一些数值类型或是日期类型)。
#UNION:返回两表数据,剔除重复行;UNION ALL返回两表全部数据,不论是否重复。
#course课程表,course_history历史课程表;两张表结构都相同,拥有相同的字段。在次基础下我们可以直接SELECT *
SELECT * FROM course A
UNION
SELECT * FROM course_history B
#一般书写的话,都建议写明查询列。且数据列结构要求相同。使用UNION可以看到下表返回两表数据,剔除掉重复的行。
SELECT A.cno,A.cname FROM course A
UNION
SELECT B.cno,B.cname FROM course_history B
#使用UNION ALL可以看到下表返回两表全部数据。
SELECT A.cno,A.cname FROM course A
UNION ALL
SELECT B.cno,B.cname FROM course_history B
###测试数据表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for course
-- ----------------------------
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
`cno` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '课程号',
`cname` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '课程名',
`credit` int(0) NULL DEFAULT NULL COMMENT '学分',
`semester` int(0) NULL DEFAULT NULL COMMENT '开课学期',
PRIMARY KEY (`cno`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of course
-- ----------------------------
INSERT INTO `course` VALUES ('C001', '高等数学', 4, 1);
INSERT INTO `course` VALUES ('C002', '大学英语', 3, 1);
INSERT INTO `course` VALUES ('C003', '大学英语', 3, 2);
INSERT INTO `course` VALUES ('C004', '计算机文化学', 2, 2);
INSERT INTO `course` VALUES ('C005', 'Java', 2, 3);
INSERT INTO `course` VALUES ('C006', '数据库基础', 4, 5);
INSERT INTO `course` VALUES ('C007', '数据结构', 4, 4);
INSERT INTO `course` VALUES ('C008', '计算机网络', 4, 4);
-- ----------------------------
-- Table structure for course_history
-- ----------------------------
DROP TABLE IF EXISTS `course_history`;
CREATE TABLE `course_history` (
`cno` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '课程号',
`cname` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '课程名',
`credit` int(0) NULL DEFAULT NULL COMMENT '学分',
`semester` int(0) NULL DEFAULT NULL COMMENT '开课学期',
PRIMARY KEY (`cno`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of course_history
-- ----------------------------
INSERT INTO `course_history` VALUES ('C001', '高等数学', 4, 1);
INSERT INTO `course_history` VALUES ('C002', '大学英语', 3, 1);
INSERT INTO `course_history` VALUES ('C003', '大学英语', 3, 2);
INSERT INTO `course_history` VALUES ('C004', '计算机文化学', 2, 2);
INSERT INTO `course_history` VALUES ('C005', 'Java', 2, 3);
INSERT INTO `course_history` VALUES ('C006', '数据库基础', 4, 5);
INSERT INTO `course_history` VALUES ('C007', '数据结构', 4, 4);
INSERT INTO `course_history` VALUES ('C008', '计算机网络', 4, 4);
INSERT INTO `course_history` VALUES ('C009', '移动通信', 3, 3);
INSERT INTO `course_history` VALUES ('C010', '中国文学近代史', 5, 4);
SET FOREIGN_KEY_CHECKS = 1;