SQL思维训练二

2,719 阅读4分钟

MySQl 专栏持续更新 不说晦涩难懂的东西 尽量输出容易理解 和 使用的SQL技巧 和 初中级开发不是很常用的但很有用的知识

欢迎查看👉🏻👉🏻👉🏻SQL 专栏 查漏补缺 指教一二

src=http __img2.biaoqingjia.com_biaoqing_201810_2c3993f64eec252da6d674f9d80fc4e9.gif&refer=http __img2.biaoqingjia.gif

每一次写博客对技术都会有更深入的理解 积少成多 百天计划我也想看看自己有多少成长 祝君好运 工作顺利

本文正在参加「技术专题19期 漫谈数据库技术」活动

简单

难度:

src=http%20__qq.yh31.com_tp_zjbq_201203060912442848.gif&refe.gifsrc=http%20__qq.yh31.com_tp_zjbq_201203060912442848.gif&refe.gif

这个应该算是思路比较简单的 先创建表结构

DROP TABLE IF EXISTS `Customers`;
CREATE TABLE `Customers` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of Customers
-- ----------------------------
BEGIN;
INSERT INTO `Customers` (`id`, `name`) VALUES (1, '变成派大星');
INSERT INTO `Customers` (`id`, `name`) VALUES (2, '海绵宝宝');
INSERT INTO `Customers` (`id`, `name`) VALUES (3, '章鱼哥');
INSERT INTO `Customers` (`id`, `name`) VALUES (4, '蟹老板');
INSERT INTO `Customers` (`id`, `name`) VALUES (5, '路人甲');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

DROP TABLE IF EXISTS `Orders`;
CREATE TABLE `Orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `customers_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of Orders
-- ----------------------------
BEGIN;
INSERT INTO `Orders` (`id`, `customers_id`) VALUES (1, 3);
INSERT INTO `Orders` (`id`, `customers_id`) VALUES (2, 2);
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

问题

某网站包含两个表,Customers 表和 Orders 表。编写一个 SQL 查询,找出所有从不订购任何东西的客户。

示例

图片.png

分析

  • 两个表进行配合查询 有两种 第一个是表连接。第二个是子查询

先说表连接 关联条件是满足的 是怎么去选用 连接 方式 内链接 左连接 右连接

首先我们需要的数据是 从没有订购过的客户 也就是 Orders 不存在的 Customers 数据

  • 内链接 返回相交 不合适 可以写出结果但是比较麻烦
  • 右连接 返回右表数据 这个肯定是不行的 因为它只会返回 他拥有的 customers_id 但是我需要的未拥有 其实这里就可以明白 我们应该设置左表为主表 因为我们返回的信息是左表的信息
  • 左链接 未匹配 数据是null 但是返回左表所有数据 这样我们就知道 右表数据为空 就是未购买的客户

左链接:

select * from Customers c left join Orders os on os.customers_id = c.id

下图中 orders 表数据为空的数据就是我们想要的 图片.png

过滤:

图片.png

得到结果

子查询

先查出 orders 表中的 customers_id 然后使用 Customers 进行过滤 这个思路很好理解

图片.png

中等

这个难度三颗星吧 主要是如果前面练习几个题之后 思路就会好点

src=http%20__qq.yh31.com_tp_zjbq_201203060912442848.gif&refe.gifsrc=http%20__qq.yh31.com_tp_zjbq_201203060912442848.gif&refe.gifsrc=http%20__qq.yh31.com_tp_zjbq_201203060912442848.gif&refe.gif

表结构:

DROP TABLE IF EXISTS `Logs`;
CREATE TABLE `Logs` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `num` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of Logs
-- ----------------------------
BEGIN;
INSERT INTO `Logs` (`id`, `num`) VALUES (1, '1');
INSERT INTO `Logs` (`id`, `num`) VALUES (2, '1');
INSERT INTO `Logs` (`id`, `num`) VALUES (3, '1');
INSERT INTO `Logs` (`id`, `num`) VALUES (4, '3');
INSERT INTO `Logs` (`id`, `num`) VALUES (5, '3');
INSERT INTO `Logs` (`id`, `num`) VALUES (6, '4');
INSERT INTO `Logs` (`id`, `num`) VALUES (7, '4');
INSERT INTO `Logs` (`id`, `num`) VALUES (8, '3');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

这个题其实挺有意思的

问题

编写一个 SQL 查询,查找所有至少连续出现三次的数字。

返回的结果表中的数据可以按 任意顺序 排列。

示例图

图片.png

分析

这个主要的难点在于 连续 且相等 如果仅仅是出现次数大于等于三次的 我们可以直接 通过 having 进行过滤 但是要想找到连续的就要进行运算比较 前面练习过的数据 我们知道一个表数据中 进行数据比较 可以去使用自连接 id 因为是自增的 连续的id 就说明 每行相差 1 这两个思路比较重要 至少大于 3 就需要自连接两次 将三张表的数据进行比较

先筛选出相等三张表中相等的数据


-- 三张表连接 会有 8*8*8 = 512 条数据
select * FROM  Logs l1,Logs l2,Logs l3

-- 筛选出 num 相同的数据 62条
select * FROM  Logs l1,Logs l2,Logs l3 where l1.num = l2.num and l2.num = l3.num

筛选完成之后还剩余 62 条 接下来根据 id 连续来进行筛选 Id 是否连续 需要通过列运算 如下写法:

-- 当超过 3个连续相同的会有 重复数据 所有需要去重
select DISTINCT l1.num AS ConsecutiveNums FROM  Logs l1,Logs l2,Logs l3 where l1.num = l2.num and l2.num = l3.num and l3.id = l2.id + 1 and l2.id = l1.id + 1

上面这种写法 比较中规中矩 还有一种很有意思的写法 使用子查询 这种写法相对来说比较有意思


SELECT DISTINCT Num AS ConsecutiveNums FROM Logs 
WHERE (id+1, num) IN (SELECT * FROM Logs)
AND (id+2, num) IN (SELECT * FROM Logs)

-- 相当于
SELECT DISTINCT Num AS ConsecutiveNums FROM Logs 
WHERE (1+1, 1) IN (SELECT * FROM Logs)
AND (1+2, 1) IN (SELECT * FROM Logs)

结尾

着实有点忙 第三题非找个困难的搞一搞 先让他跑一会

本文正在参加「技术专题19期 漫谈数据库技术」活动