子查询

在嵌套查询中,最外面查询结果集返回给调用方,称为外部查询。嵌套在外部查询内的查询称为子查询,子查询的结果集供外部查询使用

根据是否依赖外部查询,可将子查询分为自包含子查询和相关子查询。自包含子查询不依赖外部查询,相关子查询则依赖外部查询。

子查询结果是在运行时计算的,查询结果会跟随查询表的变化而改变。子查询可以返回单个值(标量)、多个值或者整个表结果。

在逻辑上,子查询代码仅在外部查询计算之前计算一次

自包含子查询

USE WJChi;
​
SELECT * FROM dbo.UserInfo WHERE Age=
(SELECT MAX(Age) FROM dbo.UserInfo
);

相关子查询

USE WJChi;
​
SELECT * FROM dbo.UserInfo AS UI WHERE IdentifyId =
(SELECT Id FROM dbo.Identify WHERE Id=UI.IdentifyId
);

子查询易错点

NULL值处理不当
USE WJChi;
​
SELECT * FROM dbo.Customers
WHERE custid NOT IN(SELECT TOP 10 C.custid FROM dbo.Customers AS C ORDER BY C.custid
);

上述查询语句看起来可以正常运行,但当子查询的返回结果集中包含NULL值时,上述查询语句则不会返回任何数据。解释如下:

20 NOT IN(10, 9, 8, NULL)等价于NOT(20=10 OR 20=9 OR 20=8 OR 20=NULL)NULL参与的比较预算结果均为UnknownUnknown参与的或运算结果依然为Unknown

⚠️ 我们应时刻牢记SQL是三值逻辑,这点很容易引发错误

列名处理不当

子查询中的列名首先从当前查询中进行解析,若未找到则到外部查询中查找。子查询中很有可能无意中包含了外部查询的列名导致子查询有自包含子查询变为相关子查询而引发逻辑错误。

为避免上述错误,查询中的列名尽可能使用完全限定名:[表名].[列名]

⚠️ 通常我们自己难以发现代码中的逻辑错误,而我们的最终用户尝尝扮演着问题发现者的角色 ?

编写语义清晰明了的SQL可以很大程度的避免逻辑上的错误

表表达式

表表达式,也可称为表子查询,是一个命名的查询表达式,表示一个有效的关系表,因此表表达式必须满足以下三个条件:

  1. 无法表表达式结果集顺序

表表达式表示一个关系表,关系型数据库基于集合理论,表中的数据是无序的。标准SQL中不允许在表表达式中使用ORDER BY子句,除非ORDER BY子句用于展示之外的其他目的,否则会报错:

除非另外还指定了 TOP、OFFSET 或 FOR XML,否则,ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效.

⚠️在查询表表达式时,除非在外部查询中指定了ORDER BY子句,否则无法保证查询结果集中数据的顺序。有时候会看到即使外部查询未使用ORDER BY但查询结果集按预期顺序返回了结果,这是由于数据库自身优化的结果,依然无法保证每次查询都能按预期结果返回。

  1. 所有列必须显式指定名称

  2. 所有列名必须唯一

表表达式分为:派生表、公用表表达式、视图三种类型。其中,派生表与公用表表达式只适用于单语句范围,即,只存在于当前查询语句中。视图则可以被多条查询语句复用

派生表

派生表又称为子查询表,在外部查询的FROM子句中进行定义,一旦外部查询结束,派生表也就不复存在。

在一次查询中派生表无法被多次引用,若要多次引用,则需要多次书写派生表:

USE WJChi;
​
SELECT Cur.orderyear, Prv.numcusts AS prvnumcusts, Cur.numcusts - Prv.numcusts AS growth
FROM (SELECT YEAR(orderdate) AS orderyear, COUNT(DISTINCT custid) AS numcustsFROM dbo.Orders GROUP BY YEAR(orderdate) AS CurLEFT JOIN-- 为了再次使用派生表,需要重复书写相同逻辑SELECT YEAR(orderdate) AS orderyear, COUNT(DISTINCT custid) AS numcustsFROM dbo.Orders GROUP BY YEAR(orderdate) AS PrvON Cur.orderyear = Prv.orderyear + 1
);

公用表表达式

公用表表达式(CTE)定义方式如下:

WITH...AS
(...
)

与派生表类似,外部查询完成后,CTE也就消失了。但,不同于派生表,CTE可以在一次查询中多次使用(但不能嵌套使用而派生表可以):

USE WJChi;
​
WITH YearlyCount AS
(SELECT YEAR(orderdate) AS orderyear, COUNT(DISTINCT custid) AS numcustsFROM dbo.OrdersGROUP BY YEAR(orderdate)
)
SELECT Cur.orderyear, Prv.numcusts AS prvnumcusts
FROM YearlyCount AS Cur
LEFT JOIN
-- 再次使用CTE
YearlyCount AS Prv
ON Cur.orderyear = Prv.orderyear + 1;

这里需要注意一点:CTE之前的SQL语句要以分号(;)结尾。

我们也可以在一次查询中定义多个CTE:

-- WITH只需要使用一次
WITH Temp1 AS
(
),
Temp2 AS
(
)
SELECT ...

视图

视图是虚拟表,自身不包含数据,只存储了动态查询语句,多用于简化复杂查询。

视图创建后被作为数据库对象而存储到数据库中,除非显式进行删除。因此,同一个视图可以被不同的查询多次使用。

使用以下语句创建视图:

CREATE VIEW ViewName
AS
...

修改视图:

ALTER VIEW ViewName
AS
...

删除视图:

DROP VIEW ViewName;

视图是数据库中的对象,因此我们可以控制其访问权限,如:SELECT、UPDATE或访问视图底层数据表等。

视图一旦创建,在底层数据表发生变更后,其不会自动更新。因此,在视图中使用SELECT语句时尽可能显式的指定所需列,而不是使用SELECT *。可以使用存储过程:sp_refreshviewsp_refreshsqlmodule来更新视图的元数据,或者使用ALTER语句修改视图定义。

关于是否应该使用视图,仁者见仁,智者见智:

使用SQL Server视图的优缺点

为什么mysql中很少见到使用视图功能?

小结

不要让数据库(查询)变得复杂;

表表达式有助于简化代码以提升可读性与可维护性;

推荐阅读

T-SQL基础(二)之关联查询

转载于:https://www.cnblogs.com/Cwj-XFH/p/10012936.html

T-SQL基础(三)之子查询与表表达式相关推荐

  1. c语言子查询返回子菜单,T-SQL基础(三)之子查询与表表达式

    子查询 在嵌套查询中,最外面查询结果集返回给调用方,称为外部查询.嵌套在外部查询内的查询称为子查询,子查询的结果集供外部查询使用. 根据是否依赖外部查询,可将子查询分为自包含子查询和相关子查询.自包含 ...

  2. MySQL基础篇:子查询

    文章目录 概述 where型子查询 from型子查询 EXISTS型子查询 复制表子查询 概述 在某些情况下,当进行一个查询时,需要的条件或数据要用另一个select语句的结果,这个时候,就要用到** ...

  3. MySQL学习思维导图(MySQL简介、SQL基础命令、约束、单表查询、多表查询、内置函数、存储过程、视图、事务、索引)

    MySQL学习思维导图 内容包括:MySQL简介.SQL基础命令.约束.单表查询.多表查询.内置函数.存储过程.视图.事务.索引 文章目录 MySQL学习思维导图 一.MySQL简介 二.SQL基础命 ...

  4. SQL进阶之关联子查询行间比较

    SQL进阶之关联子查询行间比较 关联子查询行间比较 越前须知(雾) 具体用法 与最近一年比较营收 移动平均值和移动累计值 查询重叠的时间区间 关联子查询行间比较 越前须知(雾) 本系列参考<SQ ...

  5. SQL进阶之关联子查询练习

    SQL进阶之关联子查询 一.关联子查询简介 二.关联子查询实操 1.CreateTable 2.Sample 一.关联子查询简介 通过关联表内部条件从而达到查询效果 二.关联子查询实操 注:版本使用: ...

  6. cte公用表表达式_SQL Server中的CTE; 查询公用表表达式

    cte公用表表达式 Common table expressions (CTEs) in SQL Server provide us with a tool that allows us to des ...

  7. 阿里云AI训练营-SQL基础3:复杂查询方法-视图、子查询、函数等

    3.1 视图 3.1.1 什么是视图 3.1.2 视图与表有什么区别 3.1.3 为什么会存在视图 3.1.4 如何创建视图 3.1.5 如何修改视图结构 3.1.6 如何更新视图内容 3.1.7 如 ...

  8. SQL Server调优系列基础篇(子查询运算总结)

    前言 前面我们的几篇文章介绍了一系列关于运算符的介绍,以及各个运算符的优化方式和技巧.其中涵盖:查看执行计划的方式.几种数据集常用的连接方式.联合运算符方式.并行运算符等一系列的我们常见的运算符.有兴 ...

  9. sql 基础语法 创建数据库和数据表 数据增删改查 分组查询 子查询回顾

    参考链接: SQL教程 MySQL教程 一.创建数据库语法 --用master数据库 use master --判断数据库是否存在,若存在则删除 if exists (select * from sy ...

最新文章

  1. 1、Android测试入门
  2. Animy.js,自己编写的功能丰富的html动画库
  3. 单片机学习--3D动画演示单片机工作原理
  4. ad怎么批量改元器件封装_Altium Designer 批量修改元件封装的方法(修正)
  5. Web控件TreeView展开无闪烁的两个解决方法
  6. 前端学习(2062):vue的option选项
  7. python中gmtime的hour错误_python中gmtime的hour错误_在Python中操作日期和时间之gmtime()方法的使用...
  8. 微信朋友圈删除后可重新编辑了 网友:这有啥用
  9. 横向扩展 纵向扩展 数据库_扩展数据库–减少扩展的艺术
  10. Linux系统管理(3)——防火墙 iptables基本原理 四表五链 NetFilter 概述
  11. python的基本语法while true_Python正课15 —— 流程控制之while循环
  12. 阅卷系统java语言_利用Python开发智能阅卷系统
  13. biopython有什么用_用Biopython解析BLAST结果
  14. 百度贴吧恶意代码分析
  15. (GIS可视化)热力图
  16. 关于printf的输出——进制转换
  17. Python Rule Engine
  18. 【敏捷】敏捷时代的建模:敏捷团队的扩张除了代码还需要什么? (ZZ)
  19. EDA之立创EDA专业版使用(原理图绘制)
  20. oracle add_months()函数

热门文章

  1. 掘金健康大数据 需突破多重挑战
  2. 谁说程序员干到 35 岁就不行了?
  3. java出现no XXX in java.library.path的解决办法及eclipse配置
  4. OOP设计思考——何时使用接口?
  5. php中区分大小写的超全局变量总结
  6. 在不重装XP系统,增加系统盘剩余空间
  7. 优化调整Oracle 8i数据库
  8. 图像聚类与检索的简单实现(一)
  9. ORACLE NOT EXISTS不等值 改写成hive
  10. MVC的开发模式简单介绍