SQL Server-表表达式基础回顾(二十四)
前言
从这一节开始我们开始进入表表达式章节的学习,Microsoft SQL Server支持4种类型的表表达式:派生表、公用表表达式(CTE)、视图、内嵌表值函数(TVF)。简短的内容,深入的理解,Always to review the basics。
表表达式
表表达式没有任何的物理实例化,在查询表表达式时它们是虚拟的,内部查询是非嵌套的,换句话说,外部查询和内部查询直接合并到一个底层对象的查询中,使用表表达式的好处通常与代码的逻辑方面有关,而与代码的性能无关-摘抄自SQL Server 2012基础教程。在使用表表达式时我们必须满足以下3点要求,否则将会报错。我们下面来简短介绍下表表达式的4中类型。
(1)无法保证顺序。
(2)所有列都必须具有名称。
(3)所有列名都必须是唯一的。
派生表
派生表(也称为子查询表)是在外部查询的FROM子句中定义的,它们存在的范围是外部查询。一旦外部查询完成后,派生表就消失了。我们看一个简单的派生表的例子。
USE TSQL2012
GO SELECT *
FROM(
SELECT * FROM Sales.Customers WHERE country = N'USA') AS USACusts;
我们再来具体看下上述已经明确说过表表达式查询满足的条件,接下来我们进行如下查询:
USE TSQL2012
GO SELECT *
FROM(
SELECT * FROM Sales.Customers WHERE country = N'USA' ORDER BY custid) AS USACusts;
当我们在子查询中添加ORDER BY之后就出现如上错误,这也就是说的上述表表达式要求的第一点,表表达式作为关系表,因为关系在源于集合理论,所以无法保证输出数据的顺序,看到SQL Server 2012基础教程中是这么说,我也就这么理解,至于真正原因还是无法理解,反正在表表达式中千万不要进行ORDER BY。关于要求的第二点和第三点就不用多说,比如上述此时对表不起别名肯定会报错,还有当对多个表进行联接时,表中列字段肯定有一样的,为保证唯一,我们必须为列名起别名来解决不唯一的问题。使用表表达式的好处之一就是在外部查询的任何子句中,可以引用内部查询的SELECT子句中分配的列别名,如此这样可以帮助我们绕开在SELECT子句逻辑处理之前的查询子句中(如WHERE、GROUP BY)无法引用SELECT子句中分配的列别名的实际问题,到底是什么意思呢,我们知道进行常规的查询时,此时如WHERE、GROUP BY是在SELECT之前进行,所以会导致我们对SELECT中的列通过WHERE、GROUP BY无法进行引用,我们来看一下以下例子。
USE TSQL2012
GO SELECT YEAR(orderdate) AS orderyear, COUNT(DISTINCT custid) AS custids
FROM Sales.Orders
GROUP BY orderyear
如上此时我们对SELECT中的orderyear通过GROUP BY来进行分组,但是GROUP BY操作是在SELECT之前所以会导致出现如下错误。
要解决这个问题我们可以通过表表达式中的派生表来查询
USE TSQL2012
GO SELECT orderyear, COUNT(DISTINCT custid) AS custids
FROM (SELECT YEAR(orderdate) AS orderyear, custid FROM Sales.Orders) AS SO
GROUP BY orderyear
对于派生表可以引用参数来用于存储过程或函数等变量或输入参数,同时派生表可以进行嵌套,如下:
USE TSQL2012
GO SELECT orderyear, numcusts
FROM (
SELECT orderyear, COUNT(DISTINCT custid) AS numcusts
FROM (
SELECT YEAR(orderdate) AS orderyear, custid
FROM Sales.Orders) AS D1
GROUP BY orderyear)AS D2
WHERE numcusts > ;
当有多个表时这样进行嵌套时此时代码会越来越复杂,冗长的代码不利于维护容易导致出错,同时也降低了代码的可读性。此时我们可以用表表达式的第2种形式CTE。
公用表表达式(CTE)
CTE通过WITH语句定义,具有如下常用形式。
WITH <CTE_NAME>[(<target_column_list>)]
AS
(
<inner_query_defining_CTE>
)
<outer_query_against_CTE>
我们来看一个关于CTE简单的例子
USE TSQL2012
GO WITH USACusts AS
(
SELECT custid, companyname
FROM Sales.Customers
WHERE country = N'USA'
)
SELECT * FROM USACusts
和派生表相同,一旦外部查询完成后,CTE马上就会消失。在CTE中我们同样可以使用参数,如下:
USE TSQL2012
GO DECLARE @empid AS INT = ; WITH C AS
(
SELECT YEAR(orderdate) AS orderyear, custid
FROM Sales.Orders
WHERE empid = @empid
)
SELECT orderyear, COUNT(DISTINCT custid) AS numcusts
FROM C
GROUP BY orderyear
我们同样可以类似实现派生表一样的嵌套,如下:
USE TSQL2012
GO WITH C1 AS
(
SELECT YEAR(orderdate) AS orderyear, custid
FROM Sales.Orders
),C2 AS
(
SELECT orderyear,COUNT(DISTINCT custid) AS numcusts
FROM C1
GROUP BY orderyear
) SELECT orderyear, numcusts
FROM C2
WHERE numcusts >
这里我们利用CTE实现了和派生表同样的结果,派生表和CTE其实只是在语义上有差异,但是相对于派生表最主要的优势在于不需要像派生表那样需要多重嵌套,而CTE只要定义了就无需嵌套,每个CTE在代码中以模块化的方式分别出现。这中模块化的方式和嵌套派生表方式相比,大大提高了代码的可读性和可维护性,若有多个表需要嵌套利用CTE来实现更加清爽并有助于代码的清晰性。而对于派生表的另外一个优势在于就外部查询的FROM子句而言,CTE在之前就已经存在,因此可以引用同一个CTE的多个实例。
视图(VIEW)
视图和内嵌表值函数是两种可以重复使用的表表达式类型,其定义被存储为数据库对象,创建之后,这些对象是数据库的永久部分,并且只有在显式删除它们时才能从数据库中删除。我们看下如何创建视图并使用视图。
USE TSQL2012
GO IF OBJECT_ID('Sales.USACusts') IS NOT NULL
DROP VIEW Sales.USACusts;
GO CREATE VIEW Sales.USACusts
AS SELECT custid, companyname, contactname, contacttitle, [address]
FROM Sales.Customers
WHERE country = N'USA' GO
创建视图完之后视图对象就在数据库中已经存在,此时我们再来查询视图
USE TSQL2012
GO SELECT *
FROM Sales.USACusts
内嵌表值函数(TVF)
内嵌表值函数是支持输入参数的可重复使用的表表达式。除了支持输入参数之外的其他所有方面都和视图类似。我们来看下怎么创建内嵌表值函数。
USE TSQL2012
GO IF OBJECT_ID('dbo.GetCustOrders') IS NOT NULL
DROP FUNCTION dbo.GetCustOrders;
GO CREATE FUNCTION dbo.GetCustOrders(@cid AS INT) RETURNS TABLE
AS RETURN
SELECT orderid, custid, empid, orderdate, requireddate, shippeddate, shipperid, shipcity,
shipaddress, shipregion, freight
FROM Sales.Orders
WHERE custid = @cid
GO
此时我们创建完毕TVF,我们接下来来调用自定义的TVF
USE TSQL2012
GO SELECT orderid, custid
FROM dbo.GetCustOrders() AS O;
上述我们为表表达式提供了一个别名,虽然不是必须的,但是推荐这样做,因为它使代码更具有可读性和少出错误。本节我们对表表达式的4种方式作了一下回顾,同样我们来为这4种形式的表表达式来做个结论。
(1)表表达式可以简化代码,提高代码的可维护性和封装查询逻辑。
(2)当需要使用表表达式并且不打算重复使用其定义时,可以使用派生表或CTE,而CTE对派生表具有更多优势不需要像派生表那样嵌套CTE,使用CTE使代码更加模块化和便于维护,此外,还可以引用同一个CTE的多个实例,这一点是派生表无法实现的。
(3)当需要使用表表达式并且需要定义可重复使用的表表达式时,可以使用视图或内嵌表值函数,当不需要支持输入参数时,可以使用视图,否则,应当使用内嵌表值函数(TVF)。
总结
本节回顾了表表达式的基础内容,下节我们详细讲讲使用视图的限制,简短的内容,深入的理解,我们下节再会。
SQL Server-表表达式基础回顾(二十四)的更多相关文章
- SQL Server 表表达式--派生表、公用表表达式(CTE)、视图和内联表值函数
概述 表表达式是一种命名的查询表达式,代表一个有效地关系表.可以像其他表一样,在数据处理中使用表表达式. SQL Server支持四种类型的表表达式:派生表,公用表表达式,视图和内联表值函数. 为什么 ...
- Sql server 表表达式
1.表表达式概述 (1)表表达式(table expression) 是一个命名的查询表达式.代表一个有效的关系表 (2)在DML 中,使用表表达式和使用其他表非常类似 (3)sqlserver 支持 ...
- Py修行路 python基础 (二十四)socket编程
socket编程 一.客户端/服务端架构 客户端/服务端架构 即C/S架构,包括:1.硬件C/S架构,2.软件C/S架构. 互联网中处处都是C/S架构,学习socket 就是为了完成C/S架构的开发. ...
- 夯实Java基础(二十四)——Java8新特征之Optional类
1.概述 对于Java程序员来说,到目前为止出现次数最多的应该是NullpointException,它是导致Java应用程序失败的最常见原因.之前处理空指针我们必须先通过条件先去判断,然后再确认是否 ...
- JavaEE基础(二十四)/多线程
1.多线程(多线程的引入) 1.什么是线程 线程是程序执行的一条路径, 一个进程中可以包含多条线程 多线程并发执行可以提高程序的效率, 可以同时完成多项工作 2.多线程的应用场景 红蜘蛛同时共享屏幕给 ...
- Java基础(二十四)Java IO(1)输入/输出流
在Java API中,可以从其中读入一个字节序列的对象称作输入流,而可以向其中写入一个字节序列的对象称为输出流. 输入流的指向称为源,程序从指向源的输入流中读取数据. 输出流的指向是字节要去的目的地, ...
- <Android 基础(二十四)> EditText
介绍 A text field allows the user to type text into your app. It can be either single line or multi-li ...
- python编程基础之二十四
函数: def 函数名([参数1],[参数2],[参数3], ... ,[参数n]): 函数体代码 函数名命名规则:同标识符命名相同,但是多了一点,不要和系统函数重名,其实所有命名都是一样只要符合标识 ...
- koa 基础(二十四)封装 DB 库 --- 新增数据、更新数据、删除数据
1.根目录/module/db.js /** * DB库 */ var MongoClient = require('mongodb').MongoClient; var Config = requi ...
- 机器学习实战基础(二十四):sklearn中的降维算法PCA和SVD(五) PCA与SVD 之 重要接口inverse_transform
重要接口inverse_transform 在上周的特征工程课中,我们学到了神奇的接口inverse_transform,可以将我们归一化,标准化,甚至做过哑变量的特征矩阵还原回原始数据中的特征矩阵 ...
随机推荐
- JAVA回调机制(CallBack)详解
序言 最近学习java,接触到了回调机制(CallBack).初识时感觉比较混乱,而且在网上搜索到的相关的讲解,要么一言带过,要么说的比较单纯的像是给CallBack做了一个定义.当然了,我在理解了回 ...
- ABP文档 - 本地化
文档目录 本节内容: 简介 应用语言 本地化源 XML文件 注册XML本地化源 JSOn文件 注册JSON本地化源 资源文件 自定义源 获取一个本地文本 在服务端 在MVc控制器里 在MVC视图里 在 ...
- Spring框架概述
Spring是最流行的Java企业级应用开发框架,全球数以百万的开发者在使用Spring框架创建高性能.易测试.可重用的代码. Spring框架的核心特性可以应用于任何Java应用,但扩展的JavaE ...
- .NET Core的日志[3]:将日志写入Debug窗口
定义在NuGet包"Microsoft.Extensions.Logging.Debug"中的DebugLogger会直接调用Debug的WriteLine方法来写入分发给它的日志 ...
- ASP.NET 5 RC1 升级 ASP.NET Core 1.0 RC2 记录
升级文档: Migrating from DNX to .NET Core Migrating from ASP.NET 5 RC1 to ASP.NET Core 1.0 RC2 Migrating ...
- Android Studio快捷键
一.android studio 默认快捷键 刚开始接触一款开发软件,想必很想了解它的快捷方式,这会对你的编程起到很好的帮助,提高工作效率,接下来给你介绍下Android Studio一些常用的快 ...
- git
CMD命令:git initgit add . [添加文件至暂存区]git commit -m '描述性语句 随意写即可'git branch gh-pages [创建仓库分支]git checkou ...
- 如何编译Zookeeper源码
1. 安装Ant Ant下载地址:http://ant.apache.org/bindownload.cgi 解压即可. 2. 下载Zookeeper源码包 https://github.com/ap ...
- 希尔排序(java)
时间复杂度为O( n^(3/2) )不是一个稳定的排序算法 如何看一个算法是否稳定:{("scala",12),("python",34),("c++ ...
- C#移动跨平台开发(2)Xamarin移动跨平台解决方案是如何工作的?
概述 上一篇 C#移动跨平台开发(1)环境准备发布之后不久,无独有偶,微软宣布了开放.NET框架源代码并且会为Windows.Mac和Linux开发一个核心运行时(Core CLR),这也是开源的!I ...