在進行復雜業務邏輯sql編寫時,往往理不清多張表之間的連接關係,這時你需要一個清晰的思路來串連多張表。第一個誤區就是根據查詢條件認爲查詢字段所在表爲主表,這是錯誤的,表的連接順序往往是固定的,查詢條件字段所在表是主表是個僞命題。
1、根據某個字段分組,但是字段值爲某些值得是有歸爲一組
比如記錄如下:
id status
100 1
101 2
102 3
103 4
104 5
105 99
106 98
將status 5 99 98的歸爲一個組,其他的按status值分組
SELECT
count(*) as count,
case when status in (90,98,5) then 5 else status end as optyStatus
from some_test
where `status` is not null
group by case when status in (90,98,5) then 5 else status end
2、2個表間複製數據
INSERT INTO hb_t_nickname1(nickname,gender,is_deleted)
SELECT DISTINCT nickname,gender,is_deleted FROM hb_t_nickname;
3、刪除重複數據
注意:不能重命名
DELETE hb_t_iu from hb_t_iu,(
SELECT
max(id) id,
tel
FROM
hb_t_iu
GROUP BY
tel
HAVING
count( * ) > 1 ) iu2
where hb_t_iu.tel = iu2.tel
and hb_t_iu.id < iu2.id
4、連表更新
UPDATE huc_user huser
inner join hb_t_iu iu on huser.mobile_no = iu.tel
SET huser.gender = iu.gender
5、取餘數
mod(m,n)
m是被取餘的數,n是模
6、計算datetime類型日期和當前時間天數
TIMESTAMPDIFF(YEAR, huser.birth_time, now())
需要注意的是,兩個日期之間的位置和計算規則,第一個時間是beginTime,後一個是endTime,beginTime數值上要比endTime小,否則會出現負數,第一個參數是Unit,取值可以有:
MICROSECOND 微秒
SECOND 秒
MINUTE 分鐘
HOUR 小時
DAY 天
WEEK 星期
MONTH 月
QUARTER 季度
YEAR 年
7、Navicate導出數據時某個字段被處理成無規則串?
查看這個字段類型,longtext有這種情況,使用cast(field as char)轉換一下即可。
8、mysql between and使用
between and 的左右邊界是閉合的,但是在處理時間時需要注意,如果是datetime類型,且入參沒有時間時,時間默認爲00:00:00,如:
select * from t_x where created_time between '2020-01-01' and '2020-01-01';
這樣兩個時間都會是2020-01-01 00:00:00,這樣很可能跟你的預期不符合。
9 trur flase含義
mysql中boolean用tinyint(1)實現,true=1,false=2
select true + 1 // 2
10 mysql varchar 和int比較
2ABC3 =2 // true
2abc > 1 // true
mysql會把字符串類型轉換成數字,從第一個字符開始解析,到第一個字符不符合結束
11 count()和sum()
count(expression) 函數,注意入參是表達式
sum(expression) 函數,入參也是表達式
count(*)=count(1) // 統計行數,不管字段是否爲空
count(field) // 字段爲null的會被排除,空串和空白字符依然被計算
sum(field) // 數值類型沒什麼,如果field是varchar,如果存了實數也沒什麼,如果存了非實數字符串,會被解析成0
sum(2) // 是每一列都是2來相加
sum(field=2) // 表達式成立就是true也即1
count(var=2) // 表達式沒有意義了,true或false結果都一樣
12 彙總
select ifnull(a,彙總),count(*) group by a with rollup // 就是彙總
13 一對多連接去重
怎麼處理?
14 查詢表的所有字段
show full columns from t;
15 查詢一張表所有字段飽和度?
16 group by 沒有的字段需要返回?
當查詢簡單時,可以通過構建臨時表完成如:select x union select y union select z構建一個臨時結果作爲主表,但是關聯的表過多時,比如需要通過能關聯上另一張表作爲選中的結果並計算合計,這樣就很難操作了,只能在Java中操作,如何操作,定義一個final List,然後遍歷,將查詢結果集轉換成map,然後構建一個新List返回,這樣即可以填充沒有的字段,還能保證順序,其中List轉Map需要我們掌握。
17 編碼選擇
2、關於字段編碼選擇,有個同事建立的某張表使用了不同的字符編碼,導致大小寫敏感了,相關字段索引也無法使用。mysql字符集默認的編碼查詢:show charset;
如果指定了表的字符集,那麼字段的字符編碼就是默認的了,其中utf8mb4_bin大小寫敏感,使用時注意。
18 date_format()的迷惑點
select DATE_FORMAT('2020-09','%Y-%m') // 輸出null
這種用法有可能出現在前端傳參和已有字段比較的情況,爲什麼輸出null,因爲date_format接受的第一個參數類型是date,至少要有年月日,這裏只有年月,不被認爲是日期,所以格式化無效,直接輸出null,使用的時候需要警惕。
19 MySQL數據庫約束
約束(constraint),使用來保證數據庫中數據完整性(實體完整性(Entity Integrity)、域完整性(Domain Integrity)、參照完整性(Referential Integrity)、用戶定義的完整性(User-definedIntegrity))的手段之一。
MySQL中常用的約束:
約束類型: | 主鍵 | 外鍵 | 唯一 | 非空 | 自增 | 默認值 |
---|---|---|---|---|---|---|
關鍵字: | primary key | foreign key |
unique |
not null |
auto_increment |
default |
primary key = unique + not null
使用方式如下:
ALTER TABLE `zz` ADD PRIMARY KEY ( `id` ) // 添加主鍵,不需要給主鍵起名字
ALTER TABLE `zz` DROP PRIMARY KEY // 刪主鍵,主鍵不需要名稱,因爲只有一個,此字段不能有自增屬性,否則刪不了。
ALTER TABLE zz ADD CONSTRAINT fk_prod_id FOREIGN KEY (product_id) REFERENCES product (id); // 添加外鍵
ALTER TABLE `zz` DROP FOREIGN KEY `fk_prod_id`; // 刪除外鍵
ALTER TABLE zz ADD UNIQUE KEY uk_2(name,product_id); // 添加唯一約束
ALTER TABLE zz ADD UNIQUE uk_2 (NAME, product_id); // 添加唯一約束可以省略 KEY關鍵字
ALTER TABLE zz ADD CONSTRAINT UNIQUE uk_2 (NAME, product_id); // 添加唯一約束多加一個constraint關鍵字也行
ALTER TABLE zz DROP INDEX uk_2; // 刪除唯一約束,注意這裏已經變成index了
ALTER TABLE zz MODIFY product_id VARCHAR (12) NOT NULL; // 添加非空約束
ALTER TABLE zz MODIFY product_id VARCHAR (12) NULL; // 刪除非空約束
MySQL表中只能設置一個自增長字段【必須是key(其他普通字段不行))】
ALTER TABLE zz MODIFY product_id INT UNSIGNED AUTO_INCREMENT; // 添加自增
ALTER TABLE zz MODIFY product_id INT UNSIGNED;// 刪除自增
20 常用表結構修改
修改字段編碼使支持emoji表情
ALTER TABLE t_user MODIFY `signature` VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '';
添加單個或多個字段索引
ALTER TABLE table_name ADD INDEX index_name (column_list)
ALTER TABLE table_name ADD UNIQUE (column_list)
ALTER TABLE table_name ADD PRIMARY KEY (column_list)
主鍵一定是索引,索引未必是主鍵,複合主鍵一定建立複合索引,複合主鍵不能重複,每個鍵都不能爲空。
聯合主鍵:指多張表的主鍵組合,多半出現在多對多時的中間表上
複合主鍵:一張表中多個字段組成primary key,一張表只能有一個主鍵,主鍵分爲單一主鍵和複合主鍵
添加字段
ALTER TABLE xxx_yy ADD terminal_type tinyint (2) unsigned DEFAULT '0' COMMENT '註釋';
21 case when 2種用法
-- 簡單case函數
case sex
when '1' then '男'
when '2' then '女’
else '其他' end
-- case搜索函數
case when sex = '1' then '男'
when sex = '2' then '女'
else '其他' end
需要注意的是case when搜索函數和 else if功效一樣,當前的滿足了,就不會進行下面的判斷了,使用時需要注意這一點。
22 關於連接
1 連接基礎
left join = left outer join
right join = right outer join
inner join = join
full join = full outer join(left join + right join)
對於left join,條件寫在on後面和where後面是有區別的,寫在on後的不會影響主表記錄,哪怕條件是關於主表的,寫在where後面的條件是針對連接後的結果集,可以影響到主表記錄。如:
SELECT
u.NAME,
ur.role_id
FROM
user_cn u
LEFT JOIN user_role ur ON u.id = ur.user_id AND u.NAME = '張飛' // 這裏的u條件不會影響主表
2 多表連接
SELECT
u. NAME,
r.role_name
FROM
user_cn u
LEFT JOIN user_role ur ON u.id = ur.user_id
INNER JOIN role r ON ur.role_id = r.id
可以看到,多表連接後,如果有left join和inner join同時出現,那麼inner join的排除效果就會體現到主表上了,連接順序對結果是沒有影響的,我們可以看成是inner join和前面所有連接結果再進行運算,那麼自然就會排除。看這種複雜連接關係,可以先分清對應關係,這裏u對ur是一對多(u和ur是多對多),ur對r是一對一。