SQL SELECT(复杂查询)之 自连接 & 子查询 解析

SQL SELECT(复杂查询)之 自连接 & 子查询 解析
一、自连接

概念:把一张表 当做多个表使用

语法:

select ...
from 表 a(别名)
join 表 b(别名)

on a.字段=b.字段

注意:

自连接也可以是 内连接也可以是外连接
自己与一张与自己完全一样的从表建立关系 进行连接查询

以下举例所用表

employees表:字段如下

employee_id, first_name, last_name, email, phone_number

job_id, salary, commission_pct, manage_id, department_id

案例: xx员工 为 xx上司 工作

分析:

employees表:字段如下

employee_id, first_name, last_name, email, phone_number

job_id, salary, commission_pct, manage_id, department_id

manage_id 是员工id为emplo_id的领导者id 其对应的一条记录也是

employees表中的一条普通员工记录

/*
进一步分析:

1.相当于查询员工名和上司名
2.将自己(employees表)当做两个表, m和e

*/
#分析1
//相当于从employee表中查找 经过匹配后 得到这个员工的领导  
   manager_id 再把它从这个表中查出来

SELECT e.`first_name` 员工名,m.`first_name` 老板名
FROM employees e
JOIN employees m  ON e.`manager_id`=m.`employee_id`

#分析2 通过自己与自己内连接 跟自连接 一样
SELECT CONCAT(e.`first_name`,' work for ',m.`first_name`)  info
FROM employees e
JOIN employees m  ON e.`manager_id`=m.`employee_id`

二、子查询

(一)子查询

分类:

单行子查询: 子查询的结果集是一行

多行子查询: 子查询的结果集是多行

注意事项:
    子查询要包含在括号内。

    将子查询放在比较条件的右侧。

    单行操作符对应单行子查询,多行操作符对应多行子查询。
单行操作符:
    > < >= <= = <>
多行操作符:
    in(重点)、any(任意一个)、all(所有的)
    not in

1、单行子查询

 比较的对象是唯一的一个而不是一个范围集合

1.案例:谁的工资比 Abel 高?

/*
    分析1: 求出Abel的工资
    分析2: 筛选employees表,判断 salary > Abel的工资
*/

求出Abel的工资,得到一个值
SELECT salary FROM employees WHERE last_name = 'Abel';

筛选employees表,判断 salary > Abel的工资
SELECT * FROM employees WHERE salary>11000;


结合以上两部分析将第一个分析所得结果作为被比较的条件对象

SELECT * 
FROM employees 
WHERE salary>(
    SELECT salary 
    FROM employees 
    WHERE last_name = 'Abel'
);

2.案例:返回job_id与141号员工相同,salary比143号员工多的员工

    姓名,job_id 和工资

     /*
     分析1:先查询 141 号员工的job_id
           以及 143号员工的salary
     */

1》先查询 141 号员工的job_id
   以及 143号员工的salary


SELECT job_id 
FROM employees 
WHERE employee_id = 141

SELECT salary 
FROM employees 
WHERE employee_id = 143

2》结合以上两部将其作为被比较的条件对象筛选指定的员工

SELECT last_name 姓名,job_id ,salary 工资
FROM employees
WHERE job_id =(
    SELECT job_id 
    FROM employees 
    WHERE employee_id = 141

) AND salary>(
    SELECT salary 
    FROM employees 
    WHERE employee_id = 143
)

3 子查询中使用了组函数。

以下举例所用表

employees表:字段如下

employee_id, first_name, last_name, email, phone_number

job_id, salary, commission_pct, manage_id, department_id

案例 返回工资最少的员工的last_name,job_id和salary

SELECT last_name,job_id,salary 
FROM employees
WHERE salary=(

    //把如下语句获取的值作为salary比较的条件对象
    SELECT MIN(salary) FROM employees
);

SELECT * FROM employees;//查看结果有没有改变

4 子查询中用到了having

案例:查询最低工资大于50号部门最低工资的部门id和其最低工资

/*
    分析1:先查询50号部门的最低工资
    分析2:每个部门的部门id和其最低工资
    分析3:筛选看哪个部门的最低工资大于分析1的结果

*/
#分析1
SELECT MIN(salary) 
FROM employees
WHERE department_id=50

#分析2
SELECT MIN(salary) ,department_id
FROM employees
GROUP BY department_id

#分析3

SELECT MIN(salary) ,department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
    SELECT MIN(salary) 
    FROM employees
    WHERE department_id=50

);

非法使用单行子查询,其实就是 子查询结果集中返回的是多行
SELECT MIN(salary) ,department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
SELECT salary
FROM employees
WHERE department_id>50//返回的是多个值对象

);

单行子查询的结果集中出现 null的问题

SELECT MIN(salary) ,department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
    SELECT salary 
    FROM employees
    WHERE department_id>300 //结果为null

);

单行子查询的结果集多列的问题

SELECT MIN(salary) ,department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(  //到这一步 用于比较的MIN(salary)有很多个 不
    SELECT MIN(salary),department_id 
    FROM employees
    WHERE department_id=50  //50号部门最低工资

);

二、多行子查询
1.题目:

返回其它部门中比job_id为‘IT_PROG’部门任一工资低的员工的员

工号、姓名、job_id 以及salary

提示:比最高工资低 就行

     /*
     分析1: 先查询 job_id为‘IT_PROG’部门任一工资
     分析2: 查询员工号、姓名、job_id 以及salary  比分析1的 结果中任意一个都低的

     */

     1》. 先查询 job_id为‘IT_PROG’部门任一工资

     SELECT salary 
     FROM employees
     WHERE job_id = 'IT_PROG'


     2 》查询员工号、姓名、job_id 以及salary  比分析1的 结果中任意一个都低的

     SELECT employee_id,last_name,job_id,salary
     FROM employees
     WHERE salary<ANY(
            SELECT salary 
         FROM employees
         WHERE job_id = 'IT_PROG'

     )

2.题目:返回其它部门中比job_id为‘IT_PROG’部门所有工资都低的员工

的员工号、姓名、job_id 以及salary

提示:相当于比 最小的工资还要低

     SELECT employee_id,last_name,job_id,salary
     FROM employees
     WHERE salary<ALL(
            SELECT salary 
         FROM employees
         WHERE job_id = 'IT_PROG'

     )

3.题目:返回其它部门中工资和 job_id为‘IT_PROG’部门的随便一个工资 相同 的员工

SELECT employee_id,last_name,job_id,salary
     FROM employees
     WHERE salary NOT IN(
            SELECT salary 
         FROM employees
         WHERE job_id = 'IT_PROG'
     )

语法:

in(值1,值2,值3)
salary =值1 or salary=值2 or salary=值3
  • 3
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用jsqlparser解析子查询sql的示例代码: ```java import java.io.StringReader; import java.util.List; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.SubSelect; public class JSqlParserDemo { public static void main(String[] args) throws JSQLParserException { String sql = "SELECT * FROM (SELECT * FROM table1 WHERE id IN (SELECT id FROM table2)) AS subquery"; Statement statement = CCJSqlParserUtil.parse(sql); Select selectStatement = (Select) statement; PlainSelect plainSelect = (PlainSelect) selectStatement.getSelectBody(); SubSelect subSelect = (SubSelect) plainSelect.getFromItem(); Select subquery = (Select) subSelect.getSelectBody(); PlainSelect subqueryPlainSelect = (PlainSelect) subquery.getSelectBody(); List<Expression> expressions = subqueryPlainSelect.getSelectItems(); for (Expression expression : expressions) { System.out.println(expression.toString()); } } } ``` 上述代码中,我们首先将子查询sql语句作为字符串传入JSqlParser进行解析。然后,我们通过获取Select对象和PlainSelect对象来获取子查询Select对象和PlainSelect对象。最后,我们可以通过获取子查询的PlainSelect对象来获取子查询中的Select字段。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值