目錄
replace into 用法(insert into 的增強版)
跟insert into功能類似
replace into 首先嚐試插入數據到表中,
- 如果發現表中已經有此行數據(根據主鍵或者唯一索引判斷)則先刪除此行數據,然後插入新的數據。
- 否則,直接插入新數據。
要注意的是:插入數據的表必須有主鍵或者是唯一索引!否則的話,replace into 會直接插入數據,這將導致表中出現重複的數據。
MySQL replace into 有三種形式:
replace into tbl_name(col_name, ...) values(...)
replace into tbl_name(col_name, ...) select ...
replace into tbl_name set col_name=value, ...
INSERT INTO ... ON DUPLICATE KEY UPDATE
在INSERT語句末尾指定了ON DUPLICATE KEY UPDATE,並且插入行後會導致在一個UNIQUE索引或PRIMARY KEY中出現重複值,則在出現重複值的行執行UPDATE;如果不會導致唯一值列重複的問題,則插入新行。
情景:
實時數據的更新,如果有新的渠道則插入數據,如果渠道數據已經存在,則更新數據,如果是新增數據,則直接覆蓋,如果是時長和次留數據就需要累加更新
方法一:
replace into tablename (f1, f2, f3) values(vf1, vf2, vf3),(vvf1, vvf2, vvf3)
自動查詢主鍵或唯一索引衝突,如有衝突,會先刪除原有的數據記錄,然後執行插入新的數據,影響行數2
對於不能覆蓋的數據此方法不適用
方法二
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
在insert時判斷是否已有主鍵或唯一索引重複,如果有,一句update後面的表達式執行更新,否則,執行插入
性能分析
在數據庫數據量很少的時候, 這兩種方式都很快
在數據量大的時候,replace的操作要比insert on duplicate的操作低太多太多,
replace慢的原因,在更新數據的時候,要先刪除舊的,然後插入新的,在這個過程中,還要重新維護索引,所以速度慢
insert on duplicate 的更新操作雖然也會更新數據,但其對主鍵的索引卻不會有改變,也就是說,insert on duplicate 更新對主鍵索引沒有影響.因此對索引的維護成本就低了一些
示例:
INSERT INTO `new_duration` (`channel_name`, `date`, `channel_id`, `u_19`, `click`, `imei_new`, `android_new`, `oaid_new`, `ip_new`, `d_15`, `launch`)
VALUES ('qm-gdtsdmpjc2_lf', '2019-12-26', 13792, 1, 0, 1, 0, 0, 0, 1200, 12)
ON DUPLICATE KEY UPDATE
`u_19`=VALUES(`u_19`) ,`d_15`= `d_15`+VALUES(`d_15`), `launch`= `launch`+VALUES(`launch`), `click`=0,`imei_new`=1,`android_new`=0,`ip_new`=0,`oaid_new`=0;
case when then else end
Case具有兩種格式。簡單Case函數和Case搜索函數。
--簡單Case函數
CASE sex
WHEN '1' THEN '男'
WHEN '2' THEN '女'
ELSE '其他' END
--Case搜索函數
CASE WHEN sex = '1' THEN '男'
WHEN sex = '2' THEN '女'
ELSE '其他' END
/*
CREATE TABLE `dmp_history_channel_version_event_uid_20190717` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`channel` varchar(50) NOT NULL COMMENT '渠道',
`action` varchar(100) NOT NULL COMMENT '事件',
`uid` varchar(100) NOT NULL COMMENT '用戶id',
`hitnum` int(11) DEFAULT NULL COMMENT '點擊數',
PRIMARY KEY (`id`,`action`),
KEY `uid` (`uid`),
KEY `channel` (`channel`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
/*!50100 PARTITION BY KEY (`action`)
PARTITIONS 1024 */;
INSERT INTO `dmp_history_channel_version_event_uid_20190717` VALUES (2, 'a', 'b', '1', 100);
INSERT INTO `dmp_history_channel_version_event_uid_20190717` VALUES (1, 'a', 'a', '1', 10);
*/
SELECT
SUM(CASE WHEN action in('a','b') THEN hitnum ELSE 0 END) as ad_click
FROM dmp_history_channel_version_event_uid_20190717
TO_DAYS、 FROM_DAYS
TO_DAYS(date)給出一個日期 date,返回一個天數(從 0 年開始的天數):
SELECT TO_DAYS('2020-01-01');
+-----------------------+
| TO_DAYS('2020-01-01') |
+-----------------------+
| 737790 |
+-----------------------+
1 row in set (0.00 sec)
FROM_DAYS 跟TO_DAYS相反的過程
SELECT FROM_DAYS(737790);
+-------------------+
| FROM_DAYS(737790) |
+-------------------+
| 2020-01-01 |
+-------------------+
1 row in set (0.00 sec)
常用來劃分分區:
CREATE TABLE my_range_datetime(
id INT,
hiredate DATETIME
)
PARTITION BY RANGE (TO_DAYS(hiredate) ) (
PARTITION p1 VALUES LESS THAN ( TO_DAYS('20171202') ),
PARTITION p2 VALUES LESS THAN ( TO_DAYS('20171203') ),
PARTITION p3 VALUES LESS THAN ( TO_DAYS('20171204') ),
PARTITION p4 VALUES LESS THAN ( TO_DAYS('20171205') ),
PARTITION p5 VALUES LESS THAN ( TO_DAYS('20171206') ),
PARTITION p6 VALUES LESS THAN ( TO_DAYS('20171207') ),
PARTITION p7 VALUES LESS THAN ( TO_DAYS('20171208') ),
PARTITION p8 VALUES LESS THAN ( TO_DAYS('20171209') ),
PARTITION p9 VALUES LESS THAN ( TO_DAYS('20171210') ),
PARTITION p10 VALUES LESS THAN ( TO_DAYS('20171211') ),
PARTITION p11 VALUES LESS THAN (MAXVALUE)
);
-- MAXVALUE是一個無窮大的值
INSERT INTO SELECT
一個表的查詢字段作爲另一個表的寫入
INSERT INTO db1_name (field1,field2) SELECT field1,field2 FROM db2_name