数据库子查询

postgres LATERAL

​ 在PostgreSQL中,LATERAL关键字用于在FROM子句中引用前面的FROM项提供的列。通过使用LATERAL,您可以在子查询或函数中引用前面FROM子句中的列。

在没有LATERAL的情况下,每个子查询或函数都是独立求值的,因此不能交叉引用其他FROM项。但是,使用LATERAL关键字后,您可以在子查询或函数中引用位于其前面的FROM项中的列,从而进行交叉引用。

LATERAL可以出现在FROM列表的顶层,也可以出现在JOIN树中。在JOIN树中,它还可以引用位于JOIN右侧的左侧的任何项。

计算过程如下:对于提供交叉引用列的FROM项的每一行,或者多个FROM项提供引用列的行的集合,LATERAL项会使用行或行集的列值进行计算。计算出来的结果集将像往常一样被加入到联合查询中。这一过程会在列的来源表的每一行或行的集合上重复进行。

请注意,使用LATERAL可能会增加查询的计算复杂性,因为它涉及对多个FROM项进行交叉引用。因此,在使用LATERAL时要谨慎,并确保查询的逻辑和性能符合您的需求。

基础数据

当然,以下是一个使用PostgreSQL中的LATERAL关键字的例子:

假设我们有两个表:customers(客户表)和orders(订单表),并且每个客户可以有多个订单。我们想要检索每个客户的订单数以及订单的总金额。

首先,我们会创建这两个表的简单版本:

--create table
CREATE TABLE customers (  
  customer_id INT PRIMARY KEY,  
  customer_name VARCHAR(50)  
);  
  
CREATE TABLE orders (  
  order_id INT PRIMARY KEY,  
  customer_id INT REFERENCES customers(customer_id),  
  order_amount DECIMAL(10, 2)  
);
--insert
INSERT INTO customers (customer_id, customer_name)  
VALUES  
  (1, 'John Doe'),  
  (2, 'Jane Smith'),  
  (3, 'Michael Johnson');

INSERT INTO orders (order_id, customer_id, order_amount)  
VALUES  
  (1, 1, 100.00),  
  (2, 1, 200.00),  
  (3, 2, 150.00),  
  (4, 3, 50.00),  
  (5, 3, 250.00);

查询示例

SELECT c.customer_id, c.customer_name, o.total_orders, o.total_amount  
FROM customers c,  
LATERAL (  
  SELECT COUNT(*) AS total_orders, SUM(order_amount) AS total_amount  
  FROM orders  
  WHERE customer_id = c.customer_id  
) o;
--查询结果
SELECT c.customer_id, c.customer_name, o.total_orders, o.total_amount  
FROM customers c,  
LATERAL (  
  SELECT COUNT(*) AS total_orders, SUM(order_amount) AS total_amount  
  FROM orders  
  WHERE customer_id = c.customer_id  
  7  ) o;

CUSTOMER_ID CUSTOMER_NAME                                                                                             TOTAL_ORDERS TOTAL_AMOUNT
          1 John Doe                                                                                                        2          300
          2 Jane Smith                                                                                                      1          150
          3 Michael Johnson                                                                                                 2          300

C##SCOTT@LHRCDB> 

oracle 子查询

select t. from (select * from emp order by sal desc) t where rownum<4;*

由此可见使用子查询需要注意:

子查询要在括号内,括号内子查询只返回一行
子查询放在比较条件右侧增强可读性
单行操作符对应单行子查询,多行操作符对应多行子查询
————————————————
版权声明:本文为CSDN博主「十三妹_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41896822/article/details/127929554

一、单行子查询

  • 只返回一行
  • 比较操作符:= > >= < <= <>(<>不等于,等价于!=)

使用单行比较操作符

--##例,查询工作与7369相同且工资大于7876的员工信息
select empno,ename,sal from emp where job=(select job from emp where empno=7369) and sal >(select sal from emp where empno=7876);
 
     EMPNO ENAME                       SAL
---------- -------------------- ----------
      7788 SCOTT                      3000
      7934 MILLER                     1300

C##SCOTT@LHRCDB> 

使用分组函数

--#例 ,查询工资最低的员工
select empno,ename,sal from emp where sal=(select min(sal) from emp);
 
     EMPNO ENAME	     SAL
---------- ---------- ----------
      7369 SMITH	     800

--##上述子查询等价于:

select empno,ename,sal from emp order by sal asc fetch first 1 rows only;

子查询使用HAVING

使用HAVING

  • 首先执行子查询
  • 想主查询的having语句返回结果
--#例 查询哪些部门最低工资比20号部门最低工资高
select deptno,min(sal) from emp group by deptno having min(sal) >(select min(sal) from emp where deptno=20);
 
    DEPTNO   MIN(SAL)
---------- ----------
	30	  950
	10	 1300
--# 查询平均工资最高的职位
select job,avg(sal) from emp group by job having avg(sal)=(select max(avg(sal)) from emp group by job);
JOB	    AVG(SAL)
--------- ----------
PRESIDENT	5000
--#为了测试子查询,但从结果来说有多种查询方法

注:单行子查询返回有多行结果时,会出错

ORA-01427*:*single-row subquery returns more than one row

二、多行子查询

1、操作符

  • IN 等于列表中的某一个值
  • ANY 与列表的任意值比较
  • ALL 与列表所有值比较

2、返回值多于一行

--#查询是领导的员工,mgr存的是员工的领导工号
select empno,ename from emp where empno in (select mgr from emp);
 
     EMPNO ENAME
---------- ----------
      7566 JONES
      7698 BLAKE
      7782 CLARK
      7788 SCOTT
      7839 KING
      7902 FORD
 
6 rows selected.
 
select empno,ename from emp where empno not in (select mgr from emp);
 
no rows selected
 
select empno,ename from emp where empno not in (select mgr from emp where mgr is not null);
 
     EMPNO ENAME
---------- ----------
      7369 SMITH
      7499 ALLEN
      7521 WARD
      7654 MARTIN
      7844 TURNER
      7876 ADAMS
      7900 JAMES
      7934 MILLER
 
8 rows selected.

从上述可知,使用NOT IN时不能对null操作

使用ANY

--#查询工资比职位是 clerk 的员工中任意(某)一个低的员工信息
select empno,ename,sal from emp where sal < any (select sal from emp where job='CLERK') and job !='CLERK';
 
     EMPNO ENAME	     SAL
---------- ---------- ----------
      7521 WARD 	    1250
      7654 MARTIN	    1250

附:

  • < any :小于最大值

  • > any :大于最小值

  • = any :等价于 in

使用ALL

--# 例,查询工资比各部门平均工资都高的员工
select empno,ename,sal from emp where sal > all (select avg(sal) from emp group by deptno);
 
     EMPNO ENAME	     SAL
---------- ---------- ----------
      7566 JONES	    2975
      7788 SCOTT	    3000
      7902 FORD 	    3000
      7839 KING 	    5000

多行多列子查询要使用多行操作符,如:

select empno,ename,sal,job from emp
where (job,sal) in (select job,sal from emp where deptno=10)   and empno<>7788;

在FROM中使用子查询

--#例:查询比本部门平均工资高的员工
select a.empno,a.ename,a.sal,a.job,a.deptno,b.avgsal from emp a, (select deptno,avg(sal) avgsal from emp group by deptno) b where a.deptno=b.deptno and a.sal > b.avgsal;
 
     EMPNO ENAME	     SAL JOB	       DEPTNO	  AVGSAL
---------- ---------- ---------- --------- ---------- ----------
      7499 ALLEN	    1600 SALESMAN	   30 1566.66667
      7566 JONES	    2975 MANAGER	   20	    2175
      7698 BLAKE	    2850 MANAGER	   30 1566.66667
      7788 SCOTT	    3000 ANALYST	   20	    2175
      7839 KING 	    5000 PRESIDENT	   10 2916.66667
      7902 FORD 	    3000 ANALYST	   20	    2175
 
6 rows selected.

关联子查询

普通子查询:在主查询执行之前,子查询首先执行一次。子查询的结果要在主查询中使用。

关联子查询需要重复执行子查询。(where写在子查询中)

--#例:查询比本部门平均工资高的员工
select a.empno,a.ename,a.sal,a.deptno from emp a where a.sal > (select avg(sal) from emp b  where a.deptno=b.deptno);
 
     EMPNO ENAME	     SAL     DEPTNO
---------- ---------- ---------- ----------
      7499 ALLEN	    1600	 30
      7566 JONES	    2975	 20
      7698 BLAKE	    2850	 30
      7788 SCOTT	    3000	 20
      7839 KING 	    5000	 10
      7902 FORD 	    3000	 20
 
6 rows selected.

在SELECT中使用子查询

--#例:查询员工所属的部门名
select empno,ename,deptno, (select dname from dept d where a.deptno=d.deptno) from emp a;
 
     EMPNO ENAME	  DEPTNO (SELECTDNAMEFR
---------- ---------- ---------- --------------
      7369 SMITH	      20 RESEARCH
      7499 ALLEN	      30 SALES
      7521 WARD 	      30 SALES
      7566 JONES	      20 RESEARCH
      7654 MARTIN	      30 SALES
      7698 BLAKE	      30 SALES
      7782 CLARK	      10 ACCOUNTING
      7788 SCOTT	      20 RESEARCH
      7839 KING 	      10 ACCOUNTING
      7844 TURNER	      30 SALES
      7876 ADAMS	      20 RESEARCH
      7900 JAMES	      30 SALES
      7902 FORD 	      20 RESEARCH
      7934 MILLER	      10 ACCOUNTING
 
14 rows selected.
使用exists 和 not exists
--#,查询是经理的员工
select a.empno,a.ename from emp a where exists (select 1 from emp b where b.mgr=a.empno);
 
     EMPNO ENAME
---------- ----------
      7566 JONES
      7698 BLAKE
      7782 CLARK
      7788 SCOTT
      7839 KING
      7902 FORD
 
6 rows selected.
--#,查询不是经理的员工
select a.empno,a.ename from emp a where not exists (select 1 from emp b where b.mgr=a.empno);
 
     EMPNO ENAME
---------- ----------
      7369 SMITH
      7499 ALLEN
      7521 WARD
      7654 MARTIN
      7844 TURNER
      7876 ADAMS
      7900 JAMES
      7934 MILLER
 
8 rows selected.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值