写在前面

一般地,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. Excel统计发票和金税盘核对新版

    之前的博文:如何使用Excel表格状态栏动态查看统计,介绍了如何利用excel一拉就可以进行统计,和金税盘的月度统计统计.由于最近年月日显示成方框,所以作废了发票和对冲了上月的一张发票,导致这个月出现 ...

  2. [LeetCode] 270. Closest Binary Search Tree Value 最近的二叉搜索树的值

    Given a non-empty binary search tree and a target value, find the value in the BST that is closest t ...

  3. 【VS开发】【C/C++开发】memcpy和memmove的区别

    memcpy和memmove()都是C语言中的库函数,在头文件string.h中,作用是拷贝一定长度的内存的内容,原型分别如下: void *memcpy(void *dst, const void ...

  4. k8s 修改节点角色和删除节点

    修改节点角色: kubectl label nodes cn-thin05 node-role.kubernetes.io/node= 卸载节点: kubectl drain jupiter --de ...

  5. centos7 nginx 配置 ssl证书

    安装nginx 从阿里云服务器下载 nginx版本的ssl证书,防止再 /etc/nginx/ssl 下 停止 nginx 服务 systemctl stop nginx 修改配置文件 /etc/ng ...

  6. 《PHP - 信号/基本操作/配置》

    一:PHP 信号 - SIGINT / SIGTERM / SIGQUIT - 退出FPM,在master收到退出信号后将向所有的worker进程发送退出信号,然后master退出. - SIGUSR ...

  7. C语言单链表简单实现(简单程序复杂化)

    PS: goto还是很好玩的. #include <stdio.h> #include <stdlib.h> typedef struct _node{ int value; ...

  8. STL对map排序

    // sort start typedef struct{ ... }Node; // Map的键是字符串,值是结构体.虽然有自动排序特性,但是按字符串的排序并不能符合要求.此时,Map的key可以视 ...

  9. HTML常用技巧

    1. 为网页链接添加快捷键:accesskey 属性 https://zhidao.baidu.com/question/2267343500557447508.html 2. 键盘事件设置快捷键:h ...

  10. Select与Epoll的区别

      相同点: 都是IO多路转接,都是一个线程能同一时间等待一堆描述符 不同点: 1.select接口使用不方便,每次调用完select都需要重新设置fd_set,因为输入输出未分离,返回的fd_set ...