CREATE TABLE `t2` ( `id` int(11) NOT NULL, `gid` char(1) DEFAULT NULL, `col1` int(11) DEFAULT NULL, `col2` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; insert into t2 values (1,'A',31,6), (2,'B',25,83), (3,'C',76,21), (4,'D',63,56), (5,'E',3,17), (6,'A',29,97), (7,'B',88,63), (8,'C',16,22), (9,'D',25,43), (10,'E',45,28), (11,'A',2,78), (12,'B',30,79), (13,'C',96,73), (14,'D',37,40), (15,'E',14,86), (16,'A',32,67), (17,'B',84,38), (18,'C',27,9), (19,'D',31,21), (20,'E',80,63), (21,'A',89,9), (22,'B',15,22), (23,'C',46,84), (24,'D',54,79), (25,'E',85,64), (26,'A',87,13), (27,'B',40,45), (28,'C',34,90), (29,'D',63,8), (30,'E',66,40), (31,'A',83,49), (32,'B',4,90), (33,'C',81,7), (34,'D',11,12), (35,'E',85,10), (36,'A',39,75), (37,'B',22,39), (38,'C',76,67), (39,'D',20,11), (40,'E',81,36);
-- 方法1: select * from t2 as a where not exists (select 1 from t2 where gid=a.gid and col2>a.col2); -- 1. select 1 from t2 where gid=a.gid and col2>a.col2 : select就進入了隱式迭代,同組中比當前col2大的就輸出1; -- 2. 而後not exists來判斷是否存在比當前col2大的,若是不存在就返回true;返回true就輸出當前col2這一列; -- 3. 這裏的exists與not exists是判斷語句,返回的是true or false; -- 方法2: select * from (select * from t2 order by gid,col2 desc) as t group by gid; -- t2按照gid和col2來降序排列,而後group分組,分組就取的是frist row,而frist row就是最大的值; -- 乍看之下貌似不用自鏈接也能夠搞定,可是group by分組是不能放在order by以後的,不然就會報錯;
select * from t2 as a where 3 > (select count(*) from t2 where gid=a.gid and col2>a.col2) order by a.gid,a.col2 desc; -- 比當前col2大的值若是小於三條就輸出(注意必須是小於三條,若是等於三條就表明已經有了三條),而後輸出後排序;
上面兩條自鏈接sql都比較難理解,但只要換個角度,其實理解起來也很容易,首先在mysql中要把select翻譯爲輸出,而且要知足where之後才輸出;輸出之後再分組,分組之後才輪到排序,排序以後才輪到取幾個
經過join,mysql能夠作到集合中的求交集,並集,差集等需求,但比起相似redis等集合來講,效率差了不止一個級別了;
數據準備mysql
-- 建立數據表 CREATE TABLE IF NOT EXISTS tdb_goods( goods_id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, goods_name VARCHAR(150) NOT NULL, goods_cate VARCHAR(40) NOT NULL, brand_name VARCHAR(40) NOT NULL, goods_price DECIMAL(15,3) UNSIGNED NOT NULL DEFAULT 0, is_show BOOLEAN NOT NULL DEFAULT 1, is_saleoff BOOLEAN NOT NULL DEFAULT 0 )ENGINE=MyISAM AUTO_INCREMENT=24 DEFAULT CHARSET=utf8 COMMENT='測試商品表'; -- 寫入記錄 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('R510VC 15.6英寸筆記本','筆記本','華碩','3399',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('Y400N 14.0英寸筆記本電腦','筆記本','聯想','4899',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('G150TH 15.6英寸遊戲本','遊戲本','雷神','8499',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('X550CC 15.6英寸筆記本','筆記本','華碩','2799',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('X240(20ALA0EYCD) 12.5英寸超極本','超級本','聯想','4999',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('U330P 13.3英寸超極本','超級本','聯想','4299',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('SVP13226SCB 13.3英寸觸控超極本','超級本','索尼','7999',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('iPad mini MD531CH/A 7.9英寸平板電腦','平板電腦','蘋果','1998',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('iPad Air MD788CH/A 9.7英寸平板電腦 (16G WiFi版)','平板電腦','蘋果','3388',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES(' iPad mini ME279CH/A 配備 Retina 顯示屏 7.9英寸平板電腦 (16G WiFi版)','平板電腦','蘋果','2788',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('IdeaCentre C340 20英寸一體電腦 ','臺式機','聯想','3499',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('Vostro 3800-R1206 臺式電腦','臺式機','戴爾','2899',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('iMac ME086CH/A 21.5英寸一體電腦','臺式機','蘋果','9188',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('AT7-7414LP 臺式電腦 (i5-3450四核 4G 500G 2G獨顯 DVD 鍵鼠 Linux )','臺式機','宏碁','3699',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('Z220SFF F4F06PA工做站','服務器/工做站','惠普','4288',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('PowerEdge T110 II服務器','服務器/工做站','戴爾','5388',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('Mac Pro MD878CH/A 專業級臺式電腦','服務器/工做站','蘋果','28888',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES(' HMZ-T3W 頭戴顯示設備','筆記本配件','索尼','6999',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('商務雙肩揹包','筆記本配件','索尼','99',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('X3250 M4機架式服務器 2583i14','服務器/工做站','IBM','6888',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('玄龍精英版 筆記本散熱器','筆記本配件','九州風神','',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES(' HMZ-T3W 頭戴顯示設備','筆記本配件','索尼','6999',DEFAULT,DEFAULT); INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('商務雙肩揹包','筆記本配件','索尼','99',DEFAULT,DEFAULT);
table1 {[INNER|CROSS]JOIN|{LEFT|RIGHT}[OUTER]JOIN} table2 ON conditional_expr ... {[INNER|CROSS]JOIN|{LEFT|RIGHT}[OUTER]JOIN} tablen ON conditional_expr
JOIN 按照功能大體分爲以下三類:web
-- ↓↓把單表更新的table換成了關聯在一塊兒的table UPDATE tdb_goods AS g JOIN tdb_goods_brands AS b ON g.brand_name = b.brand_name JOIN tdb_goods_cates AS c ON g.goods_cate = c.cate_name SET g.brand_name = b.brand_id, g.goods_cate = c.cate_id; -- ↓↓因爲把原來的品牌名和分類名更換爲了id,因此相應的字段名稱和類型要有所改變 ALTER TABLE tdb_goods CHANGE brand_name brand_id TINYINT NOT NULL DEFAULT 0, CHANGE goods_cate cate_id TINYINT NOT NULL DEFAULT 0; DESC tdb_goods;
-- 內鏈接 SELECT * FROM tdb_goods AS g JOIN tdb_goods_cates AS c ON g.cate_id = c.cate_id JOIN tdb_goods_brands AS b ON g.brand_id = b.brand_id; -- 左鏈接 SELECT * FROM tdb_goods AS g LEFT JOIN tdb_goods_cates AS c ON g.cate_id = c.cate_id LEFT JOIN tdb_goods_brands AS b ON g.brand_id = b.brand_id;
-- 查找出重複記錄; SELECT goods_id,goods_name FROM tdb_goods GROUP BY goods_name HAVING count(goods_name) >= 2; -- 進行刪除 DELETE t1 FROM tdb_goods AS t1 JOIN (SELECT goods_id,goods_name FROM tdb_goods GROUP BY goods_name HAVING count(goods_name) >= 2 ) AS t2 ON t1.goods_name = t2.goods_name WHERE t1.goods_id > t2.goods_id; -- 注意,單表的刪除在delete後面不用加上表名,但多表必定要加,不然會報語法錯誤; -- 如何理解這條sql語句? 首先把t1和t2關聯一塊兒;而後把t1全刪除;也就是說把符合另一張表關聯條件的本表給刪掉;
交叉鏈接,獲得的結果是兩個表的乘積redis
select * from tdb_goods,tdb_goods_brands; -- tdb_goods表23條數據,tdb_goods_brands有10條數據,笛卡爾之後就出現23*10條數據; select * from tdb_goods as g join tdb_goods_brands as b; -- join在沒有on條件的時候也是笛卡爾乘積;
mysql裏面沒有Full join,只有union;若是要使用union的話,被union的表的結構要同樣才能並在一塊兒;sql
-- 先查出1101的評論,再查出1101所關注的人的評論; SELECT * FROM `comment` WHERE user_id = 1101 UNION SELECT * FROM `comment` WHERE user_id IN (select follow_user_id from follow where user_id = 1101);
以往作PHP+MYSQL的web應用時,從未用過外鍵,但即便如此,外鍵仍是頗有必要的,它能是多表之間的關聯更嚴格,可以達到一致性的需求;
若是不用外鍵約束的話,在多表關聯的應用場景中,咱們插入一條數據,該條數據只要知足語法規範既可插入,但若是使用了外鍵,該語句還要同時知足當前外鍵在關聯的表中是否存在;服務器
使用外鍵要知足如下條件:測試
語法翻譯
[CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name, ...) REFERENCES tbl_name (index_col_name,...) [ON DELETE reference_option] [ON UPDATE reference_option] reference_option: RESTRICT | CASCADE | SET NULL | NO ACTION
若是子表試圖建立一個在父表中不存在的外鍵值,InnoDB會拒絕任何INSERT或UPDATE操做。若是父表試圖UPDATE或者DELETE任何子表中存在或匹配的外鍵值,最終動做取決於外鍵約束定義中的ON UPDATE和ON DELETE選項。InnoDB支持5種不一樣的動做,若是沒有指定ON DELETE或者ON UPDATE,默認的動做爲RESTRICT:設計
上文中的父表是指被參照的表;
外鍵約束使用最多的狀況無外乎:code
InnoDB容許你使用ALTER TABLE在一個已經存在的表上增長一個新的外鍵:排序
ALTER TABLE tbl_name ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name, ...) REFERENCES tbl_name (index_col_name,...) [ON DELETE reference_option] [ON UPDATE reference_option]
也支持
ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;
Example
CREATE TABLE `test1` ( `goods_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, `goods_name` varchar(150) NOT NULL, `brand_id` smallint(5) unsigned NOT NULL DEFAULT '0', `goods_price` decimal(15,3) unsigned NOT NULL DEFAULT '0.000', PRIMARY KEY (`goods_id`), KEY `brand_id` (`brand_id`), FOREIGN KEY (`brand_id`) REFERENCES `test2` (`brand_id`) -- test1的brand_id必須和test2同樣,包括類型,長度,是否有符號,才能建立外鍵; -- 建立完以後FOREIGN KEY...這sql就會自動變爲:CONSTRAINT `test1_ibfk_1` FOREIGN KEY (`brand_id`) REFERENCES `test2` (`brand_id`) -- 若是不加任何ON DELETE reference_option語句的話,默認就是NO ACTION,也就是說,父表test2更新和刪除,只准增長; -- 若是加上ON DELETE CANSCADE和ON UPDATE CANSCADE的話,test2刪除和更新都會影響到test1; ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='索引測試test1'; CREATE TABLE `test2` ( `brand_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, `brand_name` varchar(40) NOT NULL, PRIMARY KEY (`brand_id`), ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='索引測試test2';
mysql> insert into test1(goods_name,brand_id) values('i phone 1',6); 1452 - Cannot add or update a child row: a foreign key constraint fails (`test`.`test1`, CONSTRAINT `test1_ibfk_1` FOREIGN KEY (`brand_id`) REFERENCES `test2` (`brand_id`)) -- 沒有參照不能插入 mysql> delete from test2 where brand_id=1; 1451 - Cannot delete or update a parent row: a foreign key constraint fails (`test`.`test1`, CONSTRAINT `test1_ibfk_1` FOREIGN KEY (`brand_id`) REFERENCES `test2` (`brand_id`)) -- NO ACTION,凡是test1已經關聯上的test2的row都不能被刪除;保持數據的一致性;沒關聯上能夠被刪除,雖然是no action;
表的設計是無限極的設計方式,但mysql搞不了遞歸,只能實現一級;
數據準備
CREATE TABLE tdb_goods_types( type_id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, type_name VARCHAR(20) NOT NULL, parent_id SMALLINT UNSIGNED NOT NULL DEFAULT 0 )ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='無限極分類表';; INSERT tdb_goods_types(type_name,parent_id) VALUES('家用電器',DEFAULT); INSERT tdb_goods_types(type_name,parent_id) VALUES('電腦、辦公',DEFAULT); INSERT tdb_goods_types(type_name,parent_id) VALUES('你們電',1); INSERT tdb_goods_types(type_name,parent_id) VALUES('生活電器',1); INSERT tdb_goods_types(type_name,parent_id) VALUES('平板電視',3); INSERT tdb_goods_types(type_name,parent_id) VALUES('空調',3); INSERT tdb_goods_types(type_name,parent_id) VALUES('電風扇',4); INSERT tdb_goods_types(type_name,parent_id) VALUES('飲水機',4); INSERT tdb_goods_types(type_name,parent_id) VALUES('電腦整機',2); INSERT tdb_goods_types(type_name,parent_id) VALUES('電腦配件',2); INSERT tdb_goods_types(type_name,parent_id) VALUES('筆記本',9); INSERT tdb_goods_types(type_name,parent_id) VALUES('超級本',9); INSERT tdb_goods_types(type_name,parent_id) VALUES('遊戲本',9); INSERT tdb_goods_types(type_name,parent_id) VALUES('CPU',10); INSERT tdb_goods_types(type_name,parent_id) VALUES('主機',10);
實現分類
SELECT t1.type_id, t1.type_name AS parent_name, t2.type_name, t2.parent_id FROM `tdb_goods_types` AS t1 JOIN tdb_goods_types AS t2 ON t1.type_id = t2.parent_id;