联接查询

sql server 2008支持四种表运算符----JOIN,APPLY,PIVOT,UNPIVOT.

JOIN表运算符是ANSI标准,而APPLY,PIVOT,UNPIVOT是T-SQL对标准的扩展

JOIN表运算符,联接有三种基本类型:交叉联接,内联接和外联接.

交叉联接只有一个步骤:笛卡尔积;内联接有两个步骤:笛卡尔积和过滤;外联接有三个步骤:笛卡尔积,过滤,添加外部行.

(逻辑查询处理和物理查询处理的不同!)

3.1 交叉联接 (cross join)

最简单的联接,只实现了一个逻辑查询步骤(笛卡尔积)

3.1.1 ANSI SQL-92

一般标准都是用 ANSI-SQL 92的

-- ANSI SQL-92
USE TSQLFundamentals2008; SELECT C.custid, E.empid
FROM Sales.Customers AS C
CROSS JOIN HR.Employees AS E;

3.1.2 ANSI SQL-89

-- ANSI SQL-89
SELECT C.custid, E.empid
FROM Sales.Customers AS C, HR.Employees AS E;

3.1.3 自交叉联接

对同一个表的多个实例也可以进行联接,这种功能就是所谓的自联接,所有基本联接类型(交叉联接,内联接,以及外联接)都是支持自联接.

-- Self Cross-Join
SELECT
E1.empid, E1.firstname, E1.lastname,
E2.empid, E2.firstname, E2.lastname
FROM HR.Employees AS E1
CROSS JOIN HR.Employees AS E2;
GO
--在自联接中,必须为表起别名.如果不为表指定别名,联接结果中的列名就会有歧义.
--自联接的笛卡尔积,与不是自联接的笛卡尔积不同!

3.1.4 生成数字表

自交叉联接的运用.

-- All numbers from  - 

-- Auxiliary table of digits
USE tempdb;
IF OBJECT_ID('dbo.Digits', 'U') IS NOT NULL DROP TABLE dbo.Digits;
CREATE TABLE dbo.Digits(digit INT NOT NULL PRIMARY KEY); --2008特有的
INSERT INTO dbo.Digits(digit)
VALUES (),(),(),(),(),(),(),(),(),(); /*
Note:
Above INSERT syntax is new in Microsoft SQL Server 2008.
In earlier versions use: INSERT INTO dbo.Digits(digit) VALUES(0);
INSERT INTO dbo.Digits(digit) VALUES(1);
INSERT INTO dbo.Digits(digit) VALUES(2);
INSERT INTO dbo.Digits(digit) VALUES(3);
INSERT INTO dbo.Digits(digit) VALUES(4);
INSERT INTO dbo.Digits(digit) VALUES(5);
INSERT INTO dbo.Digits(digit) VALUES(6);
INSERT INTO dbo.Digits(digit) VALUES(7);
INSERT INTO dbo.Digits(digit) VALUES(8);
INSERT INTO dbo.Digits(digit) VALUES(9);
*/ SELECT digit FROM dbo.Digits;
GO -- All numbers from -
SELECT D3.digit * + D2.digit * + D1.digit + AS n
FROM dbo.Digits AS D1
CROSS JOIN dbo.Digits AS D2
CROSS JOIN dbo.Digits AS D3
ORDER BY n;

3.2 内联接

内联接要应用的两个逻辑查询处理步骤:首先像交叉联接一样,对两个输入表进行笛卡尔积运算;然后根据用户指定的谓词对结果进行过滤.

3.2.1 ANSI-SQL 92

ANSI-SQL 92:须在两个表名之间指定INNER JOIN关键字.

INNER关键字是可选的,因为内联接是默认的联接方式,所以可以只单独指定JOIN关键字.

用于对行进行过滤的谓词是在一个称为ON子句的特别设计的语句中指定的,该谓词也称为联接条件.

---------------------------------------------------------------------
-- INNER Joins
--------------------------------------------------------------------- -- ANSI SQL-92
USE TSQLFundamentals2008; SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E
JOIN Sales.Orders AS O
ON E.empid = O.empid;
--以上,在关系代数的基础上来考虑内联接,联接运算首先对两个表求笛卡尔积,然后根据条件E.empid = O.empid,对行进行过滤.
--与WHERE和HAVING子句类似,ON子句同样也只返回令谓词结果为TRUE的行,而不会返回令谓词计算结果为FALSE或UNKNOW的行.

3.2.2 ANSI-SQL 89

-- ANSI SQL-89
SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E, Sales.Orders AS O
WHERE E.empid = O.empid;
GO
--没有ON子句,不推荐使用!

3.2.3 更安全的内联接

-- Inner Join Safety
-- 采用ANSI-SQL 92的语法
SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS El
JOIN Sales.Orders AS O;
GO SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E, Sales.Orders AS O;
GO

3.3 特殊的联接实例

特殊的联接实例包括:组合联接,不等联接,以及多表联接

3.3.1 组合联接

组合联接就是联接条件设计联接两边的多个列的查询.当需要根据主键-外键关系来联接两个表,而且主外键关系是组合的(即,关系基于多个列)时,通常就要使用组合联接.

例如:

SELECT * FROM TABLE1  AS  T1 INNER JOIN TABLE2 AS T2 ON T1.COL1= T2.COL1 AND T1.COL2 = T2.COL2

---------------------------------------------------------------------
-- Composite Joins
--------------------------------------------------------------------- -- Audit table for updates against OrderDetails
USE TSQLFundamentals2008;
IF OBJECT_ID('Sales.OrderDetailsAudit', 'U') IS NOT NULL
DROP TABLE Sales.OrderDetailsAudit;
CREATE TABLE Sales.OrderDetailsAudit
(
lsn INT NOT NULL IDENTITY,
orderid INT NOT NULL,
productid INT NOT NULL,
dt DATETIME NOT NULL,
loginname sysname NOT NULL,
columnname sysname NOT NULL,
oldval SQL_VARIANT,
newval SQL_VARIANT,
CONSTRAINT PK_OrderDetailsAudit PRIMARY KEY(lsn),
CONSTRAINT FK_OrderDetailsAudit_OrderDetails
FOREIGN KEY(orderid, productid)
REFERENCES Sales.OrderDetails(orderid, productid)
); SELECT OD.orderid, OD.productid, OD.qty,
ODA.dt, ODA.loginname, ODA.oldval, ODA.newval
FROM Sales.OrderDetails AS OD
JOIN Sales.OrderDetailsAudit AS ODA
ON OD.orderid = ODA.orderid
AND OD.productid = ODA.productid
WHERE ODA.columnname = N'qty';

3.3.2 不等联接

如果联接条件只包含等号运算符,要么这样的联接叫做等值联接.如果联接条件包含除等号以外的其他运算符,那么这样的联接叫做不等联接.

---------------------------------------------------------------------
-- Non-Equi Joins
--------------------------------------------------------------------- -- Unique pairs of employees
SELECT
E1.empid, E1.firstname, E1.lastname,
E2.empid, E2.firstname, E2.lastname
FROM HR.Employees AS E1
JOIN HR.Employees AS E2
ON E1.empid < E2.empid;
--ON子句中指定的判断条件,目的是为了生存雇员之间的唯一配对组合.
--以上,使用内联接,并在联接条件中指定左边的键值要小于右边的键值!

3.3.3 多表联接

一个联接表运算符只对两个表进行操作,而一条查询语句可以包含多个联接.

当FROM子句中包含多个表运算符时,表运算符在逻辑上是按从左到右的顺序处理的.也就是,第一个表运算符的结果表将作为第二个表运算符的输入,第二个表运算符的结果将作为第三个表运算符左边的输入,以此类推!

---------------------------------------------------------------------
-- Multi-Table Joins
--------------------------------------------------------------------- SELECT
C.custid, C.companyname, O.orderid,
OD.productid, OD.qty
FROM Sales.Customers AS C
JOIN Sales.Orders AS O
ON C.custid = O.custid
JOIN Sales.OrderDetails AS OD
ON O.orderid = OD.orderid;

3.4 外联接

3.4.1 外联接基础

外联接是在ANSI-SQL 92中才被引入的,外联接的逻辑步骤有:1.笛卡尔积;2.ON 过滤器;3.添加外部行

在外联接中,要把一个表标记为"保留的"表;在表名之间使用关键字LEFT OUTER JOIN,RIGHT OUTER JOIN,以及FULL OUTER JOIN,其中OUTER关键字是可选的.

LEFT关键字表示左边表的行是保留的,RIGHT关键字表示右边表的行是保留的,而FULL关键字则表示左右两边表的行都是保留的.外联接的第三个逻辑查询处理步骤就是要识别保留表中按照ON条件在另一个表找不到与之匹配的那些行,再把这些行添加到联接的前两个步骤生成的结果表中;对于来自联接的非保留表的那些列,追加的外部行中额这些列则用NULL作为占位符.

-- Customers and their orders, including customers with no orders
SELECT C.custid, C.companyname, O.orderid
FROM Sales.Customers AS C
LEFT OUTER JOIN Sales.Orders AS O
ON C.custid = O.custid;

从外联接保留表的角度来看,可以认为外联接结果中的数据行包括两种:内部行和外部行.内部行是指按照ON子句中的条件能在联接的另一边找到匹配的那些行;而外部行则是指找不到匹配的那些行.内联接只返回内部行,而外联接同时返回内部行和外部行.

外联接中,ON子句中的过滤条件不是最终的.ON子句中的条件并不能最终决定保留表中部分行是否会在结果中出现,而只是判断是否能够匹配另一边表中的某些行.所以,当需要表达一个非最终的条件时,就在ON子句中指定联接条件.当在生成外部行之后,要应用过滤器,而且希望过滤条件是最终的,就应该在WHERE子句中指定.,对于行的过滤来说,WHERE子句是最终的.

-- Customers with no orders
SELECT C.custid, C.companyname
FROM Sales.Customers AS C
LEFT OUTER JOIN Sales.Orders AS O
ON C.custid = O.custid
WHERE O.orderid IS NULL;
GO
--以上,可以返回外部行,对于外部行,其来自联接的非保留表的列都标记为NULL,所以可以只筛选联接的非保留表的列值之一为NULL的那些行
--选择非保留表中的哪个列作为过滤器也很重要.应该选择只在外部行才取值为NULL,而在其他行取值不为NULL(例如,NULL值不能来自基本表)的某个列.可以考虑三种情况----主键列,联接列,以及定义为NOT NULL的列.\
--当查找NULL值时,应该使用 IS NULL 运算符.

3.4.2 外联接的高级主题

1.包含缺少值的数据

2.对外联接中非保留表的列值进行过滤

3.在多表联接中使用外联接

4.随外联接一起使用COUNT聚合函数

111

第三章 联接查询 T-SQL语言基础的更多相关文章

  1. Java Persistence with MyBatis 3(中文版) 第三章 使用XML配置SQL映射器

    关系型数据库和SQL是经受时间考验和验证的数据存储机制.和其他的ORM 框架如Hibernate不同,MyBatis鼓励开发者可以直接使用数据库,而不是将其对开发者隐藏,因为这样可以充分发挥数据库服务 ...

  2. SQL语言基础和数据库操作

    Sql语言基础: 核心思想:我们自己构造一段查询的代码,然后添加到语句后,从而得到想要的某些数据. Mysql是一种开源数据库 APP Serv:Apache+php+mysql,相当于phpstud ...

  3. PL/SQL语言基础

    PL/SQL语言基础 进行PL/SQL编程前,要打开输出set serveroutput on 1.创建一个匿名PL/SQL块,将下列字符输出到屏幕:"My PL/SQL Block Wor ...

  4. 学习笔记:oracle学习三:SQL语言基础之sql语言简介、用户模式

    目录 1.sql语言简介 1.1 sql语言特点 1.2 sql语言分类 1.3 sql语言的编写规则 2.用户模式 2.1 模式与模式对象 2.2 实例模式scott 本系列是作为学习笔记,用于记录 ...

  5. orcale 之 SQL 语言基础

    SQL 全称是结构化查询语句(Structure Query Language),是数据库操作的国际化语言,对所有的数据库产品都要支持. SQL 语言的分类 我们按照其功能可以大致分为四类: 数据定义 ...

  6. 浅谈PL/SQL语言基础

    在前面的学习中,我们大部分接触的都是SQL语言,但是,在实现复杂操作的时候,SQL语言就无能为力了,这时候就需要引入新的语言,PL/SQL语言就是对SQL语言的扩展,可以实现存储过程,函数等的创建.下 ...

  7. SQL语言基础-基本概念

    SQL:IBM的圣约瑟(SanJose),SEQUEL 2(也就是现在的SQL语言) 1979.Oracle首先提出提供了商用的SQL语言 1986.10美国ANSI采用SQL作为关系数据库管理系统的 ...

  8. SQL语言基础

    主要学习链接1 http://www.cnblogs.com/anding/p/5281558.html 搜索学习链接2 http://www.cnblogs.com/libingql/p/41342 ...

  9. 学习笔记:oracle学习三:SQL语言基础之检索数据:简单查询、筛选查询

    目录 1. 检索数据 1.1 简单查询 1.1.1 检索所有列 1.1.2 检索指定的列 1.1.3 查询日期列 1.1.4 带有表达式的select语句 1.1.5 为列指定别名 1.1.6 显示不 ...

随机推荐

  1. 在RestController中获取各种信息的方法

    内容 获取方法 URL中路径的一部分 首先需要在RequestMapping做映射, 之后在方法中可以通过注解使用映射的变量@GetMapping("/{id}")public S ...

  2. 20191114-4 Beta发布用户使用报告

    20191114-4 Beta发布用户使用报告 此作业要求参见:https://edu.cnblogs.com/campus/nenu/2019fall/homework/10007 组名:胜利点 组 ...

  3. window环境下 恢复odoo数据库备份文件时产生的 Database restore error: Command `psql` not found.

    1,首先先查看 PostgreSQL 是否安装在C盘,如果安装在其他盘 则需要配置环境变量 配置完成后重启服务就可以了 2, 如果还不行,只需在odoo.conf中添加一个配置设置.也就是在odoo项 ...

  4. python调用系统命令的方法

    1.os模块 (1)system()方法 这个方法是直接调用标准C的system() 函数,在一个子终端运行系统命令 (2)poen()方法 这个方法执行命令后通过一个管道文件将结果返回 3.subp ...

  5. Oracle 必要的后台进程

    Oracle 必要的后台进程 Table of Contents 1. 简述 2. 必要进程 2.1. 默认启动后台进程 2.2. 哪些进程不能杀 1 简述 oralce 每次大的版本变更,后台进程都 ...

  6. C#调用SQL中存储过程并用DataGridView显示执行结果

    //连接数据库 SqlConnection con = new SqlConnection("server=服务器名称;database=数据库名称;user id=登录名;pwd=登录密码 ...

  7. OpenID简介

    OpenID 是一个以用户为中心的数字身份识别框架,它具有开放.分散性.OpenID 的创建基于这样一个概念:我们可以通过 URI (又叫 URL 或网站地址)来认证一个网站的唯一身份,同理,我们也可 ...

  8. ubuntu下终端代理方法

    起因 正常使用shadowsocks后只能在浏览器中访问google,而终端中却无法使用.   解决方法 ProxyChains是一个终端代理方案,使用比较简单. 在源里有这个软件,直接安装 sudo ...

  9. NativeContainer

    安全系统复制数据的过程的缺点是它还隔离了每个副本中作业的结果.要克服此限制,您需要将结果存储在一种名为NativeContainer的共享内存中. 什么是NativeContainer? A Nati ...

  10. linux中为什么删除文件比创建文件要快,读取文件和删除文件的过程是什么?

    一.为什么删除文件比创建文件要快? 因为删除文件只是将bitmap位图表中将文件所占据的inode 和dacablock的使用状态从1变成0,相当于释放了这些快的使用权. 二.读取文件和删除文件的过程 ...