The twelfth lecture of the Mysql series subqueries (very important, master must)

Subquery

The select statement that appears in the select statement is called a subquery or inner query.

The external select query is called the main query or outer query.

Subquery classification

Divided into 4 types according to the number of rows and columns of the result set

  • Scalar sub-query (the result set has only one row and one column)

  • Column query (the result set has only one column and multiple rows)

  • Row subquery (the result set has one row and multiple columns)

  • Table subquery (the result set is generally multiple rows and multiple columns)

According to the different positions of the subquery in the main query

  • After select: only supports scalar subqueries.

  • After from: Support table subquery.

  • After where or having: support scalar subquery (single column and single row), column subquery (single column and multiple rows), row subquery (multiple columns and multiple rows)

  • Behind exists (ie related subquery): table subquery (multiple rows, multiple columns)

Prepare test data

There are a lot of test data, which I put on my personal blog.

Open the link in the browser: http://www.itsoku.com/article/209

Execute the script of the javacode2018_employees library part in mysql.

Successfully created the javacode2018_employees library and 5 tables as follows:

Table Name description
departments Department table
employees Employee Information Form
jobs Job Information Form
locations Location table (will be used in the department table)
job_grades Salary scale

subquery after select

The subquery is located after the select, and only supports scalar subqueries.

Example 1

Query the number of employees in each department

SELECT
  a.*,
  (SELECT count(*)
   FROM employees b
   WHERE b.department_id = a.department_id) AS 员工个数
FROM departments a;

Example 2

Query the department name of employee number=102

SELECT (SELECT a.department_name
        FROM departments a, employees b
        WHERE a.department_id = b.department_id
              AND b.employee_id = 102) AS 部门名;

Subquery after from

The result set of the subquery is used as a table, and an alias is required, otherwise the table cannot be found.

Then connect the real table and the result table of the subquery.

Example 1

Query the salary grade of the average salary of each department

-- 查询每个部门平均工资
SELECT
  department_id,
  avg(a.salary)
FROM employees a
GROUP BY a.department_id;

-- 薪资等级表
SELECT *
FROM job_grades;

-- 将上面2个结果连接查询,筛选条件:平均工资 between lowest_sal and highest_sal;
SELECT
  t1.department_id,
  sa AS '平均工资',
  t2.grade_level
FROM (SELECT
        department_id,
        avg(a.salary) sa
      FROM employees a
      GROUP BY a.department_id) t1, job_grades t2
WHERE
  t1.sa BETWEEN t2.lowest_sal AND t2.highest_sal;

The last result of running is as follows:

mysql> SELECT
          t1.department_id,
          sa AS '平均工资',
          t2.grade_level
        FROM (SELECT
                department_id,
                avg(a.salary) sa
              FROM employees a
              GROUP BY a.department_id) t1, job_grades t2
        WHERE
          t1.sa BETWEEN t2.lowest_sal AND t2.highest_sal;
+---------------+--------------+-------------+
| department_id | 平均工资     | grade_level |
+---------------+--------------+-------------+
|          NULL |  7000.000000 | C           |
|            10 |  4400.000000 | B           |
|            20 |  9500.000000 | C           |
|            30 |  4150.000000 | B           |
|            40 |  6500.000000 | C           |
|            50 |  3475.555556 | B           |
|            60 |  5760.000000 | B           |
|            70 | 10000.000000 | D           |
|            80 |  8955.882353 | C           |
|            90 | 19333.333333 | E           |
|           100 |  8600.000000 | C           |
|           110 | 10150.000000 | D           |
+---------------+--------------+-------------+
12 rows in set (0.00 sec)

Subqueries behind where and having

After where or having, you can use

  • Scalar subquery (single row single column row subquery)

  • Column subquery (single column and multiple rows subquery)

  • Row subquery (multiple rows and multiple columns)

Features

  • The subquery is placed in parentheses.

  • Subqueries are generally placed on the right side of the condition.

  • Standard sub-query, generally used with single-line operators, multi-line operators >, <, >=, <=, =, <>, !=

  • Lie sub query, generally used with multi-line operators

  1. in(not in): "any one" in the list

  2. any or some: compare with "a certain value" returned by the subquery, such as a>som(10,20,30), a is greater than any one of the subquery, and a is greater than the minimum value in the subquery, which is equivalent to a >min(10,20,30).

  3. all: Compare with the "all values" returned by the subquery, such as a>all(10,20,30), a is greater than all the values ​​in the subquery, in other words, a is greater than the maximum value in the subquery to satisfy the query condition, which is equivalent At a>max(10,20,30);

  • The execution of the subquery takes precedence over the execution of the main query, because the conditions of the main query use the results of the subquery.

mysql中的in、any、some、all

in, any, some, all are respectively one of the keywords of the subquery.

  • in: in is often used in where expressions, its role is to query data in a certain range

  • Any is the same as some: It can be used in combination with =, >, >=, <, <=, and <> to indicate any data of equal to, greater than, greater than or equal to, less than, less than or equal to, and not equal to.

  • all: It can be used in combination with =, >, >=, <, <=, <>, respectively representing all data among equal, greater than, greater than or equal to, less than, less than or equal to, and not equal to.

These keywords will be used frequently below.

Scalar quantum query

General scalar sub-query, example
query whose salary is higher than Abel's?

/*①查询abel的工资【改查询是标量子查询】*/
SELECT salary
FROM employees
WHERE last_name = 'Abel';

/*②查询员工信息,满足salary>①的结果*/
SELECT *
FROM employees a
WHERE a.salary > (SELECT salary
                  FROM employees
                  WHERE last_name = 'Abel');

Multiple scalar subqueries, examples

Return job_id is the same as employee 141, salary is more than employee 143, name, job_id and salary

/*返回job_id与141号员工相同,salary比143号员工多的员工、姓名、job_id和工资*/
/*①查询141号员工的job_id*/
SELECT job_id
FROM employees
WHERE employee_id = 141;
/*②查询143好员工的salary*/
SELECT salary
FROM employees
WHERE employee_id = 143;
/*③查询员工的姓名、job_id、工资,要求job_id=① and salary>②*/
SELECT
  a.last_name 姓名,
  a.job_id,
  a.salary    工资
FROM employees a
WHERE a.job_id = (SELECT job_id
                  FROM employees
                  WHERE employee_id = 141)
      AND
      a.salary > (SELECT salary
                  FROM employees
                  WHERE employee_id = 143);

Subquery + grouping function, example

Query the ID of the department whose minimum wage is greater than the minimum wage of department No. 50 and its minimum wage [having]

/*查询最低工资大于50号部门最低工资的部门id和其最低工资【having】*/
/*①查询50号部门的最低工资*/
SELECT min(salary)
FROM employees
WHERE department_id = 50;
/*②查询每个部门的最低工资*/
SELECT
  min(salary),
  department_id
FROM employees
GROUP BY department_id;
/*③在②的基础上筛选,满足min(salary)>①*/
SELECT
  min(a.salary) minsalary,
  department_id
FROM employees a
GROUP BY a.department_id
HAVING min(a.salary) > (SELECT min(salary)
                        FROM employees
                        WHERE department_id = 50);

Wrong scalar subquery, example

Change the min (salary) in the sub-query statement in the above example ③ to salary, and the execution effect is as follows:

mysql> SELECT
          min(a.salary) minsalary,
          department_id
        FROM employees a
        GROUP BY a.department_id
        HAVING min(a.salary) > (SELECT salary
                                FROM employees
                                WHERE department_id = 500000);
ERROR 1242 (21000): Subquery returns more than 1 row

Error prompt: The result returned by the subquery exceeds 1 row.

Note: The above subquery only supports at most one column and one row.

Column query

Column query needs to be used with multi-line operators: in (not in), any/some, all.

In order to improve efficiency, it is best to reiterate the distinct keyword.

Example 1
returns the names of all employees in the department whose location_id is 1400 or 1700

/*返回location_id是1400或1700的部门中的所有员工姓名*/
/*方式1*/
/*①查询location_id是1400或1700的部门编号*/
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN (1400, 1700);

/*②查询员工姓名,要求部门是①列表中的某一个*/
SELECT a.last_name
FROM employees a
WHERE a.department_id IN (SELECT DISTINCT department_id
                          FROM departments
                          WHERE location_id IN (1400, 1700));

/*方式2:使用any实现*/
SELECT a.last_name
FROM employees a
WHERE a.department_id = ANY (SELECT DISTINCT department_id
                             FROM departments
                             WHERE location_id IN (1400, 1700));

/*拓展,下面与not in等价*/
SELECT a.last_name
FROM employees a
WHERE a.department_id <> ALL (SELECT DISTINCT department_id
                             FROM departments
                             WHERE location_id IN (1400, 1700));

Example 2
returns the employee number, name, job_id, salary of any employee whose salary is lower than any of the jobs whose job_id is'IT_PROG' in other jobs

/*返回其他工种中比job_id为'IT_PROG'工种任一工资低的员工的员工号、姓名、job_id、salary*/
/*①查询job_id为'IT_PROG'部门任-工资*/
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG';

/*②查询员工号、姓名、job_id、salary,slary<①的任意一个*/
SELECT
  last_name,
  employee_id,
  job_id,
  salary
FROM employees
WHERE salary < ANY (SELECT DISTINCT salary
                    FROM employees
                    WHERE job_id = 'IT_PROG') AND job_id != 'IT_PROG';

/*或者*/
SELECT
  last_name,
  employee_id,
  job_id,
  salary
FROM employees
WHERE salary < (SELECT max(salary)
                FROM employees
                WHERE job_id = 'IT_PROG') AND job_id != 'IT_PROG';

Example 3
returns the employee number, name, job_id, salary of all employees whose salary is lower than that of the department with job_id of'IT_PROG' in other types of work

/*返回其他工种中比job_id为'IT_PROG'部门所有工资低的员工的员工号、姓名、job_id、salary*/
SELECT
  last_name,
  employee_id,
  job_id,
  salary
FROM employees
WHERE salary < ALL (SELECT DISTINCT salary
                    FROM employees
                    WHERE job_id = 'IT_PROG') AND job_id != 'IT_PROG';

/*或者*/
SELECT
  last_name,
  employee_id,
  job_id,
  salary
FROM employees
WHERE salary < (SELECT min(salary)
                FROM employees
                WHERE job_id = 'IT_PROG') AND job_id != 'IT_PROG';

Row subquery (result set with one row and multiple columns)

Example
Query the information of the employee with the smallest employee number and the highest salary, in 3 ways.

/*查询员工编号最小并且工资最高的员工信息*/
/*①查询最小的员工编号*/
SELECT min(employee_id)
FROM employees;
/*②查询最高工资*/
SELECT max(salary)
FROM employees;
/*③方式1:查询员工信息*/
SELECT *
FROM employees a
WHERE a.employee_id = (SELECT min(employee_id)
                       FROM employees)
      AND salary = (SELECT max(salary)
                    FROM employees);

/*方式2*/
SELECT *
FROM employees a
WHERE (a.employee_id, a.salary) = (SELECT
                                     min(employee_id),
                                     max(salary)
                                   FROM employees);
/*方式3*/
SELECT *
FROM employees a
WHERE (a.employee_id, a.salary) in (SELECT
                                     min(employee_id),
                                     max(salary)
                                   FROM employees);

Way 1 is more common, while Ways 2 and 3 are more concise.

After exists (also called correlated subquery)

Syntax: exists (fun query statement).

  • exists query result: 1 or 0, the result of exists query is used to determine whether there is a value in the result set of the subquery.

  • Generally speaking, subqueries that can use exists can definitely be replaced by in, so exists is used less.

  • Different from the previous query, this first executes the main query, and then the results of the main query are filtered according to the sub-query. The sub-query involves the fields used in the main query, so it is called a related sub-query.

Example 1
simple example

mysql> SELECT exists(SELECT employee_id
              FROM employees
              WHERE salary = 300000) AS 'exists返回1或者0';
+----------------------+
| exists返回1或者0     |
+----------------------+
|                    0 |
+----------------------+
1 row in set (0.00 sec)

Example 2
Query the department name of all employees

/*exists入门案例*/
SELECT exists(SELECT employee_id
              FROM employees
              WHERE salary = 300000) AS 'exists返回1或者0';

/*查询所有员工部门名*/
SELECT department_name
FROM departments a
WHERE exists(SELECT 1
             FROM employees b
             WHERE a.department_id = b.department_id);

/*使用in实现*/
SELECT department_name
FROM departments a
WHERE a.department_id IN (SELECT department_id
                          FROM employees);

Example 3
Query departments without employees

/*查询没有员工的部门*/
/*exists实现*/
SELECT *
FROM departments a
WHERE NOT exists(SELECT 1
                 FROM employees b
                 WHERE a.department_id = b.department_id AND b.department_id IS NOT NULL);
/*in的方式*/
SELECT *
FROM departments a
WHERE a.department_id NOT IN (SELECT department_id
                              FROM employees b
                              WHERE b.department_id IS NOT NULL);

There is b.department_id IS NOT NULL in the above script. Why, there is a big hole, look down.

NULL's big pit

Use in to query departments without employees, as follows:

SELECT *
FROM departments a
WHERE a.department_id NOT IN (SELECT department_id
                              FROM employees b);

operation result:

mysql> SELECT *
    -> FROM departments a
    -> WHERE a.department_id NOT IN (SELECT department_id
    ->                               FROM employees b);
Empty set (0.00 sec)

In the case of in, when the value of the column in the subquery is NULL, the result of the outer query is empty.

Suggestion: When building a table, the column is not allowed to be empty.

Guess you like

Origin blog.csdn.net/m0_47157676/article/details/108699941