1. 程式人生 > 實用技巧 >sql中的join

sql中的join

首先準備資料

有以下資料,三張表:role(角色表)、hero(英雄表)、skill(技能表),我們以英雄聯盟的資料做示例

  • 一個hero對應一個role(我們這裡暫定)
  • 一個role可以對應多個hero
  • 一個hero可以對應多個skill
  • 一個skill只能對應一個hero

DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
  `id` int NOT NULL AUTO_INCREMENT,
  `Name` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
INSERT INTO `role` VALUES (1,'戰士'),(2,'法師'),(3,'刺客'),(4,'坦克'),(5,'射手'),(6,'輔助');

DROP TABLE IF EXISTS `hero`;
CREATE TABLE `hero` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  `title` varchar(45) NOT NULL,
  `role_id` int NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
INSERT INTO `hero` VALUES (1,'趙信','德邦總管',1),(2,'安妮','黑暗之女',2),(3,'瑞茲','符文法師',2),(4,'卡特琳娜','不祥之刃',3);

DROP TABLE IF EXISTS `skill`;
CREATE TABLE `skill` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  `passive` varchar(45) NOT NULL DEFAULT '0',
  `hero_id` int NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;
INSERT INTO `skill` VALUES (1,'果決','1',1),(2,'三重爪擊','0',1),(3,'風斬電刺','0',1),(4,'無畏衝鋒','0',1),(5,'新月護衛','0',1),(6,'嗜火','1',2),(7,'碎裂之火','0',2),(8,'焚燒','0',2),(9,'熔岩護盾','0',2),(10,'提伯斯之怒','0',2),(11,'奧術專精','1',3),(12,'超負荷','0',3),(13,'符文禁錮','0',3),(14,'法術湧動','0',3),(15,'曲境折躍','0',3),(16,'貪婪','1',4),(17,'彈射之刃','0',4),(18,'伺機待發','0',4),(19,'瞬步','0',4),(20,'死亡蓮華','0',4);

為什麼需要join?

有時候我們需要同時獲取兩張表或三張表或更多表的資訊,我們有兩種方式:
比如我們要查出英雄是 安妮 的技能有哪些
1.我們可以先在hero表查詢到安妮的資訊,然後再去skill表查詢技能資訊,需要兩次查詢
2.我們可以使用join將兩張表關聯到一起,通過一次查詢獲取
簡單來說,就是需要同時獲取多張表的資訊時需要用到sql的join

1.corss join(交叉連線、笛卡爾連線)

corss join可以對兩張表進行笛卡爾積,任意的兩張表或多張表都可以進行笛卡爾連線,哪怕這些表沒有任何關係
我們現在對hero表和skill進行corss join

corss join的語法

SELECT * FROM hero CROSS JOIN skill;
SELECT * FROM hero,skill;
SELECT * FROM hero JOIN skill;

以上三種形式都可以生成笛卡爾積,產生的結果是兩個表的資訊合併在一起,資料條數就是兩個表條數相乘

corss join的問題

  • 笛卡爾積是兩張表中任意的資料組合
  • 真實情況中我們不會將兩個表進行笛卡爾積的,因為這樣是不符合實際業務意義的,它純粹是一個數學上的概念。比如上圖中 卡特琳娜、瑞茲、安妮是不應該有趙信的果決技能的
  • 一般情況下我們還會配合使用 on 或者 where 來做一些篩選
  • 笛卡爾積可以做2張以上表的合集

那如何將那些不符合我們業務邏輯的記錄過濾掉呢?

  • 使用 on
SELECT * FROM hero CROSS JOIN skill on hero.id = skill.hero_id;
  • 使用 where
SELECT * FROM hero CROSS JOIN skill WHERE hero.id = skill.hero_id;

此時我們查詢到的結果就是符合業務邏輯的

通常我們是不使用 corss join 加 on 或 where 進行查詢的,一般我們會使用 inner join

2.inner join(內連線)

我們直接把上面的 cross join 更改為 inner join

select * from hero inner join skill

查詢到的依然是一個笛卡爾積
加上 on 後

select * from hero inner join skill on hero.id = skill.hero_id;

查詢到的和cross join加on的結果是一樣的。

用inner join和cross join的結果都是一樣的,那麼它們有什麼區別?

  • inner join和cross join從結果上來對比是沒有區別的,inner join主要是和其他的join如left join來區別的
  • 兩者在底層實現上還是有所區別的
  • 一般來說cross join只用來求笛卡爾積

為什麼加了on就可以把錯誤的記錄去掉呢

如下圖所示,加了on只有,只會將 hero.id = skill.role_id 的資料挑選出來,錯誤的結果就被排除掉了

3.left join(左連線)和right join(右連線)

為了說明left join和right join,我們在資料庫中插入四條資料

//英雄表新增兩個英雄,但是沒有對應的技能
INSERT INTO `LOL`.`hero` (`name`, `title`, `role_id`) VALUES ('艾希', '寒冰射手', '5');
INSERT INTO `LOL`.`hero` (`name`, `title`, `role_id`) VALUES ('索拉卡', '眾星之子', '6');
//技能表新增兩個技能,但是沒有對應的英雄
INSERT INTO `LOL`.`skill` (`name`, `passive`) VALUES ('阿爾法突襲', '0');
INSERT INTO `LOL`.`skill` (`name`, `passive`) VALUES ('無極劍道', '0');

使用lefe join進行查詢

select hero.name,skill.name from hero left join skill on hero.id = skill.hero_id;

以上語句查詢,我們會得到如下結果:

沒有技能的兩個英雄,它所對應的技能為null

那麼left join和inner join有什麼區別呢?

區別就是left join會包含inner join的結果集,left join就是查詢到 hero.id = skill.hero_id 的結果集再加上左表沒有匹配到的結果集;left join是更偏重左表的,將左表裡面沒有匹配到的記錄也會加入到結果集中
left join是確保左表中的列是一定存在的

使用right join查詢

select hero.name,skill.name from hero right join skill on hero.id = skill.hero_id;

以上語句查詢,我們會得到如下結果:

所以我們發現right join和left join是相反的,側重於右表

4.outer join

有時候我們希望左表的記錄和右表的記錄都出現在結果集裡,我們就可以使用outer join
但是我們發現mysql、sqlserver都沒有 outer join這個語法,只有 left outer join 和right outer join
left outer join 查詢的結果和 left join 一樣
right outer join 查詢的結果和 right join 一樣
那我們應該如何 outer join 呢
答案是使用 union

select hero.name,skill.name from hero left join skill on hero.id = skill.hero_id
union
select hero.name,skill.name from hero right join skill on hero.id = skill.hero_id

上述查詢會產生如下結果,這個結果是符合我們預期的

以上就是sql中各種join的語法與使用