马哈鱼数据血缘分析器中的子查询语句分析

2021-09-23

在实际生产环境中,无论你的业务复杂与否,子查询都是绕不开的话题,本文带你了解一下马哈鱼数据血缘分析器是如果处理各种子查询的。通过本文你能了解到不同场景的子查询在马哈鱼中的展示状态。

嵌套子查询可以说是SQL语句中比较复杂的一部分,它可以提高查询效率,简化SQL语句的实现逻辑。子查询指的是一个查询语块可以嵌套在另外一个查询语句块的Form子句、where子句或者having子句中,根据位置不同可分为为子查询或内查询,后者为父查询或外查询。

下面我们逐步分析各种使用场景中子查询对应马哈鱼中的显示状态:

一、子查询分类场景分析

1、在From中声明子查询

最常见的子查询使用场景之一是它作为派生表与其他表或视图进行关联分析,这一类子查询主要有两种类型,一种是子查询作为派生表与其他表进行关联;另一种是子查询形成的派生表作为外层查询的唯一表。后者是前者的一种特殊情况,这两种情况下,子查询所产生的的中间结果集均会被马哈鱼显示并作为外层结果集的部分或全部数据源,如下:

--形式一:子查询派生表与其他表进行关联
SELECT e.employee_id,e.last_name,e.salary,dept_avg_sal.avg_sal
FROM employees e,(
        SELECT department_id,AVG(salary) avg_sal
        FROM employees
        GROUP BY department_id
        )  dept_avg_sal
WHERE e.department_id = dept_avg_sal.department_id
AND e.salary > dept_avg_sal.avg_sal

image-20210917223501706

形式二:子查询作为派生表
select * from (
  select dt.d_year
    ,item.i_brand_id brand_id
    ,item.i_brand brand
    ,sum(ss.ss_sales_price) sum_agg
 from date_dim dt
   ,store_sales ss
   ,item
 where dt.d_date_sk = store_sales.ss_sold_date_sk
  and store_sales.ss_item_sk = item.i_item_sk
  and item.i_manufact_id = 816
  and dt.d_moy=11
 group by dt.d_year
   ,item.i_brand
   ,item.i_brand_id
 order by dt.d_year
     ,sum_agg desc
     ,brand_id
        ) where rownum <= 100;

image-20210917224328673

2、单值子查询

单值子查询作为子查询中较为常见的一种使用方式,它可以是相关子查询也可以是不相关子查询,它产生的结果集因为仅作用于限制外层查询返回数据的多少,本身并不影响外层查询返回的列数,所以,它的中间结果集会被单独列出,如下图:

SELECT employee_id,last_name,salary
FROM employees e1
WHERE salary > (
        SELECT AVG(salary)
        FROM employees e2
        WHERE e2.department_id = e1.department_id  );

image-20210917223809982

3、返回结果集中的子查询

返回结果集中的子查询必须是返回单列,一般是相关子查询,它返回的值作为外层查询的一个列,直接影响到最终查询结果集,所以它的中间结果集的地位会会像其他表或视图一样,作为最终结果集的源数据提供者,如下图:

--子查询作为返回值
select dt.d_year
    ,item.i_brand_id brand_id
    ,item.i_brand brand
    ,sum(ss.ss_sales_price) sum_agg
  ,(select score from  store_sales where storeid=1) score
 from date_dim dt
   ,store_sales ss
   ,item
 where dt.d_date_sk = store_sales.ss_sold_date_sk
  and store_sales.ss_item_sk = item.i_item_sk
  and item.i_manufact_id = 816
  and dt.d_moy=11
 group by dt.d_year
   ,item.i_brand
   ,item.i_brand_id
 order by dt.d_year
     ,sum_agg desc
     ,brand_id

image-20210917225457503

4、嵌套子查询--IN表达式

嵌套子查询(in)它可以是相关子查询也可以是不相关子查询,它产生的结果集因为仅作用于筛选外层查询返回数据的多少,本身并不影响外层查询返回的列数,所以,它的中间结果集会被单独列出,如下图

--子查询在in表达式内
SELECT employee_id,last_name,job_id,department_id
FROM employees
WHERE employee_id IN (
            SELECT DISTINCT manager_id
            FROM employees);

image-20210917230154021

5、嵌套子查询--[not]exists表达式

嵌套子查询([not]exists)它可以是相关子查询也可以是不相关子查询,它产生的结果集因为仅作用于筛选外层查询返回数据的多少,本身并不影响外层查询返回的列数,所以,它的中间结果集会被单独列出,如下图

--场景一:子查询中返回表中列
SELECT employee_id,last_name,job_id,department_id
FROM employees e1
WHERE EXISTS (
        SELECT employee_id
        FROM employees 
        WHERE e1.employee_id = manager_id
        );
       

image-20210917230543519

--场景二:子查询中返回常量
SELECT employee_id,last_name,job_id,department_id
FROM employees e1
WHERE EXISTS (
        SELECT 1
        FROM employees 
        WHERE e1.employee_id = manager_id
        );

image-20210917230807539

6、在having子句中使用子查询

having子句中的子查询也是用于筛选分组后的数据集合,它本质还是用于筛选数据本身,并不会影响外层结果集的结构,所以它的中间结果集会被单独列出,如下图:

--在having子句中使用子查询
SELECT d.deptno,d.dname,AVG(e.sal) avgsal
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY d.deptno,d.dname
HAVING AVG(e.sal)=(SELECT MAX(AVG(sal))
     FROM emp GROUP BY deptno);

image-20210918000210984

二、总结分析

通过分析子查询的各种使用场景,我们不难发现,子查询的位置决定了它所形成的中间结果集在马哈鱼分析结果上的位置,根据子查询所在的位置,我们可以简单总结如下:

  • where子句之前的子查询,它的中间结果集会参与它外层查询的结果集的形成,中间结果集在马哈鱼分析界面上和表或视图地位一致;
  • where子句之后的子查询,它的结果集仅参与外层查询返回数据的筛选限制,本身不会对外层查询结果集的结构产生影响,马哈鱼将它的中间结果集和外层结果集并列展示。

三、参照

马哈鱼数据血缘分析器: https://sqlflow.gudusoft.com

马哈鱼数据血缘分析器中文网站: https://www.sqlflow.cn