说到联接与集合操作,其实它们就是对表的2种形式的操作。前者是表之间的水平操作,后者是表之间的垂直操作。
1.联接
联接分为2个时期.旧语法中,FROM子句后面表之间用逗号分开,没有JOIN ON 关键字.新语法才加入了JOIN关键字和ON子句.还引入了外部联接.
旧的语法也是支持外部联接的,不过形式有所不同。以前关于外部联接的语法是 *=和=*(左右联接),不推荐.
关于这方面的知识,可以参考JJ大大有篇写得很好的文章(
http://blog.csdn.net/jinjazz/archive/2009/08/10/4430354.aspx)
CROSS:
交叉连接可以用于对某个的表每条记录生产一定数量的副本.
举个例子: Customers 表 表示消费信息,Employees 表示员工信息 ,我现在要为消费者和员工的每个组合生成一个指定日期内每天的订单表
DECLARE @fromdate AS DATETIME, @todate AS DATETIME;
SET @fromdate = '20060101';
SET @todate = '20060131';
----2000
SELECT IDENTITY(int, 1, 1) AS OrderID,
CustomerID, EmployeeID,
DATEADD(day, n-1, @fromdate) AS OrderDate
INTO dbo.MyOrders
FROM dbo.Customers, dbo.Employees, dbo.Nums
WHERE n <= DATEDIFF(day, @fromdate, @todate) + 1;
select * from dbo.MyOrders
--2005
WITH Orders
AS
(
SELECT CustomerID, EmployeeID,
DATEADD(day, n-1, @fromdate) AS OrderDate
FROM dbo.Customers, dbo.Employees, dbo.Nums
WHERE n <= DATEDIFF(day, @fromdate, @todate) + 1
)
SELECT ROW_NUMBER() OVER(ORDER BY OrderDate) AS OrderID,
CustomerID, EmployeeID, OrderDate
FROM Orders;
利用Cross 可以提高行与聚合函数计算的效率
--计算表里的每行值 占总和的百分比以及与平均值的差值
create table #(a int)
insert # select 1
union all select 2
union all select 5
union all select 6
union all select 7
union all select 9
--方法1: 子查询
select A,
百分比=cast(A*1.0/(select SUM(A) from # ) as decimal(18,2)),
差值=A-(select AVG(1.*A) from #)
from #
--方法2:CROSS
select A,
百分比=cast(A*1.0/summ as decimal(18,2)),
差值=A-avgg
from #,(select SUM(A) as summ,AVG(A) as avgg from #) k
--方法3:over
select A,
百分比 =cast(A*1.0/ SUM(a) over() as decimal(18,2)),
差值=A- AVG(1.*A) over()
from #
/*
A 百分比 差值
----------- --------------------------------------- ---------------------------------------
1 0.03 -4.000000
2 0.07 -3.000000
5 0.17 0.000000
6 0.20 1.000000
7 0.23 2.000000
9 0.30 4.000000
*/
--通过执行计划 你可以发现 第一个是最慢的,最快的是第三个,比第二个还要快将近一倍
INNER:
这里先说个细节:其实用INNER JOIN ON 是个好习惯我觉得.如果你忘记在ON后面写条件,那么会出错.但是你忘在WHERE里面写条件,那分析器
只会把你的查询当做CROSS JOIN 。
OUTER:
分为三种:left.right.full 。注意他在逻辑步骤中的地位.是在ON筛选后,进行添加.
这个时候条件写where 后面和ON后面是有区别的.具体参考我之前写的 学习笔记4--逻辑查询
NATURAL JOIN :
..传说中的自然连接.隐含连接条件是表中具有相同列名的列 相等..未被支持现在...
其他链接如:自连接,不等连接,多连接,半连接等.
这里提下多连接:多个表的INNER JOIN 你无论怎么安排顺序都是一样的,不会影响查询结果的。执行计划甚至会出现不同的访问次序.
当多表链接设计到OUTER JOIN时候,可能不当的次序会出现逻辑错误.
create table #1 (A INT )
CREATE TABLE #2 (B int)
create table #3 (a int, b int)
insert #1 select
1 union all select 2 union all select 3
insert #2 select
2 union all select 3
insert #3 select
1,1 union all select 2,2 union all select 3,3
--目的:通过右连接 使得#1表的记录都存在 即使为NULL
select a.*
from #3 c right join #1 a on a.A= c.a join #2 b on c.b=b.B
/*
A
-----------
2
3
*/
select a.*
from #3 c join #2 b on c.b=b.B right join #1 a on a.A= c.a
/*
A
-----------
1
2
3
*/
select a.*
from #1 a left join (#2 b join #3 c on b.B=c.b) on a.A=c.a
/*
A
-----------
1
2
3
*/
-----这里就看出了多表连接涉及到外联接时候需要注意的地方 第一个结果并不是预期的结果 因为它进行了右连接后 又因为和第三个表链接
-----导致不符合条件的记录缺失.推荐使用第三种带括号的 条理会比较清晰 当然第二种也可以
关于连接的问题:
--问题描述:求每个月一年内的销售总额(这里假设每个月都有了)
MonthlyOrders 表如下:
/*
ordermonth numorders
----------------------- -----------
1996-07-01 00:00:00.000 22
1996-08-01 00:00:00.000 25
1996-09-01 00:00:00.000 23
1996-10-01 00:00:00.000 26
1996-11-01 00:00:00.000 25
1996-12-01 00:00:00.000 31
1997-01-01 00:00:00.000 33
1997-02-01 00:00:00.000 29
1997-03-01 00:00:00.000 30
1997-04-01 00:00:00.000 31
1997-05-01 00:00:00.000 32
1997-06-01 00:00:00.000 30
1997-07-01 00:00:00.000 33
1997-08-01 00:00:00.000 33
1997-09-01 00:00:00.000 37
1997-10-01 00:00:00.000 38
1997-11-01 00:00:00.000 34
1997-12-01 00:00:00.000 48
1998-01-01 00:00:00.000 55
1998-02-01 00:00:00.000 54
1998-03-01 00:00:00.000 73
1998-04-01 00:00:00.000 74
1998-05-01 00:00:00.000 14
*/
select b.ordermonth,
numorders=SUM(c.numorders)
from MonthlyOrders a
join MonthlyOrders b on DATEADD(M,11,b.ordermonth)=a.ordermonth
join MonthlyOrders c on c.ordermonth between b.ordermonth and a.ordermonth
group by b.ordermonth
/*
ordermonth numorders
----------------------- -----------
1996-07-01 00:00:00.000 337
1996-08-01 00:00:00.000 348
1996-09-01 00:00:00.000 356
1996-10-01 00:00:00.000 370
1996-11-01 00:00:00.000 382
1996-12-01 00:00:00.000 391
1997-01-01 00:00:00.000 408
1997-02-01 00:00:00.000 430
1997-03-01 00:00:00.000 455
1997-04-01 00:00:00.000 498
1997-05-01 00:00:00.000 541
1997-06-01 00:00:00.000 523
*/
--上面的问题就是采用了自连接的方法 连续聚合而成这些记录
2.集合操作
集合操作在2005中有
UNION--(返回2个输入表的行)
EXCEPT--(返回位于第一个输入表的行但是不属于第二个输入表的行)
INTERSECT--(返回2个输入表都存在的行)
PS:集合操作对NULL的判断是认为2NULL是相等的.
这里有一个问题;
也许你会觉得EXCEPT 可以用NOT EXISTS 代替. 其实有些情况下是不一样的,我举例说明:
create table test1 (a int ,b int)
create table test2 (c int, d int)
insert test1 select 1,2 union all select 1,null union all select 3,4
insert test2 select 1,2 union all select 1,null
-- except
select * from test1
except
select * from test2
/*
a b
----------- -----------
3 4
*/
-- not exists
select * from test1
where not exists(select * from test2 where a=c and b=d)
/*
a b
----------- -----------
1 NULL
3 4
*/
----------从上面可以看出 当筛选表里的记录和被筛选表的相同记录里含有NULL值时候 你用NOT EXISTS 它永远认为这2个是不相等的.
这里同样的问题会出现在INTERSECT.
这三个集合操作的优先级最高为:INTERSECT ,之后就是按从上到下出现的次序
再说最后一个注意点:
除了排序之为的逻辑处理,如联接 筛选 分组 TOP等都不允许直接用在集合结果集上 ,如:
create table #a (a int, b int )
create table #b (c int, d int )
insert #a select
1,2 union all select 3,9 union all select 4,8
insert #b select
4,2 union all select 5,9 union all select 3,2 union all select 4,9
--这里直接作于#A表 而不是整个结果集
select top 1
* from #a
union all
select * from #b
--列名 'A' 无效。
select * from #a
union all
select * from #b
group by A
-----我们可以通过将结果集包装成一个派生表 或者CTE进行操作.
小技巧:这时候如果你想对2输入表分别进行排序,比如上面的#a的a列升序,#b的d列降序,可以这样
select a,b
from (
select *,flag=1 from #a
union all
select *,2 from #b
) l
order by case when flag=1 then a end ,case when flag=2 then b end desc
/*
a b
----------- -----------
5 9
4 9
4 2
3 2
1 2
3 9
4 8
*/
相关推荐
在SQL Server 2017的学习中,我们首先需要了解SQL Server的基础操作,这包括了基本的增删改查操作,比如INSERT、DELETE、UPDATE和SELECT。这些是数据库管理中最常用的操作,用于处理数据的存取和修改。 接着,我们...
《SQL Server精华 (CHM)_sqlserver_SQLServer笔记_》是一部综合性的SQL Server学习资源,旨在帮助用户深入理解和掌握Microsoft SQL Server数据库管理系统的核心概念、功能和最佳实践。这部笔记涵盖了一系列关键知识...
本笔记主要针对SQL Server的语法进行整理,旨在帮助初学者快速掌握基础概念和常用操作。 一、SQL简介 SQL(Structured Query Language)是用于管理和处理关系数据库的标准语言。在SQL Server中,你可以创建、更新、...
SQL(Structured Query Language)是用于管理和操作数据库的强大工具,它被广泛应用于各种关系型数据库管理系统,如MySQL、Oracle、SQL Server、PostgreSQL等。这份"SQL学习笔记"涵盖了SQL的基础概念、语法以及高级...
《高效SQL学习笔记》 SQL,全称Structured Query Language,即结构化查询语言,是用于管理关系数据库的标准语言。高效地掌握SQL对于任何IT从业者,尤其是数据分析师、数据库管理员和开发人员来说,都是至关重要的...
SQL(Structured Query ...以上只是SQL学习笔记中的部分要点,实际应用中还需要结合具体数据库系统(如MySQL、Oracle、SQL Server等)的特点和最佳实践。通过持续学习和实践,才能真正精通SQL,成为数据管理的高手。
标题“20170909学习sql笔记”表明这是一个关于SQL学习的资料,可能包含了一天的学习记录或者一个教程的集合。SQL,全称Structured Query Language,是用于管理和处理关系数据库的标准语言。这个标题暗示我们将探讨...
- 学习更高级的SQL语句,如子查询、联接操作、集合函数、窗口函数等,增强数据分析能力。 - 存储过程和触发器允许预编译和封装复杂的业务逻辑,提高性能和安全性。 7. **第七章 理解安全和网络连接** - 数据库...
【SQL ADV的笔记 老师的】是关于SQL Server高级编程的个人学习记录,这份笔记主要聚焦在提升SQL Server数据库的管理和开发技巧。笔记的内容可能涵盖了诸多方面,包括但不限于高级查询技术、存储过程、触发器、索引...
最后,`SQL笔记一.doc`可能包含了更详细的学习内容,如WHERE子句的使用、条件运算符、通配符搜索、集合操作以及视图和存储过程的创建等。通过阅读这份笔记,你将能够系统地掌握SQL的基本语法,并逐步提升到更高级的...
【Java学习笔记全套】是针对Java编程语言的一套全面学习资料,涵盖了Unix操作系统基础、SQL数据库操作、核心Java编程、Hibernate持久化框架、以及Spring框架等多个关键知识点。这些笔记旨在帮助初学者系统地掌握Java...
SQL-Summary.rar_sql这个压缩包文件,显然是一个关于SQL学习的总结,尤其是针对SQL Server数据库管理系统的学习笔记。以下是根据标题、描述和文件名整理出的SQL相关知识点详解: 一、SQL基础概念 SQL Server是由...
这篇SQL学习笔记涵盖了从基础到进阶的多个方面,包括数据库操作、表管理、查询、索引、视图、存储过程和触发器等核心概念。 首先,让我们从第一节的库操作及基本查询开始。在SQL中,`CREATE TABLE`语句用于创建新的...
以上只是SQL语言的基本概念和常用操作,实际应用中还包括更复杂的子查询、联接、集合操作、事务控制、存储过程等功能。掌握好SQL,对于数据分析、数据库管理等工作至关重要。通过学习和实践,可以灵活运用SQL解决...
《SQL 读书笔记》PDF版是一份全面介绍SQL语言的宝贵资源,适合对数据库操作有基础了解并希望进一步提升技能的读者。SQL,全称Structured Query Language,即结构化查询语言,是用于管理关系数据库的标准语言。这份...
7. **SQL与编程语言的交互**: - 如Python的pandas库、Java的JDBC、PHP的PDO等,通过API与SQL数据库进行交互。 在"SQL上课笔记"中,可能会详细讲解这些概念,并通过实例代码进行实践,帮助学习者理解和掌握SQL语句...
Oracle数据库是世界上最流行的数据库管理系统之一,对于复杂...在实际工作中,可能还需要结合其他功能,如联接(JOINs)、聚合函数(GROUP BY)、集合操作(UNION, INTERSECT, EXCEPT)等,来处理更复杂的业务需求。
"清晰的技术资料学习笔记"这个压缩包包含了一系列关于SQL、ORACLE、JAVA、JSF、EBJ和ECLIPSE的学习资源,这些都是信息技术行业的核心技术和工具。下面,我们将深入探讨这些技术及其重要性。 首先,SQL(Structured ...
SQL存储过程是数据库管理系统中一组为了完成特定功能的SQL语句集合,经编译后存储在数据库中,用户可以通过调用这个预编译的程序来执行一系列操作,它提高了数据库应用的性能和效率。在SQL中,存储过程可以接受参数...