SQL进阶系列之2自连接
写在前面
一般地,SQL的连接运算根据其特征的不同,有着不同的名称,比如内连接、外连接、交叉连接等,这些连接大多是以不同的表或视图为对象进行的,针对相同的表进行的连接成为自连接。理解自连接有助于我们理解SQL面向集合的语言特性。
可重排列、排列、组合
CREATE TABLE Products
(name VARCHAR(16) PRIMARY KEY,
price INTEGER NOT NULL);
--可重排列·排列·组合
INSERT INTO Products VALUES('苹果', 50);
INSERT INTO Products VALUES('橘子', 100);
INSERT INTO Products VALUES('香蕉', 80);
--排序
DELETE FROM Products;
INSERT INTO Products VALUES('苹果', 50);
INSERT INTO Products VALUES('橘子', 100);
INSERT INTO Products VALUES('葡萄', 50);
INSERT INTO Products VALUES('西瓜', 80);
INSERT INTO Products VALUES('柠檬', 30);
INSERT INTO Products VALUES('香蕉', 50);
--不聚合,查看集合的包含关系
DELETE FROM Products;
INSERT INTO Products VALUES('橘子', 100);
INSERT INTO Products VALUES('葡萄', 50);
INSERT INTO Products VALUES('西瓜', 80);
INSERT INTO Products VALUES('柠檬', 30);
-- 可重排列(3*3种结果)
SELECT P1.name AS name_1,P2.name AS name_2 FROM Products P1,Products P2;
-- 排列($P_3^2$种结果)
SELECT P1.name AS name_1,P2.name AS name_2 FROM Products P1,Products P2 WHERE P1.name <> P2.name;
-- 组合($C_3^2$种结果)
SELECT P1.name AS name_1,P2.name AS name_2 FROM Products P1,Products P2 WHERE P1.name > P2.name;
-- 组合 非等值自连接
SELECT P1.name AS name_1,P2.name AS name_2,P3.name AS name_3 FROM Products P1,Products P2,Products P3 WHERE P1.name > P2.name AND P2.name > P3.name;
删除重复行
-- 用于删除重复行的SQL语句(1):使用极值函数(仅支持Oracle)
DELETE FROM Products P1 WHERE rowid < (SELECT MAX(P2.rowid) FROM Product P2 WHERE P1.name = P2.name AND P1.price = P2.price)
-- 用于删除重复行的SQL语句(1):使用非等值连接
DELETE FROM Products P1 WHERE EXISTS (SELECT * FROM Products P2 WHERE P1.name = P2.name AND P1.price = P2.price AND P1.rowid < P2.rowid)
查找局部不一致的列
--查找局部不一致的列
CREATE TABLE Addresses
(name VARCHAR(32),
family_id INTEGER,
address VARCHAR(32),
PRIMARY KEY(name, family_id));
INSERT INTO Addresses VALUES('前田义明', '100', '东京都港区虎之门3-2-29');
INSERT INTO Addresses VALUES('前田由美', '100', '东京都港区虎之门3-2-92');
INSERT INTO Addresses VALUES('加藤茶', '200', '东京都新宿区西新宿2-8-1');
INSERT INTO Addresses VALUES('加藤胜', '200', '东京都新宿区西新宿2-8-1');
INSERT INTO Addresses VALUES('福尔摩斯', '300', '贝克街221B');
INSERT INTO Addresses VALUES('华生', '400', '贝克街221B');
SELECT DISTINCT A1.name,A2.name FROM Addresses A1,Addresses A2 WHERE A1.family_id = A2.family_id AND A1.address <> A2.address;
DELETE FROM Products;
INSERT INTO Products VALUES('苹果', 50);
INSERT INTO Products VALUES('橘子', 100);
INSERT INTO Products VALUES('葡萄', 50);
INSERT INTO Products VALUES('西瓜', 80);
INSERT INTO Products VALUES('柠檬', 30);
INSERT INTO Products VALUES('草莓', 100);
INSERT INTO Products VALUES('香蕉', 100);
-- 用于查找价格相同但商品名称不同的记录的SQL语句
SELECT DISTINCT P1.name,P1.price FROM Products P1,Products P2 WHERE P1.price = P2.price AND P1.name <> P2.name;
排序
-- 窗口函数(OLAP函数/分析函数)依赖特定数据库的实现
SELECT name,price,
RANK() OVER (ORDER BY price DESC) AS rank_1, -- 跳过并列
DENSE_RANK() OVER (ORDER BY price DESC) AS rank_2 --不跳过并列
FROM Products;

SELECT P1.name,P1.price,
(SELECT COUNT(P2.price)
FROM Products P2 WHERE P1.price < P2.price) + 1 AS rank_1
FROM Products P1 ORDER BY rank_1;

-- 添加DISTINCT,类似于DENSE_RANK函数
SELECT P1.name,P1.price,
(SELECT COUNT(DISTINCT P2.price)
FROM Products P2 WHERE P1.price < P2.price) + 1 AS rank_1
FROM Products P1 ORDER BY rank_1;

-- 排序 使用自连接
SELECT P1.name,MAX(P1.price) AS price,COUNT(P2.price)+1 AS rank_1 FROM Products AS P1
LEFT JOIN Products AS P2 ON P1.price < P2.price GROUP BY P1.name ORDER BY rank_1;
-- 不聚合,查看结合的包含关系
SELECT P1.name,P2.name FROM Products AS P1
LEFT JOIN Products AS P2 ON P1.price < P2.price;
-- 如果这里不是用LEFT JOIN而使用INNER JOIN?
小结
- 自连接经常和非等值连接结合起来使用
- 自连接和GROUP BY结合使用可以生成递归集合
- 将自连接看做不同表直接的连接更容易理解
- 应把表看做行的集合,用面向集合的方法来思考
- 自连接的性能开销更大,应尽量给用于连接的列建立索引
练习题
-- 练习题 1-2-1 可重组合
-- 可重组合
SELECT P1.name,P2.name FROM Products AS P1,Products AS P2 WHERE P1.name >= P2.name;
-- 练习题 1-2-2 分地区排序
-- 方法一 窗口函数
SELECT district,name,price,RANK () OVER (PARTITION BY district ORDER BY price DESC)
FROM DistrictProducts;
-- 自连接(关联子查询)
SELECT DP1.district,DP1.name,DP1.price,(SELECT COUNT(DP2.price)+1 FROM DistrictProducts DP2 WHERE DP1.district = DP2.district AND DP1.price < DP2.price) AS rank_1
FROM DistrictProducts DP1;
-- 更新位次
/* 练习题1-2-3:自连接 */
SELECT P1.district, P1.name,
MAX(P1.price) AS price,
COUNT(P2.name) +1 AS rank_1
FROM DistrictProducts P1 LEFT OUTER JOIN DistrictProducts P2
ON P1.district = P2.district
AND P1.price < P2.price
GROUP BY P1.district, P1.name;
SQL进阶系列之2自连接的更多相关文章
- SQL进阶系列之9用SQL处理数列
写在前面 关系模型的数据结构里,并没有顺序的概念,但SQL处理有序集合也有坚实的理论基础 生成连续编号 --生成连续编号 CREATE TABLE Digits (digit INTEGER PRIM ...
- SQL进阶系列之7用SQL进行集合运算
写在前面 集合论是SQL语言的根基,因为这种特性,SQL也被称为面向集合语言 导入篇:集合运算的几个注意事项 注意事项1:SQL能操作具有重复行的集合(multiset.bag),可以通过可选项ALL ...
- SQL进阶系列之6用关联子查询比较行与行
写在前面 使用SQL对同一行数据进行列间的比较很简单,只需要在WHERE子句里写上比较条件就可以了,对于不同行数据进行列间比较需要使用自关联子查询. 增长.减少.维持现状 需要用到行间比较的经典场景是 ...
- SQL进阶系列之4HAVING字句的力量
写在前面 SQL是面向集合的语言,与面向过程和面向对象语言都不一样 寻找缺失的编号 /* 寻找缺失的编号 */ CREATE TABLE SeqTbl (seq INTEGER PRIMARY KEY ...
- Linq To Sql进阶系列(六)用object的动态查询与保存log篇
动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动 ...
- SQL进阶系列之12SQL编程方法
写在前面 KISS -- keep it sweet and simple 表的设计 注意命名的意义 英文字母 + 阿拉伯数字 + 下划线"_" 属性和列 编程的方针 写注释 注意 ...
- SQL进阶系列之10HAVING子句又回来了
写在前面 HAVING子句的处理对象是集合而不是记录 各队,全队点名 --各队,全体点名! CREATE TABLE Teams (member CHAR(12) NOT NULL PRIMARY K ...
- SQL进阶系列之11让SQL飞起来
写在前面 SQL的性能优化是数据库使用者必须面对的重要问题,本节侧重SQL写法上的优化,SQL的性能同时还受到具体数据库的功能特点影响,这些不在本节讨论范围之内 使用高效的查询 参数是子查询时,使用E ...
- SQL进阶系列之8EXISTS谓词的用法
写在前面 支撑SQL和关系数据库的基础理论:数学领域的集合论和逻辑学标准体系的谓词逻辑 理论篇 什么是谓词?谓词是返回值为真值(true false unknown)的函数 关系数据库里,每一个行数据 ...
随机推荐
- Mongodb CPU占用率达90%的优化调整报告
1问题描述 1.1现场的数据库部署情况 服务器基本情况如下: CPU 20逻辑核,40线程 内存 64 G 硬盘 D盘 :1T SSD E盘:3T SATA F盘:3T SATA 在这台机器上同时部署 ...
- IO多路复用(select、poll、epoll)介绍及select、epoll的实现
IO多路复用(select.poll.epoll)介绍及select.epoll的实现 IO多路复用中包括 select.pool.epoll,这些都属于同步,还不属于异步 一.IO多路复用介绍 1. ...
- 关于最火爆的服务器Tomcat你真的了解吗?
作为Apache 软件基金会的Jakarta 项目中的一个核心项目,Tomcat因技术先进.性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应 ...
- 开源之路2--SSH
SSH 为 Secure Shell (安全外壳协议)的缩写,由 IETF 的网络小组(Network Working Group)所制定:SSH是每一台Linux电脑的标准配置. SSH 是建立在应 ...
- matlab调试时子函数断点不起作用
matlab调试代码时总是遇到这样一个奇怪的问题,就是当我在主程序(.m脚本)中调用子函数并在子函数中设置断点,然后开始调试运行主程序... 发现主程序直接运行到结束而并没有在调用子函数的时候在所设置 ...
- LeetCode 859. 亲密字符串(Buddy Strings) 23
859. 亲密字符串 859. Buddy Strings 题目描述 给定两个由小写字母构成的字符串 A 和 B,只要我们可以通过交换 A 中的两个字母得到与 B 相等的结果,就返回 true:否则返 ...
- ERP通过JAVA流的形式将数据传到外围系统
1.ERP封装数据成XML写入数据库服务器指定文件 --指定相关文件信息 v_file_path := '/u01/test/app/fs1/EBSapps/appl/cux/12.0.0/forms ...
- 43 多线程(十三)——CAS(了解即可)
emm...记一些关键词吧 原子操作 悲观锁.乐观锁 比较交换 硬件层面 C.C#底层实现 JUC = java.util.concurrent 高级并发才使用 面试会问到 了解即可 剩下的内容交给未 ...
- LOJ2482 CEOI2017 Mousetrap 二分答案、树形DP
传送门 表示想不到二分答案qwq 将树看作以陷阱为根.先考虑陷阱和起始点相邻的情况,此时老鼠一定会往下走,而如果管理者此时不做操作,那么一定会选择让操作次数变得最大的一棵子树.设\(f_i\)表示当前 ...
- CCF 2016-04-2 俄罗斯方块
CCF 2016-04-2 俄罗斯方块 题目 问题描述 俄罗斯方块是俄罗斯人阿列克谢·帕基特诺夫发明的一款休闲游戏. 游戏在一个15行10列的方格图上进行,方格图上的每一个格子可能已经放置了方块,或者 ...