SQL高级查询方法

Wesley13
• 阅读 749

正文共:5024 字 2 图  预计阅读时间:14 分钟

前文推送

  1. SQL Server入门

  2. Transact-SQL基础(上)

  3. Transact-SQL基础(下)

  4. SQL笔试50题(上)

  5. SQL笔试50题(下)

  6. SQL基础查询方法

本文目录:

  • 4.8 子查询 subquery

  • 4.9 联接 join

  • 4.10 UNION运算符

  • 4.11 EXCEPT和INTERSECT半联接

  • 4.12 公用表表达式 WITH

4.8 子查询 subquery

子查询是一个嵌套在 SELECT、INSERT、UPDATE 或 DELETE 语句或其他子查询中的查询。任何允许使用表达式的地方都可以使用子查询。

子查询也称为内部查询或内部选择,而包含子查询的语句也称为外部查询或外部选择。

有三种基本的子查询。它们是:

  • 在通过 IN 或由 ANY 或 ALL 修改的比较运算符引入的列表上操作。WHERE expression [NOT] IN (subquery)

  • 通过未修改的比较运算符引入且必须返回单个值。WHERE expression comparison_operator [ANY | ALL] (subquery)

  • 通过 EXISTS 引入的存在测试。WHERE [NOT] EXISTS (subquery)

许多包含子查询的 Transact-SQL 语句都可以改用联接表示。其他问题只能通过子查询提出。

在 Transact-SQL 中,包含子查询的语句和语义上等效的不包含子查询的语句(即联接的方式)在性能上通常没有差别。但是,在一些必须检查存在性的情况中,使用联接会产生更好的性能。否则,为确保消除重复值,必须为外部查询的每个结果都处理嵌套查询。所以在这些情况下,联接方式会产生更好的效果。

子查询的 SELECT 查询总是使用 圆括号括起来。它不能包含 COMPUTE 或 FOR BROWSE 子句,如果同时指定了 TOP 子句,则只能包含 ORDER BY 子句。

子查询受下列 限制的制约:

  • 通过比较运算符引入的子查询选择列表只能包括一个表达式或列名称(对 SELECT * 执行的 EXISTS 或对列表执行的 IN 子查询除外)。

  • 如果外部查询的 WHERE 子句包括列名称,它必须与子查询选择列表中的列是联接兼容的。

  • ntext、text 和 image 数据类型不能用在子查询的选择列表中。

  • 由于必须返回单个值,所以由未修改的比较运算符(即后面未跟关键字 ANY 或 ALL 的运算符)引入的子查询不能包含 GROUP BY 和 HAVING 子句。

  • 包含 GROUP BY 的子查询不能使用 DISTINCT 关键字。

  • 不能指定 COMPUTE 和 INTO 子句。

  • 只有指定了 TOP 时才能指定 ORDER BY。

  • 不能更新使用子查询创建的视图。

  • 按照惯例,由 EXISTS 引入的子查询的选择列表有一个星号 (*),而不是单个列名。因为由 EXISTS 引入的子查询创建了存在测试并返回 TRUE 或 FALSE 而非数据,所以其规则与标准选择列表的规则相同。

子查询的例子可以参考笔试题中的例子,SQL笔试50题(上)SQL笔试50题(下)

4.9 联接 join

通过联接,可以从两个或多个表中根据各个表之间的逻辑关系来检索数据。

联接条件可通过以下方式定义两个表在查询中的关联方式:

  • 指定每个表中要用于联接的列。典型的联接条件在一个表中指定一个外键,而在另一个表中指定与其关联的键。

  • 指定用于比较各列的值的逻辑运算符(例如 = 或 <>)。

可以在 FROM 或 WHERE 子句中指定 内部联接;而只能在 FROM 子句中指定 外部联接。联接条件与 WHERE 和 HAVING 搜索条件相结合,用于控制从 FROM 子句所引用的基表中选定的行。

比如下列联接因为是内部联接,因此也可以改写为在WHERE条件中指定联接。

      1
    
      
 
     
     
     -- FROM中指定联接(首选)
    
      
 
     
     
     
    
      
 
     
     
      2
    
      
 
     
     
     SELECT pv.ProductID, v.BusinessEntityID, v.Name
    
      
 
     
     
     
    
      
 
     
     
      3
    
      
 
     
     
     FROM Purchasing.ProductVendor 
    
      
 
     
     
     AS pv 
    
      
 
     
     
     
    
      
 
     
     
      4
    
      
 
     
     
     JOIN Purchasing.Vendor 
    
      
 
     
     
     AS v
    
      
 
     
     
     
    
      
 
     
     
      5    
    
      
 
     
     
     ON (pv.BusinessEntityID = v.BusinessEntityID)
    
      
 
     
     
     
    
      
 
     
     
      6
    
      
 
     
     
     WHERE StandardPrice > 
    
      
 
     
     
     10
    
      
 
     
     
     
    
      
 
     
     
      7    
    
      
 
     
     
     AND 
    
      
 
     
     
     Name 
    
      
 
     
     
     LIKE N
    
      
 
     
     
     'F%';
    
      
 
     
     
     
    
      
 
     
     
      8
    
      
 
     
     
     -- WHERE中指定联接
    
      
 
     
     
     
    
      
 
     
     
      9
    
      
 
     
     
     SELECT pv.ProductID, v.BusinessEntityID, v.Name
    
      
 
     
     
     
    
      
 
     
     
     10
    
      
 
     
     
     FROM Purchasing.ProductVendor 
    
      
 
     
     
     AS pv, Purchasing.Vendor 
    
      
 
     
     
     AS v
    
      
 
     
     
     
    
      
 
     
     
     11
    
      
 
     
     
     WHERE pv.VendorID = v.VendorID
    
      
 
     
     
     
    
      
 
     
     
     12    
    
      
 
     
     
     AND StandardPrice > 
    
      
 
     
     
     10
    
      
 
     
     
     
    
      
 
     
     
     13    
    
      
 
     
     
     AND 
    
      
 
     
     
     Name 
    
      
 
     
     
     LIKE N
    
      
 
     
     
     'F%';
    
      
 
     
     
     
   
     

    
    
    

在 FROM 子句中指定联接条件有助于将这些联接条件与 WHERE 子句中可能指定的其他任何搜索条件分开,建议用这种方法来指定联接。简化的 ISO FROM 子句联接语法如下:

     1FROM first_table  
    
      
 
     
     
     
    
      
 
     
     
     2join_type  
    
      
 
     
     
     
    
      
 
     
     
     3second_table 
    
      
 
     
     
     
    
      
 
     
     
     4[ON (join_condition)]
    
      
 
     
     
     
   
     

    
    
    

join_type 指定要执行的联接类型

  • 内部联接(典型的联接运算,使用类似于 = 或 <> 的比较运算符)。内部联接包括同等联接和自然联接。

  • 外部联接。外部联接可以是左向外部联接、右向外部联接或完整外部联接。

    在 FROM 子句中可以用下列某一组关键字来指定外部联接:

  • LEFT JOIN 或 LEFT OUTER JOIN。

    左向外部联接的结果集包括 LEFT OUTER 子句中指定的左表的所有行,而不仅仅是联接列所匹配的行。如果左表的某一行在右表中没有匹配行,则在关联的结果集行中,来自右表的所有选择列表列均为空值。

  • RIGHT JOIN 或 RIGHT OUTER JOIN

    右向外部联接是左向外部联接的反向联接。将返回右表的所有行。如果右表的某一行在左表中没有匹配行,则将为左表返回空值。

  • FULL JOIN 或 FULL OUTER JOIN

    完整外部联接将返回左表和右表中的所有行。当某一行在另一个表中没有匹配行时,另一个表的选择列表列将包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值。

  • 交叉联接

    交叉联接将返回左表中的所有行。左表中的每一行均与右表中的所有行组合。交叉联接也称作笛卡尔积。

join_condition 定义用于对每一对联接行进行求值的谓词(比较运算符或关系运算符)。

当 SQL Server 处理联接时,查询引擎会从 多种可行的方法中选择最有效的方法来处理联接。由于各种联接的实际执行过程会采用多种不同的优化,因此无法可靠地预测。

联接的例子可以参考 笔试题中的例子, SQL笔试50题(上)SQL笔试50题(下),在笔试题中有大量的内联接和左联接的例子。

4.10 UNION运算符

UNION 运算符可以将两个或多个 SELECT 语句的结果组合成一个结果集。

UNION 的结果集列名与 UNION 运算符中第一个 SELECT 语句的结果集中的列名相同。另一个 SELECT 语句的结果集列名将被忽略。

默认情况下,UNION 运算符将从结果集中删除重复的行。如果使用 ALL (即UNION ALL)关键字,那么结果中将包含所有行而不删除重复的行。

使用 UNION 运算符时需遵循下列准则:

  • 在用 UNION 运算符组合的语句中,所有选择列表中的表达式(如列名称、算术表达式、聚合函数等)数目必须相同。

  • 用 UNION 组合的结果集中的对应列或各个查询中所使用的任何部分列都必须具有相同的数据类型,并且可以在两种数据类型之间进行隐式数据转换,或者可以提供显式转换。例如,datetime 数据类型的列和 binary 数据类型的列之间的 UNION 运算符将不执行运算,直到进行了显式转换。但是,money 数据类型的列和 int 数据类型的列之间的 UNION 运算符将执行运算,因为它们可以进行隐式转换。

  • 用 UNION 运算符组合的各语句中对应结果集列的顺序必须相同,因为 UNION 运算符按照各个查询中给定的顺序一对一地比较各列。

  • 表中通过 UNION 运算所得到的列名称是从 UNION 语句中的第一个单独查询得到的。若要用新名称引用结果集中的某列(例如在 ORDER BY 子句中),必须按第一个 SELECT 语句中的方式引用该列

    1SELECT city AS Cities FROM stores_west2UNION 3SELECT city FROM stores_east4ORDER BY city
    

4.11 EXCEPT和INTERSECT半联接

使用 EXCEPT 和 INTERSECT 运算符可以比较两个或更多 SELECT 语句的结果并返回 非重复值

  • EXCEPT 运算符返回由 EXCEPT 运算符左侧的查询返回、而又不包含在右侧查询所返回的值中的所有非重复值。(左边结果与 左右两边结果的交集的差集 A-A∩B)

  • INTERSECT 返回由 INTERSECT 运算符左侧和右侧的查询都返回的所有非重复值。(两个查询结果的并集然后去重后的结果,A∪B)

使用 EXCEPT 或 INTERSECT 比较的结果集必须具有相同的结构。它们的列数必须相同,并且相应的结果集列的数据类型必须兼容。

INTERSECT 运算符优先于 EXCEPT

4.12 公用表表达式 WITH

公用表表达式 (CTE) 可以认为是在单个 SELECT、INSERT、UPDATE、DELETE 或 CREATE VIEW 语句的执行范围内定义的 临时结果集。CTE 与派生表类似,具体表现在 不存储为对象,并且 只在查询期间有效。与派生表的不同之处在于,CTE 可自引用,还 可在同一查询中引用多次

CTE 可用于:

  • 创建递归查询。

  • 在不需要常规使用视图时替换视图,也就是说,不必将定义存储在元数据中。

  • 启用按从标量嵌套 select 语句派生的列进行分组,或者按不确定性函数或有外部访问的函数进行分组。

  • 在同一语句中多次引用生成的表。

使用 CTE 可以获得提高可读性和轻松维护复杂查询的优点。查询可以分为单独块、简单块、逻辑生成块。之后,这些简单块可用于生成更复杂的临时 CTE,直到生成最终结果集。

可以在用户定义的例程(如函数、存储过程、触发器或视图)中定义 CTE。

CTE 由表示 CTE 的表达式名称、可选列列表和定义 CTE 的查询组成。定义 CTE 后,可以在 SELECT、INSERT、UPDATE 或 DELETE 语句中对其进行引用,就像引用表或视图一样。CTE 也可用于 CREATE VIEW 语句,作为定义 SELECT 语句的一部分。

CTE 的基本语法结构如下:

     1WITH expression_name [ ( column_name [,...n] ) ]
    
      
 
     
     
     
    
      
 
     
     
     2AS
    
      
 
     
     
     
    
      
 
     
     
     3( CTE_query_definition )
    
      
 
     
     
     
    
      
 
     
     
     4
    
      
 
     
     
     -- 运行 CTE 的语句
    
      
 
     
     
     
    
      
 
     
     
     5
    
      
 
     
     
     SELECT <column_list>
    
      
 
     
     
     
    
      
 
     
     
     6
    
      
 
     
     
     FROM expression_name;
    
      
 
     
     
     
   
     

    
    
    


    
    
    
    
      
 
     
     
      1
    
      
 
     
     
     -- 定义 CTE 查询别名和列名称
    
      
 
     
     
     
    
      
 
     
     
      2WITH Sales_CTE (SalesPersonID, SalesOrderID, SalesYear)
    
      
 
     
     
     
    
      
 
     
     
      3AS
    
      
 
     
     
     
    
      
 
     
     
      4
    
      
 
     
     
     -- 定义CTE查询的结果集
    
      
 
     
     
     
    
      
 
     
     
      5(
    
      
 
     
     
     
    
      
 
     
     
      6    
    
      
 
     
     
     SELECT SalesPersonID, SalesOrderID, 
    
      
 
     
     
     YEAR(OrderDate) 
    
      
 
     
     
     AS SalesYear
    
      
 
     
     
     
    
      
 
     
     
      7    
    
      
 
     
     
     FROM Sales.SalesOrderHeader
    
      
 
     
     
     
    
      
 
     
     
      8    
    
      
 
     
     
     WHERE SalesPersonID 
    
      
 
     
     
     IS 
    
      
 
     
     
     NOT 
    
      
 
     
     
     NULL
    
      
 
     
     
     
    
      
 
     
     
      9)
    
      
 
     
     
     
    
      
 
     
     
     10
    
      
 
     
     
     -- 使用CTE查询的结果进行进一步的查询
    
      
 
     
     
     
    
      
 
     
     
     11
    
      
 
     
     
     SELECT SalesPersonID, 
    
      
 
     
     
     COUNT(SalesOrderID) 
    
      
 
     
     
     AS TotalSales, SalesYear
    
      
 
     
     
     
    
      
 
     
     
     12
    
      
 
     
     
     FROM Sales_CTE
    
      
 
     
     
     
    
      
 
     
     
     13
    
      
 
     
     
     GROUP 
    
      
 
     
     
     BY SalesYear, SalesPersonID
    
      
 
     
     
     
    
      
 
     
     
     14
    
      
 
     
     
     ORDER 
    
      
 
     
     
     BY SalesPersonID, SalesYear;
   
     

    
    
    

本文项目地址:

https://github.com/firewang/sql50

(喜欢的话,Star一下)

阅读原文,或者访问该链接可以在线观看(该系列将更新至GitHub,并且托管到read the docs)

https://sql50.readthedocs.io/zh\_CN/latest/

参考网址:

PS:

1. 后台回复“线性代数”,“SQL” 等任一关键词获取资源链接

2. 后台回复“联系“, “投稿“, “加入“ 等任一关键词联系我们

3. 后台回复 “红包” 领取红包

SQL高级查询方法

零维领域,由内而外深入机器学习

dive into machine learning

微信号:零维领域

英文ID:lingweilingyu

SQL高级查询方法

本文分享自微信公众号 - 零维领域(lingweilingyu)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
1星期前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
2年前
SQL笔试50题(下)
正文共:4832字22图  预计阅读时间:13分钟前文推送1.MIT线性代数相关资源汇总(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzU5MTgxNTQyNA%3D%3D%26mid%3D224748
Wesley13 Wesley13
2年前
P2P技术揭秘.P2P网络技术原理与典型系统开发
Modular.Java(2009.06)\.Craig.Walls.文字版.pdf:http://www.t00y.com/file/59501950(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.t00y.com%2Ffile%2F59501950)\More.E
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Easter79 Easter79
2年前
Transact
正文共:2136字5图  预计阅读时间:6分钟前文推送1.SQLServer入门(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzU5MTgxNTQyNA%3D%3D%26mid%3D224748465
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
6个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这