自连接用法

可重排列、排列、组合

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);
用于获取可重排列的SQL 语句
SELECT P1.name AS name_1, P2.name AS name_2
FROM Products P1, Products P2
-- 也可写作:
SELECT P1.name AS name_1, P2.name AS name_2
FROM Products P1 CROSS JOIN Products P2;

执行结果里每一行(记录)都是一个有序对。因为是可重排列,所以结果行数为 3^2 = 9

排除掉由相同元素构成的对:
SELECT P1.name AS name_1, P2.name AS name_2
FROM Products P1, Products P2
WHERE P1.name <> P2.name;

排除掉由相同元素构成的对,结果行数为6排列 。
在 SQL 里,只要被赋予了不同的名称,
即便是相同的表也应该当作不同的表(集合)来对待。所以,相同的表的自连接和不同表间的普通连接并没有什么区别。

接下来我们进一步对(苹果, 橘子)和(橘子, 苹果)这样只是调换了元素顺序的对进行去重:
SELECT P1.name AS name_1, P2.name AS name_2
FROM Products P1, Products P2
WHERE P1.name > P2.name;

3 个以上元素的组合:

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语句所做的是,按字符顺序排列各商品,只与“字符顺序比自己靠前”的商品进行配对

删除重复行

如果重复的列里不包含主键,就可以用主键来处理,但像这道例题一样所有的列都重复的情况,则需要使用由数据库独自实现的行 ID。如果重复的列里不包含主键,就可以用主键来处理,如果所有的列都重复的情况,则需要使用由数据库独自实现的行 ID。
(给用户提供了可用的行 ID 的数据库只有 Oracle(rowid )和 PostgreSQL(oid
))。

-- 用于删除重复行的SQL语句:使用极值函数  
DELETE FROM Products P1 WHERE rowid < ( SELECT MAX(P2.rowid)
FROM Products P2 WHERE P1.name = P2. name AND P1.price = P2.price );

-- 用于删除重复行的SQL语句:使用非等值连接  
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 

查找局部不一致的列

-- 用于查找价格相等但商品名称不同的记录的SQL 语句
SELECT DISTINCT P1.name, P1.price
FROM Products P1, Products P2
WHERE P1.price = P2.price
AND P1.name <> P2.name;

排序

在使用数据库制作各种票据和统计表的工作中,我们经常会遇到按分数、人数或销售额等数值进行排序的需求。
要按照价格从高到低的顺序,对商品进行排序:

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);

-- 窗口函数
select name,price,
	RANK() OVER (ORDER BY price DESC) AS rank_1,
	DENSE_RANK() OVER (ORDER BY price DESC) AS rank_2
FROM Products;

执行结果:

name price rank_1 rank_2
橘子 100 1 1
西瓜 80 2 2
苹果 50 3 3
香蕉 50 3 3
葡萄 50 3 3
柠檬 30 6 4
  • 聚合函数RANK和dense_rank主要的功能是计算一组数值中的排序值。
  • 区别:dence_rank在并列关系是,相关等级不会跳过。rank则跳过。

MySQL暂不支持rank()函数,可以使用非等值自连接:

-- 排序从1开始。如果已出现相同位次,则跳过之后的
SELECT P1.name,P1.price,
		(SELECT COUNT(P2.price)
		FROM Products P2
		WHERE P2.price > P1.price) + 1 AS rank_1
FROM Products P1
ORDER BY rank_1;
-- 子查询所做的,是计算出价格比自己高的记录的条数并将其作为自己的位次

如果修改成COUNT(DISTINCT P2.price) ,那么存在相同位次的记录时,就可以不跳过之后的位次,而是连续输出(相当于 DENSE_RANK 函数)

与多表之间进行的普通连接相比,自连接的性能开销更大(特别是与非等值连接结合使用的时候),因此用于自连接的列推荐使用主键或者在相关列上建立索引。
原文地址:https://www.cnblogs.com/sanzashu/p/10997699.html