014.科普.有生產力的Sql語句


題圖:Intel Corp. President Andy Grove, right, shakes hands with Microsoft Chairman Bill Gates at a meeting in Burlingame, Ca., on Monday Nov. 9, 1992, as they team up to offer a new product of videos on personal computers.html

014.科普.有生產力的Sql語句

不等不靠,有囧有料。終日乾乾,或躍在淵。java

若是,咱們作足了一些細節,敲出不夠爛的代碼,
那麼,很多企業就會倒閉,信息化建設就會倒退。mysql

若是,咱們作不足一些細節,依賴於流水線。
那麼,高效生產的同時,咱們會退化爲碼工。sql

@史榮久 / 2015-03-27 / CC-BY-SA-3.0ubuntu

觀看視頻

內容摘要

  • 安迪-比爾定律(Andy and Bill’s Law)
  • 依賴於框架流水線,咱們會從手藝人退化爲流水線上的碼工
  • 解釋和部分解決Mysql的order-by-limit巨慢
  • 分頁問題,引伸出的sublist,substring
  • 一條語句,顯示學生所選的課程:GROUP_CONCAT
  • 各GROUP的TOP-N問題(分組內,各取前N個)
  • 自增主鍵是個坑,儘可能避免(尤爲分佈式)
  • 大量插入(bulk insert),VALUES
  • 插入忽略:INSERT IGNORE
  • 插入更新:ON DUPLICATE KEY UPDATE(有bug變的特性)
  • 替換插入:REPLACE INTO
  • 大量刪除:DELETE & TRUNCATE(索引,事務,自增)
  • 多表聯合刪除,子查詢刪除,快速刪除
  • 關聯更新:單個字段,多個字段
  • 執行計劃:explain,其餘優化
  • 創建索引:根據sql和explain創建必要的索引
  • JDBC: PreparedStatement(DML) vs Statement(DDL)
  • JDBC: addBatch, executeBatch 的性能
  • JDBC: allowMultiQueries,maxAllowedPacket 安全和速度

參考資源

歡迎圍觀

if (you.accept(MoilionCircle.SPIRIT)) {
    if(you.haveADL()){
        MoilionCircle we = you.search(MoilionCircle.SLOGAN);
        we.welcome(you);
    }
    if(you.share(this)){
        We.thank(you);
        We.mayFind7Moilion();
    }
}

測試SQL

select version();
-- 5.5.41-0ubuntu0.14.04.1

-- 建庫
DROP DATABASE IF EXISTS `moilioincircle_r014`;
CREATE DATABASE `moilioincircle_r014` 
DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
USE moilioincircle_r014;

-- 建表
DROP TABLE IF EXISTS `STUDENT`;
CREATE TABLE `STUDENT` (
    `ID` int(11) NOT NULL,
    `NAME` varchar(45) NOT NULL,
    `GENDER` int(11) NOT NULL DEFAULT '1',
    PRIMARY KEY (`ID`)
)  ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

DROP TABLE IF EXISTS `COURSE`;
CREATE TABLE `COURSE` (
  `ID` int(11) NOT NULL,
  `NAME` varchar(45) COLLATE utf8_bin NOT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE KEY `NAME_UNIQUE` (`NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

DROP TABLE IF EXISTS `STUDENT_COURSE_MAP`;
CREATE TABLE `STUDENT_COURSE_MAP` (
  `STUDENT_ID` int(11) NOT NULL,
  `COURSE_ID` int(11) NOT NULL,
  PRIMARY KEY (`STUDENT_ID`,`COURSE_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

DROP TABLE IF EXISTS `EXAM`;
CREATE TABLE `EXAM` (
  `STUDENT_ID` int(11) NOT NULL,
  `COURSE_ID` int(11) NOT NULL,
  `SCORE` int(11) NOT NULL,
  PRIMARY KEY (`STUDENT_ID`,`COURSE_ID`),
  KEY `IDX_SCORE` (`SCORE`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

DROP TABLE IF EXISTS `AUTOINCR`;
CREATE TABLE `AUTOINCR` (
    `ID` int(11) NOT NULL AUTO_INCREMENT,
    `NAME` varchar(45),
    PRIMARY KEY (`ID`)
)  AUTO_INCREMENT = 100
ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

-- 數據
INSERT INTO STUDENT (ID,NAME,GENDER)
VALUES
(1,'學生1',2),
(2,'學生2',1),
(3,'學生3',NULL),
(4,'學生4',DEFAULT);

INSERT INTO COURSE (ID,NAME) 
VALUES
(1,'課程1'),
(2,'課程2'),
(3,'課程3'),
(4,'課程4');

INSERT INTO STUDENT_COURSE_MAP (STUDENT_ID,COURSE_ID) 
VALUES
(1,1),
(2,1),(2,2),
(3,1),(3,2),(3,3),
(4,1),(4,2),(4,3),(4,4);

INSERT INTO EXAM (STUDENT_ID,COURSE_ID,SCORE) 
VALUES
(1,1,90),(1,2,70),(1,3,85),(1,4,80),
(2,1,70),(2,2,85),(2,3,75),(2,4,80),
(3,1,75),(3,2,85),(3,3,85),(3,4,65),
(4,1,60),(4,2,75),(4,3,80),(4,4,85);

INSERT INTO AUTOINCR (ID,NAME) 
VALUES
(1,'自增1'),
(DEFAULT,'自增#1'),
(5,'自增5'),
(DEFAULT,'自增#2');

-- 查 -----------------

-- 學生都選了什麼課(把列換成行顯示)
-- set group_concat_max_len=10000;
SELECT 
    S.NAME,
    GROUP_CONCAT(C.NAME ORDER BY C.NAME ) AS COURSES
FROM 
    STUDENT AS S,
    COURSE AS C,
    STUDENT_COURSE_MAP AS M
WHERE 
    S.ID = M.STUDENT_ID
    AND C.ID = M.COURSE_ID
GROUP BY S.NAME
HAVING COUNT(C.NAME)>1;

-- 把各科考試,前三名取出來。
-- MYSQL 沒有 ROW_NUMBER() OVER(PARTITION BY A ORDER BY B DESC)
SELECT 
    C.NAME AS COURSE, 
    S.NAME AS STUDENT, 
    E.SCORE 
FROM 
    EXAM AS E ,
    STUDENT AS S,
    COURSE AS C
WHERE 
    (SELECT COUNT(*) FROM EXAM AS B 
        WHERE B.COURSE_ID = E.COURSE_ID 
        AND B.SCORE >= E.SCORE
    ) <= 3 
    AND E.STUDENT_ID = S.ID
    AND E.COURSE_ID = C.ID
ORDER BY COURSE ASC, SCORE DESC;

SELECT * FROM STUDENT 
WHERE (ID,NAME) IN ((1,'學生1'),(2,'學生2'));

-- ------- 增 ----------
SELECT * FROM COURSE;

INSERT IGNORE INTO COURSE (ID,NAME) 
VALUES 
(1,'課程1'),
(11,'課程1'),
(5,'課程5'),
(6,'課程6');

REPLACE INTO COURSE (ID,NAME) 
VALUES 
(5,'課程55'),
(66,'課程6'),
(7,'課程7');

INSERT INTO COURSE (ID,NAME) 
VALUES (5,'課程5'),(6,'課程6'),(8,'課程6')
ON DUPLICATE KEY UPDATE
    NAME=VALUES(NAME),ID=VALUES(ID);

INSERT INTO COURSE (ID,NAME) 
VALUES (5,'課程5'),(6,'課程6'),(7,'課程7')
ON DUPLICATE KEY UPDATE
    NAME=VALUES(NAME),
    ID=(CASE WHEN NAME = VALUES(NAME)
        THEN VALUES(ID)
        ELSE ID
        END);

-- 刪
CREATE TABLE AUTOINCR_1 LIKE AUTOINCR; -- 表結構相同
INSERT INTO AUTOINCR_1 SELECT * FROM AUTOINCR;
DESCRIBE AUTOINCR_1;

CREATE TABLE AUTOINCR_2 SELECT * FROM AUTOINCR WHERE ID <10; -- 不相同
DESCRIBE AUTOINCR_2;

SELECT * FROM AUTOINCR_1;
SELECT * FROM AUTOINCR_2;

DELETE FROM AUTOINCR_1;
INSERT INTO AUTOINCR_1 (NAME) VALUES ('課程1');
TRUNCATE TABLE AUTOINCR_1;

DELETE T1,T2 
FROM AUTOINCR_1 AS T1,AUTOINCR_2 AS T2
WHERE T1.ID = T2.ID;

DELETE QUICK FROM AUTOINCR_2;
OPTIMIZE TABLE AUTOINCR_2;

-- 改 ------
INSERT INTO AUTOINCR_1 SELECT ID,NULL FROM AUTOINCR;
INSERT INTO AUTOINCR_2 SELECT * FROM AUTOINCR WHERE ID <10;

-- 更新單個字段
UPDATE AUTOINCR_2 AS T2, AUTOINCR_1 AS T1
SET T1.NAME = T2.NAME 
WHERE T2.ID = T1.ID;

UPDATE AUTOINCR_1 SET NAME=NULL;
UPDATE AUTOINCR_1 AS T1
SET T1.NAME = (SELECT T2.NAME FROM AUTOINCR_2 AS T2 WHERE T2.ID = T1.ID);

CREATE TABLE STUDENT_1 LIKE STUDENT;
INSERT INTO STUDENT_1 SELECT ID,CONCAT(NAME,'#'),0 FROM STUDENT;

SELECT * FROM STUDENT;
SELECT * FROM STUDENT_1;

-- 更新多個字段
UPDATE STUDENT_1 AS T1
INNER JOIN (SELECT T.ID, T.NAME,  T.GENDER FROM STUDENT AS T) AS T2 
ON T2.ID = T1.ID
SET T1.NAME = T2.NAME ,T1.GENDER = T2.GENDER;
相關文章
相關標籤/搜索