# 準備數據
~~~
-- 新建 user1 表
create table if not exists user1 (
id smallint unsigned primary key auto_increment,
user_name varchar(40),
over varchar(40)
);
-- 新建 user2 表
create table if not exists user2 (
id smallint unsigned primary key auto_increment,
user_name varchar(40),
over varchar(40)
);
-- 新建 user_kills 表
create table if not exists user_kills (
id smallint unsigned primary key auto_increment,
user_id smallint unsigned,
timestr timestamp default CURRENT_TIMESTAMP,
kills smallint unsigned
);
insert into user1 (user_name,over) values ('唐僧','功德佛'),('豬八戒','凈壇使者'),('孫悟空','斗戰勝佛'),('沙僧','金身羅漢');
insert into user2 (user_name) values ('孫悟空','成佛'),('牛魔王','被降服'),('蛟魔王','被降服'),('鵬魔王','被降服'),('獅駝王','被降服');
insert into user_kills (user_id,timestr,kills) values ('2','2017-01-10 00:00:00','10'),('2','2017-02-01 00:00:00','2'),('2','2017-02-05 00:00:00','12'),('4','2017-01-10 00:00:00','3'),('2','2017-02-11 00:00:00','5'),('2','2017-02-06 00:00:00','1'),('3','2017-01-11 00:00:00','20'),('2','2017-02-12 00:00:00','10'),('2','2017-02-07 00:00:00','17');
~~~
# 全連接
MySQL不支持FULL JOIN
解決方法:
通過UNION將左連接和右連接的結果合并
~~~
SELECT select_expressions
FROM TABLE A LEFT OUTER JOIN TABLE B ON A.key=B.key
UNION ALL
SELECT select_expressions
FROM TABLE A RIGHT OUTER JOIN TABLE B ON A.key=B.key;
~~~
**UNION會自動刪除重復項,刷選出部分字段的時候要注意了,如果刷選出來的兩個字段的值完全相同就會剩下一個。**
**UNION ALL 和 UNION 不同之處在于 UNION ALL 會將左右兩個查詢的結果的所有的資料都列出來,無論資料值有無重復。**

# 內連接
join的內連接是抽取兩張表的公共部分
內連接(inner join) 可以選取A表和B表的交集 select 字段 from A表 a表別名 inner join B表 b表別名 on a.字段=b.字段;
# 左外連接
not in 關鍵字不會使用索引 所以用left join加上關鍵字為null查找只存在于A表不存在于B表的數據

LEFT OUTER JOIN:包含左表中的所有數據,當某個連接謂詞不在右表中時,新生成的表的右表字段為NULL。對左表數據的信息進行擴展,增加右表中的字段,當某個連接謂詞不在右表中時,新生成的表的右表字段為NULL。
使用LEFT OUTER JOIN對NOT IN 進行優化。
# 右外連接
RIGHT OUTER JOIN:包含右表中的所有數據,當某個連接謂詞不在左表中時,新生成的表的左表字段為NULL。對右表數據的信息進行擴展,增加左表中的字段,當某個連接謂詞不在左表中時,新生成的表的左表字段為NULL。
使用RIGHT OUTER JOIN對NOT IN 進行優化。
~~~
SELECT select_sxpressions
FROM TABLE A RIGHT OUTER JOIN TABLE B ON A.key=B.key
WHERE A.key IS NULL;
~~~
表B中不包含表A中的數據。
~~~
SELECT select_sxpressions
FROM TABLE A RIGHT OUTER JOIN TABLE B ON A.key=B.key
WHERE A.key IS NOT NULL;
~~~
表A與表B的交集,相當于INNER JOIN。

# 交叉連接
CROSS JOIN:笛卡爾連接,如果A和B是兩個集合,它們的交叉連接就記為A X B。一個表的每個記錄與另一個表的所有記錄進行連接,形成`A.length*B.length`個數據項的表。(無需提供ON)
~~~
SELECT select_expressions
FROM TABLE A CROSS JOIN TABLE B;
~~~
在實際的使用中,要盡量避免產生笛卡爾積的查詢,因為很少情況我們會使用到笛卡爾積的查詢結果,但是在一些特殊情況下,我們需要笛卡兒積查詢產生我們需要的結果。
# join更新表

先select出同一表中的某些值,再update這個表(在同一語句中)
mysql不支持這種,不能更新出現在from從句中,where后面你用了更新表user1作為子查詢表這是不容許的,其他的一些sql支持
~~~
update user1 a join
(select b.'user_name' from user1 a join user2 b on a.'user_name'=b.'user_name')
b on a.'user_name' = b.'user_name' set a.over='齊天大圣';
~~~
也就是說將select出的結果再通過中間表select一遍,這樣就規避了錯誤。注意,這個問題只出現于mysql,mssql和oracle不會出現此問題。
# 子查詢
## join優化子查詢技巧:

一般子查詢寫法:(數據小時,沒有多大影響,如果數據量大時,則要消耗大量的查詢)
~~~
select a.user_name , a.over , (select over from user2 b where a.user_name = b.user_name) as over2
from user1 a;
~~~
如果這兩張表的記錄相當多 那么這個子查詢相當于對A標的每一條記錄都要進行一次子查詢。
join優化(左連接)后的寫法:
~~~
select a.user_name , a.over , b.over from user1 a
left join user2 b on a.user_name = b.user_name
~~~
## join優化聚合子查詢
~~~
-- 如何查詢打怪最多的日期
select a.user_name,b.timestr,b.kills from
user1 a join user_kills b on a.id=b.user_id
where
b.kills=(select max(c.kills) from user_kills c where c.user_id=b.user_id);
-- 優化后語句 避免子查詢
select a.user_name,b.timestr,b.kills from user1 a inner join user_kills b on a.id=b.user_id inner join user_kills c on c.user_id=b.user_id group by a.user_name,b.timestr,b.kills having b.kills = max(c.kills);
~~~
## 分組選擇數據
分組選擇解決的問題?
如果說在幾組數據中尋找最大或者最小的記錄那么很好找,可以用聚合函數達到目的 ,但是如果要在分類中選擇幾條記錄那么就需要分組選擇了
比如在取經四人組中查出每人前2天的殺怪記錄

采用ROW_NUMBER函數,進行分區排序
使用WITH 表名 AS (),不過MySQL中不支持ROW_NUMBER() OVER(PARTITION BY 字段名 )
row_number() OVER(PARTITION BY)與 rank() OVER(PARTITION BY) 區別:前者有兩個并列第一則返回一條記錄,后者返回兩條,同時是跳躍排序;dense_rank()是連續排序!!(mySql中不支持這種查詢方法)
可以通過這個方法來實現

還有個

- SQL
- 名詞
- mysql
- 初識mysql
- 備份和恢復
- 存儲引擎
- 數據表損壞和修復
- mysql工具
- 數據庫操作
- 增
- 刪
- 改
- 查
- 數據類型
- 整數類型
- 小數類型
- 日期時間類型
- 字符和文本型
- enum類型
- set類型
- 時間類型
- null與not null和null與空值''的區別
- 數據表操作
- 創建
- 索引
- 約束
- 表選項列表
- 表的其他語句
- 視圖
- sql增刪改查
- sql增
- sql刪
- sql改
- sql查
- sql語句練習
- 連接查詢和更新
- 常用sql語句集錦
- 函數
- 字符函數
- 數值運算符
- 比較運算符與函數
- 日期時間函數
- 信息函數
- 聚合函數
- 加密函數
- null函數
- 用戶權限管理
- 用戶管理
- 權限管理
- pdo
- 與pdo相關的幾個類
- 連接數據庫
- 使用
- pdo的錯誤處理
- pdo結果集對象
- pdo結果集對象常用方法
- pdo預處理
- 常用屬性
- mysql編程
- 事務
- 語句塊
- mysql中的變量
- 存儲函數
- 存儲過程
- 觸發器
- mysql優化
- 存儲引擎
- 字段類型
- 三范式和逆范式
- 索引
- 查詢緩存
- limit分頁優化
- 分區
- 介紹
- 分區算法
- list分區
- range范圍
- Hash哈希
- key鍵值
- 分區管理
- 特別注意
- 分表
- 數據碎片與維護
- innodb表壓縮
- 慢查詢
- explain執行計劃
- count和max,groupby優化
- 子查詢優化
- mysql鎖機制
- 介紹
- 演示
- 總結
- 樂觀鎖和悲觀鎖
- 扛得住的mysql
- 實例和故事
- 系統參數優化
- mysql體系結構
- mysql基準測試
- 索引
- mysql的復制
- win配置MySQL主從
- mysql5.7新特性
- 常見問題
- general log
- 忘記密碼
- uodo log與redo log
- 事務隔離級別
- mysql8密碼登錄
- explain
- 高效的Tree表
- on delete cascade 總結
- mongod
- 簡介
- 集合文檔操作語句
- 增刪改查
- 索引
- 數據導入和導出
- 主從復制
- php7操作mongod
- 權限管理
- redis
- redis簡介
- 3.2版本配置文件
- 3.0版本配置文件
- 2.8版本配置文件
- 配置文件總結
- 外網連接
- 持久化
- RDB備份方式保存數據
- AOF備份方式保存數據
- 總結
- win安裝redis和sentinel部署
- 事務
- Sentinel模式配置
- 分布式鎖
- 管道
- php中redis代碼
- 發布訂閱
- slowlog
- Redis4.0
- scan和keys
- elasticsearch
- 配置說明
- 啟動
- kibana
- kibana下載
- kibana配置文件
- kibana常用功能
- 常用術語
- Beats
- Beats簡介
- Filebeat
- Packetbeat
- Logstash
- 配置
- elasticsearch架構
- es1.7
- head和bigdesk插件
- 插件大全
- 倒排索引
- 單模式下API增刪改查
- mget獲取多個文檔
- 批量操作bulk
- 版本控制
- Mapping映射
- 基本查詢
- Filter過濾
- 組合查詢
- es配置文件
- es集群優化和管理
- logstash
- kibana
- es5.2
- 安裝
- 沖突處理
- 數據備份
- 缺陷不足
- 集群管理api
- 分布式事務
- CAP理論
- BASE模型
- 兩階段提交(2PC)
- TCC (Try-Confirm-Cancle)
- 異步確保型
- 最大努力通知型
- 總結