首页 > 代码库 > MYSQL<五>

MYSQL<五>

-- ########## 01、LIMIT的使用和分页 ##########
INSERT INTO studentinfo VALUES(NULL, ‘刘备‘, ‘男‘, 35), (NULL, ‘关羽‘, ‘男‘, 30), (NULL, ‘张飞‘, ‘男‘, 25),
(NULL, ‘貂蝉‘, ‘女‘, 15), (NULL, ‘吕布‘, ‘男‘, 33), (NULL, ‘甄姬‘, ‘女‘, 22), (NULL, ‘董卓‘, ‘男‘, 55);

SELECT * FROM studentinfo;

-- LIMIT的使用:
-- 用法1、LIMIT 起始位置, 记录条数
-- LIMIT的起始位置0表示第一条记录
SELECT * FROM studentinfo LIMIT 0, 3;
SELECT * FROM studentinfo LIMIT 1, 3;
-- 错误代码: 1064 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 ‘-1, 3‘ at line 1
SELECT * FROM studentinfo LIMIT -1, 3;

-- 用法2、LIMIT 记录条数
-- 从第一条记录开始取若干条记录
SELECT * FROM studentinfo LIMIT 0;
SELECT * FROM studentinfo LIMIT 1;
SELECT * FROM studentinfo LIMIT 2;
SELECT * FROM studentinfo LIMIT 3;

-- LIMIT一般用于分页操作
-- 共有7条数据,设置每页3条记录,共分为3页
-- 列出每页的记录来归纳分页的方法:
-- 获取总记录条数
SELECT COUNT(*) AS 总记录条数 FROM studentinfo;
-- 第1页:第1条、第2条、第3条
SELECT * FROM studentinfo LIMIT 0, 3;
-- 第2页:第4条、第5条、第6条
SELECT * FROM studentinfo LIMIT 3, 3;
-- 第3页:第7条
SELECT * FROM studentinfo LIMIT 6, 1;    -- 此语句执行OK,但是不利于规律的归纳
SELECT * FROM studentinfo LIMIT 6, 3;

-- 从上面的语句进行分析归纳,得出分页的通用方法
-- 考虑制作方法还是从方法的返回值类型 和 参数列表 入手
-- 1、返回值类型就是当前页的数据集合
-- 2、参数列表:对于LIMIT子句来说,就两个参数:初始位置 和 记录条数
--         A:记录条数:人为设定每一页的记录的条数
--        B:初始位置:变化的值,但是只要知道了当前是第几页,就可以推算出初始位置是多少
--             计算公式:(当前页 - 1) * 记录条数
-- 3、隐含了一个数据需要获取:总页数
--         A:总记录条数 % 单页记录条数 == 0 时,总页数 = (总记录条数 / 单页记录条数)
--         B:总记录条数 % 单页记录条数 != 0 时,总页数 = (总记录条数 / 单页记录条数) + 1
-- 4、获取总记录条数:SELECT COUNT(*) AS 总记录条数 FROM 表名;

-- ########## 02、插入数据和查询数据的结合操作 ##########
-- 创建学生临时信息表
CREATE TABLE studenttemp
(
    id INT AUTO_INCREMENT PRIMARY KEY,
    `name` VARCHAR(10) NOT NULL,
    gender ENUM(‘男‘, ‘女‘) NOT NULL
);

SELECT * FROM studentinfo;
SELECT * FROM studenttemp;

-- 需求:把学生信息表中的部分内容查询出来插入到学生临时信息表中
-- 思路:结合使用查询 和 插入
-- INSERT结合查询的写法:INSERT INTO 新表(需要插入的列1, 需要插入的列2, ...) 查询其他表中的数据内容
INSERT INTO studenttemp(`name`, gender)
SELECT studentname, studentgender FROM studentinfo;

SELECT * FROM studenttemp;

-- 注意:新表和旧表的字段可以字段名不一致、顺序不一致,但是对应字段的数据类型必须要一致(数据范围小的内容放入到数据范围大的字段中是可以的)

-- ########## 03、子查询 ##########
-- 子查询:在一个查询中包含了另一个查询语句

-- 1、【独立子查询】:先执行子查询,再执行外层查询
-- 使用之前创建的courseinfo表 和 teacherinfo表
INSERT INTO courseinfo VALUES(NULL, ‘语文‘, 1), (NULL, ‘数学‘, 2), (NULL, ‘英语‘, 1);
INSERT INTO teacherinfo VALUES(NULL, ‘张老师‘, ‘男‘, 60), (NULL, ‘王老师‘, ‘女‘, 30), (NULL, ‘李老师‘, ‘男‘, 40);

SELECT * FROM courseinfo;
SELECT * FROM teacherinfo;

-- 需求:列出代课的老师的信息
-- 下句表示的是所有老师的信息,我们需要的是代课的老师的信息,所以要去课程信息表中看看哪些老师代课的,找出来
SELECT * FROM teacherinfo;
-- 错误代码: 1242 Subquery returns more than 1 row(因为子查询获取到的是一个集合)
SELECT * 
FROM teacherinfo
WHERE teacherid = (SELECT teacherid FROM courseinfo);

-- 正确写法:使用IN判断字段的内容和集合中的值是否匹配
SELECT *
FROM teacherinfo
WHERE teacherid IN (SELECT teacherid FROM courseinfo);

-- 如下写法也正确,但是没有必要这样做,特别对于大量的数据,使用DISTINCT这个去重复的操作非常耗时,除非迫不得已,否则不使用去重复
SELECT *
FROM teacherinfo
WHERE teacherid IN (SELECT DISTINCT teacherid FROM courseinfo);

-- 可以按照如下步骤进行理解:
-- step1、得到集合数据(代课的老师编号):SELECT teacherid FROM courseinfo这个子查询得到 {1, 2, 1}集合
-- step2、代课老师的编号是上一步操作中得到的集合中的某一个数据,拿着这个数据到老师信息表进行筛选
SELECT * FROM teacherinfo WHERE teacherid IN (1, 2, 1);

-- 需求:查找单个学生的所有课程成绩均及格的学生编号 和 学生姓名
-- 显然发生了语义错误:下面子查询做的事情:
-- 只要这门课程的成绩大于60分就把其学生编号筛选下留下来了,没有去管这个学生其他课程成绩
SELECT studentid AS 学生编号, studentname AS 学生姓名
FROM studentinfo
WHERE studentid IN (
    SELECT studentid
    FROM scoreinfo
    WHERE score >= 60
);

SELECT * FROM scoreinfo;

-- 正确写法:
-- 写法1、逆向思路:考虑到正向思路难度比较大,所谓所有课程成绩均及格的同学
-- 就是删除了那些只要有课程不及格就算不及格的同学后剩下的同学
-- 另外还必须是有成绩的同学才是我们要找的那部分同学(需要进行业务逻辑的确认)
SELECT studentid AS 学生编号, studentname AS 学生姓名
FROM studentinfo
WHERE studentid NOT IN
(
    SELECT studentid
    FROM scoreinfo
    WHERE score < 60
)
-- 有课程成绩的同学编号
AND studentid IN (SELECT studentid FROM scoreinfo);

-- 写法2、正向思路:考虑在成绩信息表中依据学生编号进行分组,获取组的最小成绩大于等于60的同学
SELECT studentid AS 学生编号, studentname AS 学生姓名
FROM studentinfo
WHERE studentid IN (
    SELECT studentid
    FROM scoreinfo
    GROUP BY studentid
    HAVING MIN(score) >= 60
);

SELECT * FROM scoreinfo;

-- 使用比较运算符的子查询
-- 需求:列出不小于选修了课程编号2的学生编号的学生信息
-- 错误代码: 1242 Subquery returns more than 1 row
SELECT *
FROM studentinfo
WHERE studentid >= (SELECT studentid FROM scoreinfo WHERE courseid = 2);

-- 正确写法:虽然没有大于等于某个范围的关键字或是符号,但是可以大于等于这个范围中最大的那个数据值
SELECT *
FROM studentinfo
WHERE studentid >= (SELECT MAX(studentid) FROM scoreinfo WHERE courseid = 2);

-- 使用EXISTS关键字的子查询:如果子查询查询到了结果,外层的查询才执行;否则的话,外层的查询不执行

-- 需求:有课程成绩大于等于90分的同学就列出全部的学生信息
SELECT *
FROM studentinfo
WHERE EXISTS (SELECT * FROM scoreinfo WHERE score >= 90);

-- 需求:有课程成绩大于90分的同学就列出全部的学生信息
SELECT *
FROM studentinfo
WHERE EXISTS (SELECT * FROM scoreinfo WHERE score > 90);

-- 使用ANY 或 SOME 的子查询
-- 需求:列出编号大于任一个选修了课程编号2的学生编号的学生信息
SELECT *
FROM studentinfo
WHERE studentid >= ANY(SELECT studentid FROM scoreinfo WHERE courseid = 2);
-- 上句等价于下句:列出编号大于选修了课程编号2的学生编号最小那个编号的学生信息
SELECT *
FROM studentinfo
WHERE studentid >= (SELECT MIN(studentid) FROM scoreinfo WHERE courseid = 2);

-- 关键字SOME 和 关键字ANY 是同义词
SELECT *
FROM studentinfo
WHERE studentid >= SOME(SELECT studentid FROM scoreinfo WHERE courseid = 2);

-- 使用ALL的子查询
-- 需求:列出学生编号不小于所有选修了课程编号2的学生编号的学生信息
SELECT *
FROM studentinfo
WHERE studentid >= ALL(SELECT studentid FROM scoreinfo WHERE courseid = 2);
-- 上句可以理解为:大于等于查询出课程编号2的学生学号这个范围中最大的那个数据值
SELECT *
FROM studentinfo
WHERE studentid >= (SELECT MAX(studentid) FROM scoreinfo WHERE courseid = 2);

-- 结合常见的场景:客户信息  和  订单信息来看看子查询的使用
-- 客户信息表
CREATE TABLE customers
(
    customerid INT AUTO_INCREMENT PRIMARY KEY,
    customername VARCHAR(10) NOT NULL
);
INSERT INTO customers VALUES(NULL, ‘张三‘), (NULL, ‘李四‘), (NULL, ‘王五‘), (NULL, ‘赵六‘);

-- 订单信息表
CREATE TABLE orders
(
    orderid INT AUTO_INCREMENT PRIMARY KEY,
    customerid INT NOT NULL,
    -- 金额
    amount DECIMAL(10, 2) NOT NULL,
    -- 订单类型:现金、信用卡
    ordertype VARCHAR(10) NOT NULL
);
INSERT INTO orders VALUES(NULL, 1, 22.25, ‘现金‘), (NULL, 2, 11.75, ‘信用卡‘), (NULL, 2, 5.00, ‘信用卡‘), (NULL, 2, 8.00, ‘现金‘),
(NULL, 3, 9.33, ‘信用卡‘), (NULL, 3, 10.11, ‘信用卡‘);

SELECT * FROM customers;
SELECT * FROM orders;

-- 1、独立子查询作为数据源(包含数据的集合)的使用
-- 需求:以客户为单位,统计每个客户的现金消费总数
-- 1)筛选在分组后做
-- 错误代码: 1054 Unknown column ‘ordertype‘ in ‘having clause‘
-- 分析:因为按照customerid进行分组形成的每个组中会有不同的ordertype
SELECT customerid AS 客户编号, SUM(amount) AS 现金消费总数
FROM orders
GROUP BY customerid
HAVING ordertype = ‘现金‘;
-- 2)筛选在分组前做,考虑使用子查询
-- 错误代码: 1248 Every derived table must have its own alias
SELECT *
FROM (
    SELECT customerid AS 客户编号, SUM(amount) AS 现金消费总数
    FROM orders
    WHERE ordertype = ‘现金‘
    GROUP BY customerid
);
-- 正确写法:
SELECT *
FROM (
    SELECT customerid AS 客户编号, SUM(amount) AS 现金消费总数
    FROM orders
    WHERE ordertype = ‘现金‘
    GROUP BY customerid
) AS temp;

-- 不使用星号通配符,使用具体字段
-- 错误代码: 1054 Unknown column ‘customerid‘ in ‘field list‘
SELECT customerid AS 客户编号, SUM(amount) AS 现金消费总数
FROM (
    SELECT customerid AS 客户编号, SUM(amount) AS 现金消费总数
    FROM orders
    WHERE ordertype = ‘现金‘
    GROUP BY customerid
) AS temp;
-- 正确写法:
-- 写法1
SELECT 客户编号, 现金消费总数
FROM (
    SELECT customerid AS 客户编号, SUM(amount) AS 现金消费总数
    FROM orders
    WHERE ordertype = ‘现金‘
    GROUP BY customerid
) AS temp;
-- 写法2
SELECT temp.客户编号, temp.现金消费总数
FROM (
    SELECT customerid AS 客户编号, SUM(amount) AS 现金消费总数
    FROM orders
    WHERE ordertype = ‘现金‘
    GROUP BY customerid
) AS temp;

-- 2、关联子查询
-- 1)在查询条件中使用关联子查询

-- 需求:查询出消费总计小于20元的客户信息
SELECT * FROM orders;
-- 写法1、使用独立子查询
SELECT *
FROM customers
WHERE customerid IN
(
    SELECT customerid
    FROM orders
    GROUP BY customerid
    HAVING SUM(amount) < 20
);
-- 写法2、使用关联子查询
-- 【使用关联子查询时,子查询不再像独立子查询那样可以独立执行,也不再像独立子查询那样先执行】
SELECT *
FROM customers AS c
WHERE (
    SELECT customerid
    FROM orders AS o
    WHERE o.customerid = c.customerid
    GROUP BY o.customerid
    HAVING SUM(o.amount) < 20
);
-- 可以理解为:分步操作,在查询条件中的关联子查询相当于遍历外层表中关联字段的每一行记录
-- 在这里,查询条件中的关联子查询使用的关联字段customerid相当于遍历外层的customers表中的customerid这个关联字段的每一行记录
-- 因为关联子查询中涉及到使用外层表中的关联字段,所以关联子查询就无法独立执行
-- 第1行记录
SELECT customerid
FROM orders AS o
WHERE o.customerid = 1
GROUP BY o.`customerid`
HAVING SUM(o.`amount`) < 20;
-- 第2行记录
SELECT customerid
FROM orders AS o
WHERE o.customerid = 2
GROUP BY o.`customerid`
HAVING SUM(o.`amount`) < 20;
-- 第3行记录(查询到了满足条件的记录,所以留下来)
SELECT customerid
FROM orders AS o
WHERE o.customerid = 3
GROUP BY o.`customerid`
HAVING SUM(o.`amount`) < 20;
-- 第4行记录
SELECT customerid
FROM orders AS o
WHERE o.customerid = 4
GROUP BY o.`customerid`
HAVING SUM(o.`amount`) < 20;

-- 2)关联子查询作为一个计算的列

-- 需求:列出客户姓名以及客户的个人消费数量
-- 分析:单个的获取客户姓名 或是 单个的获取客户的个人消费数量都好办,但是要在一个查询结果中出现这两者有些麻烦,借助于关联子查询
SELECT * FROM orders;

SELECT * FROM customers;

SELECT customerid AS 客户编号, COUNT(*) AS 客户的个人消费数量
FROM orders
GROUP BY customerid;

SELECT
    customername AS 客户姓名,
    (
        SELECT COUNT(o.orderid) AS 消费数量
        FROM orders AS o
        WHERE o.customerid = c.customerid
    ) AS 个人消费数量
FROM customers AS c;
-- 可以理解为:分步操作,在列中的关联子查询相当于遍历外层表中关联字段的每一行记录
-- 在这里,查询条件中的关联子查询使用的关联字段customerid相当于遍历外层的customers表中的customerid这个关联字段的每一行记录
-- 因为关联子查询中涉及到使用外层表中的关联字段,所以关联子查询就无法独立执行
-- 第1行记录
SELECT COUNT(o.orderid) AS 消费数量
FROM orders AS o
WHERE o.customerid = 1
-- 第2行记录
SELECT COUNT(o.orderid) AS 消费数量
FROM orders AS o
WHERE o.customerid = 2
-- 第3行记录
SELECT COUNT(o.orderid) AS 消费数量
FROM orders AS o
WHERE o.customerid = 3
-- 第4行记录
SELECT COUNT(o.orderid) AS 消费数量
FROM orders AS o
WHERE o.customerid = 4

-- 子查询的总结:
-- 1、独立子查询:可以独立执行,且先执行
-- 2、关联子查询:不可以独立执行,且伴随着外层查询的操作,每一次都被调用

-- ########## 04、表的连接 ##########

-- 常用的场景:部门 和 员工 是 一对多的关系,部门是一,员工是多
-- 为了体现这种一对多的关系,在员工信息表中放置部门编号这个字段

-- 部门表
CREATE TABLE dept
(
    deptid INT AUTO_INCREMENT PRIMARY KEY,
    deptname VARCHAR(20) UNIQUE NOT NULL
);

-- 员工表
CREATE TABLE employee
(
    employeeid INT AUTO_INCREMENT PRIMARY KEY,
    employeename VARCHAR(10) NOT NULL,
    deptid INT NULL
);

-- 模拟数据
INSERT INTO dept VALUES(NULL, ‘开发部‘), (NULL, ‘销售部‘), (NULL, ‘总经办‘), (NULL, ‘人事部‘);
INSERT INTO employee VALUES(NULL, ‘刘备‘, 1), (NULL, ‘张飞‘, 1), (NULL, ‘关羽‘, 1),
(NULL, ‘曹操‘, 2), (NULL, ‘荀彧‘, 2), (NULL, ‘郭嘉‘, 2),
(NULL, ‘孙权‘, 3), (NULL, ‘周瑜‘, 3), (NULL, ‘陆逊‘, 3),
(NULL, ‘孟获‘, NULL), (NULL, ‘于吉‘, 5);

SELECT * FROM dept;
SELECT * FROM employee;

-- 1、交叉连接(CROSS JOIN):获取笛卡尔积(笛卡儿积)
-- 交叉连接:不加任何限制条件,把两个实体(分别有m条记录 和 n条记录)进行连接,形成m*n条记录的新的集合
-- 写法1
SELECT * FROM dept, employee;
-- 写法2、显式使用CROSS JOIN关键字(推荐写法)
SELECT * FROM dept CROSS JOIN employee;

-- 2、内连接(INNER JOIN):在交叉连接上进行条件限制(筛选)

-- 需求:查询出员工信息及其对应的所属部门的名称
-- 分析:上述取得的笛卡尔积没有任何条件的限制,很多数据是没用意义的
--          我们需要根据员工信息表中的部门唯一标识-----部门编号,到部门信息表中获取部门的相应信息出来
--         也就是员工信息表中的部门编号应该和部门信息表中的部门编号对应起来

-- 考虑使用INNER JOIN关键字 和 WHERE子句
SELECT *
FROM dept 
INNER JOIN employee
WHERE dept.`deptid` = employee.`deptid`;
-- 改进
SELECT employee.`employeeid` AS 员工编号, employee.`employeename` AS 员工姓名, dept.`deptname` AS 部门名称
FROM dept 
INNER JOIN employee
WHERE dept.`deptid` = employee.`deptid`;
-- 可以理解为:首先取得交叉连接的笛卡尔积,再针对笛卡尔积使用条件限制,就得到了内连接的结果
SELECT employee.`employeeid` AS 员工编号, employee.`employeename` AS 员工姓名, dept.`deptname` AS 部门名称
FROM dept 
CROSS JOIN employee
WHERE dept.`deptid` = employee.`deptid`;
-- 上述写法等价于
SELECT employee.`employeeid` AS 员工编号, employee.`employeename` AS 员工姓名, dept.`deptname` AS 部门名称
FROM dept, employee
WHERE dept.`deptid` = employee.`deptid`;
-- 对于连接的对应关系的描述,SQL中提供了 ON 关键字
SELECT employee.`employeeid` AS 员工编号, employee.`employeename` AS 员工姓名, dept.`deptname` AS 部门名称
FROM dept 
INNER JOIN employee
ON dept.`deptid` = employee.`deptid`;

-- 3、外连接(OUTER JOIN)
-- 理解:这里的外,是针对作为重点的那个集合而言的

-- 1)左外连接/左连接(LEFT OUTER JOIN/LEFT JOIN):
-- 以左边的表为主,右边的表中能匹配的上的数据列出来,匹配不上的显示为NULL值
-- 2)右外连接/右连接(RIGHT OUTER JOIN/RIGHT JOIN):
-- 以右边的表为主,左边的表中能匹配的上的数据列出来,匹配不上的显示为NULL值

-- 需求:列出公司全部的部门以及部门的员工信息(多行显示)
-- 分析:重点在全部的部门,另外要列出的是全部部门中每个部门对应的员工的信息
--          隐含的意思,哪怕这个部门没有员工,也要列出这个部门来,没有员工时,员工信息就显示为NULL值
--          但是,员工没有部门的,不考虑
SELECT *
FROM dept
LEFT OUTER JOIN employee
ON dept.`deptid` = employee.`deptid`;
-- 写法1、使用LEFT OUTER JOIN
SELECT dept.`deptname` AS 部门名称, employee.`employeeid` AS 员工编号, employee.`employeename` AS 员工姓名
FROM dept
LEFT OUTER JOIN employee
ON dept.`deptid` = employee.`deptid`;
-- 写法2、使用LEFT JOIN
SELECT dept.`deptname` AS 部门名称, employee.`employeeid` AS 员工编号, employee.`employeename` AS 员工姓名
FROM dept
LEFT JOIN employee
ON dept.`deptid` = employee.`deptid`;

-- 需求:列出公司全部的员工以及员工的部门信息
-- 分析:重点在全部的员工上,另外要列出的是全部员工中每个员工对应的部门的信息
--          隐含的意思,哪怕这个员工没有部门,也要列出这个员工来,没有部门时,部门信息就显示为NULL值
-- 写法1、使用左连接写法
SELECT employee.`employeeid` AS 员工编号, employee.`employeename` AS 员工姓名, dept.`deptname` AS 部门名称
FROM employee
LEFT JOIN dept
ON employee.`deptid` = dept.`deptid`;
-- 写法2、使用右连接写法
SELECT employee.`employeeid` AS 员工编号, employee.`employeename` AS 员工姓名, dept.`deptname` AS 部门名称
FROM dept
RIGHT OUTER JOIN employee
ON employee.`deptid` = dept.`deptid`;
-- 简化
SELECT employee.`employeeid` AS 员工编号, employee.`employeename` AS 员工姓名, dept.`deptname` AS 部门名称
FROM dept
RIGHT JOIN employee
ON employee.`deptid` = dept.`deptid`;

-- 4、自连接(内连接的变体)

-- 需求:设计公司的组织架构信息表(这种设计很重要:务必掌握)
-- 蔡氏国际
--            蔡氏中国
--                    蔡氏安徽
--                    蔡氏北京
--                    蔡氏上海
--            蔡氏美国
--                    蔡氏纽约
--                    蔡氏德州
--            蔡氏日本
--                    蔡氏关东
--                    蔡氏关西

-- 考虑树形结构来进行描述,描述树结构上的节点的位置,需要描述其当前的节点和它的父节点,这样才能确定它的位置

-- 公司组织结构信息表
CREATE TABLE companyinfo
(
    -- 组织编号
    companyid INT AUTO_INCREMENT PRIMARY KEY,
    -- 组织名称
    companyname VARCHAR(10) NOT NULL,
    -- 组织父编号
    companypid INT NOT NULL
);
-- 模拟数据
INSERT INTO companyinfo VALUES(NULL, ‘蔡氏国际‘, 0),
(NULL, ‘蔡氏中国‘, 1), (NULL, ‘蔡氏美国‘, 1), (NULL, ‘蔡氏日本‘, 1),
(NULL, ‘蔡氏安徽‘, 2), (NULL, ‘蔡氏北京‘, 2), (NULL, ‘蔡氏上海‘, 2),
(NULL, ‘蔡氏纽约‘, 3), (NULL, ‘蔡氏德州‘, 3), 
(NULL, ‘蔡氏关东‘, 4), (NULL, ‘蔡氏关西‘, 4);

SELECT * FROM companyinfo;

-- 需求:根据给定的组织名称查看其组织编号及其下一级
-- 思路:首先按给定的组织名称获取其组织编号,再拿着这个组织编号做companypid父编号在表中查询,得到其下一级

-- 分步操作如下:
-- step1、首先按给定的组织名称获取其组织编号
SELECT companyid AS 组织编号, companyname AS 组织名称
FROM companyinfo
WHERE companyname = ‘蔡氏中国‘;
-- step2、拿着这个组织编号做companypid父编号在表中查询,得到其下一级
SELECT companyid AS 下一级组织编号, companyname AS 下一级组织名称
FROM companyinfo
WHERE companypid = 2;

-- 不使用分步操作,使用自连接,将组织信息表集合1的编号 和 组织信息表集合2的父编号 进行匹配
-- 也就是把左表的编号作为右表的父编号进行匹配
SELECT *
FROM companyinfo AS c1
INNER JOIN companyinfo AS c2
ON c1.`companyid` = c2.`companypid`;

-- 考虑到需求要根据给定的组织名称查看其组织编号及其下一级
-- 错误代码: 1052 Column ‘companyname‘ in where clause is ambiguous  companyname列在WHERE子句中有歧义(因为有多个companyname字段)
SELECT *
FROM companyinfo AS c1
INNER JOIN companyinfo AS c2
ON c1.`companyid` = c2.`companypid`
WHERE companyname = ‘蔡氏中国‘;

-- 正确写法1、筛选条件中使用 ON  和  WHERE
SELECT c1.`companyid` AS 组织编号, c1.`companyname` AS 组织名称, c2.`companyname` AS 下一级组织名称
FROM companyinfo AS c1
INNER JOIN companyinfo AS c2
ON c1.`companyid` = c2.`companypid`
WHERE c1.companyname = ‘蔡氏中国‘;

-- 正确写法2、筛选条件中使用 ON
SELECT c1.`companyid` AS 组织编号, c1.`companyname` AS 组织名称, c2.`companyname` AS 下一级组织名称
FROM companyinfo AS c1
INNER JOIN companyinfo AS c2
ON c1.`companyid` = c2.`companypid` AND c1.companyname = ‘蔡氏中国‘;

-- 正确写法2、筛选条件中使用 WHERE
SELECT c1.`companyid` AS 组织编号, c1.`companyname` AS 组织名称, c2.`companyname` AS 下一级组织名称
FROM companyinfo AS c1
INNER JOIN companyinfo AS c2
WHERE c1.`companyid` = c2.`companypid` AND c1.companyname = ‘蔡氏中国‘;

-- 需求:查看一级组织(一级子公司)及其下一级组织(多行显示)
SELECT c1.`companyid` AS 组织编号, c1.`companyname` AS 一级组织名称, c2.`companyname` AS 下一级组织名称
FROM companyinfo AS c1
INNER JOIN companyinfo AS c2
WHERE c1.`companyid` = c2.`companypid` AND c1.`companypid` = 1;

-- 需求:查看一级组织(一级子公司)及其下一级组织(单行显示)
SELECT temp.组织编号, temp.一级组织名称, GROUP_CONCAT(temp.下一级组织名称) AS 下一级组织名称
FROM
(
    SELECT c1.`companyid` AS 组织编号, c1.`companyname` AS 一级组织名称, c2.`companyname` AS 下一级组织名称
    FROM companyinfo AS c1
    INNER JOIN companyinfo AS c2
    WHERE c1.`companyid` = c2.`companypid` AND c1.`companypid` = 1
) AS temp
GROUP BY temp.组织编号, temp.一级组织名称;

 

MYSQL<五>