写在前面

一般地,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自连接的更多相关文章

  1. SQL进阶系列之9用SQL处理数列

    写在前面 关系模型的数据结构里,并没有顺序的概念,但SQL处理有序集合也有坚实的理论基础 生成连续编号 --生成连续编号 CREATE TABLE Digits (digit INTEGER PRIM ...

  2. SQL进阶系列之7用SQL进行集合运算

    写在前面 集合论是SQL语言的根基,因为这种特性,SQL也被称为面向集合语言 导入篇:集合运算的几个注意事项 注意事项1:SQL能操作具有重复行的集合(multiset.bag),可以通过可选项ALL ...

  3. SQL进阶系列之6用关联子查询比较行与行

    写在前面 使用SQL对同一行数据进行列间的比较很简单,只需要在WHERE子句里写上比较条件就可以了,对于不同行数据进行列间比较需要使用自关联子查询. 增长.减少.维持现状 需要用到行间比较的经典场景是 ...

  4. SQL进阶系列之4HAVING字句的力量

    写在前面 SQL是面向集合的语言,与面向过程和面向对象语言都不一样 寻找缺失的编号 /* 寻找缺失的编号 */ CREATE TABLE SeqTbl (seq INTEGER PRIMARY KEY ...

  5. Linq To Sql进阶系列(六)用object的动态查询与保存log篇

    动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动 ...

  6. SQL进阶系列之12SQL编程方法

    写在前面 KISS -- keep it sweet and simple 表的设计 注意命名的意义 英文字母 + 阿拉伯数字 + 下划线"_" 属性和列 编程的方针 写注释 注意 ...

  7. SQL进阶系列之10HAVING子句又回来了

    写在前面 HAVING子句的处理对象是集合而不是记录 各队,全队点名 --各队,全体点名! CREATE TABLE Teams (member CHAR(12) NOT NULL PRIMARY K ...

  8. SQL进阶系列之11让SQL飞起来

    写在前面 SQL的性能优化是数据库使用者必须面对的重要问题,本节侧重SQL写法上的优化,SQL的性能同时还受到具体数据库的功能特点影响,这些不在本节讨论范围之内 使用高效的查询 参数是子查询时,使用E ...

  9. SQL进阶系列之8EXISTS谓词的用法

    写在前面 支撑SQL和关系数据库的基础理论:数学领域的集合论和逻辑学标准体系的谓词逻辑 理论篇 什么是谓词?谓词是返回值为真值(true false unknown)的函数 关系数据库里,每一个行数据 ...

随机推荐

  1. Component 'TABCTL32.OCX'错误的处理方法

    错误:Component 'TABCTL32.OCX' or one of its dependencies not correctyly registered:a file is missing o ...

  2. 【电商日志项目之六】数据分析-Hive方式

    环境 hadoop-2.6.5 hive-1.2.1 一.Hive和Hbase整合如果使用Hive进行分析,Hive要从Hbase取数据(当然可以直接将数据存到Hive),那么就需要将Hive和HBa ...

  3. C++ ActiveX开发的问题讨论

    最近在一个项目中需要开发一个ocx插件,在开发过程中发现了一些问题,所以在此记录一下. 我想讨论的主要是函数的参数问题,我分别使用c++,JavaScript,C#对ocx插件做了测试,发现不同的参数 ...

  4. react-redux源码学习

    React-redux 源码学习 version 7.0.3 目录 Provider connect mapStateToProps mapDispatchToProps mergeProps opt ...

  5. leetcode 罗马数字和数字的互相转换

    不知哪个大佬说过: 关于字符串的题都可以用指针或哈希解决. 罗马数字转数字: 思想: 我们能观察到规律: 一般情况下,表示大的字母在前,小字母在后; 特殊情况下,小字母会在大字母之前,但是相应的,得到 ...

  6. 路由Routers

    路由Routers 对于视图集ViewSet,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息. REST framework提供 ...

  7. ssh远程连接一段时间会失效的问题

    话不多讲,先说明我的环境和远程环境. 本地环境:Ubuntu18.04(client) 远程环境:Ubuntu16.04(server) 我的一个小项目部署在百度云的Ubuntu服务器上,需要经常使用 ...

  8. Java设计模式之委派模式(Dellegate/Dispather)

    概述: 委派模式有点像代理模式又有点像策略模式. 区别在于代理模式注重过程,委派模式注重结果. 生活中也有很多委派模式的例子:例如公司老板给项目经理下达任务,将任务全权交给项目经理,有项目经理根据一定 ...

  9. ASP.NET WebAPI 连接数据库

    ASP.NET Web API 是一种框架,用于轻松构建可以访问多种客户端(包括浏览器和移动设备)的 HTTP 服务. ASP.NET Web API 是一种用于在 .NET Framework 上构 ...

  10. docker postgres 导出导入数据

    导出 -s  选项用来只导出表结构,而不会导出表中的数据 -t   选项用来指定要导出的数据库表 格式:docker exec -ti 容器名 pg_dump -U 用户名 -s -t table_n ...