mysql高級用法

replace into 用法(insert into 的增強版)

跟insert into功能類似

replace into 首先嚐試插入數據到表中,

  1. 如果發現表中已經有此行數據(根據主鍵或者唯一索引判斷)則先刪除此行數據,然後插入新的數據。
  2. 否則,直接插入新數據。

要注意的是:插入數據的表必須有主鍵或者是唯一索引!否則的話,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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章