MySQL之——基本操作彙總
阿新 • • 發佈:2019-01-06
本文記錄了MySQL的一些常用操作,不多說了,直接一一列出:
/* Author: liuyazhuang Date:2016-04-12 */ use test; DROP table if exists equipment; create table equipment( assetTag INTEGER primary key, description varchar(20), acquired Date ); /*資料表插入語句*/ INSERT INTO equipment values (50431,'21寸監視器', DATE '2013-01-23'); INSERT INTO equipment values (50532,'pad', DATE '2013-01-26'); /*資料表增加新的列,並初始化*/ ALTER Table equipment ADD COLUMN office VARCHAR(20); UPDATE equipment SET office='Headquarters'; /*向修改後的表中插入記錄*/ INSERT INTO equipment(assetTag,description,acquired) values (50432,'IBM-PC',DATE '2013-01-01'); /*建立代替表的新表(複製)*/ DROP TABLE if EXISTS equipmentMultiSite; CREATE TABLE equipmentMultiSite( assetTag INTEGER PRIMARY KEY, office varchar(20) DEFAULT 'Headquarters', description varchar(20), acquired DATE ); INSERT INTO equipmentMultiSite SELECT assetTag,'Headquarters',description,acquired FROM equipment; /*刪除現有equipment用檢視代替*/ DROP TABLE equipment; CREATE VIEW equipment AS SELECT assetTag,description,acquired 'dateAcquired', FROM equipment WHERE office='Headquarters'; /*基礎的查詢*/ select sum(amount) from payment where customer_id=1; /*某顧客從開戶以來的消費總額*/ select count(*) from payment where customer_id=1; /*某顧客從開戶以來的消費次數*/ /*查詢某顧客在2005年5月份和6月份消費總額,用"between”或者"<",">"來建立條件*/ select sum(amount) from payment where customer_id=1 and extract(year from payment_date)=2005 and extract(month from payment_date) between 05 and 06; select sum(amount) from payment where customer_id=1 and payment_date >= '2005-05-01 00:00:00' and payment_date < '2005-07-01 00:00:00'; /*下面用法報警了*/ select sum(amount) from payment where customer_id=1 and payment_date > UNIX_TIMESTAMP('2005-05-01 00:00:00') and payment_date < UNIX_TIMESTAMP('2005-07-01 00:00:00'); /*查詢某顧客在2005年一年的總消費*/ select sum(amount) from payment where customer_id=1 and extract(year from payment_date)=2005; select sum(amount) from payment where customer_id=1 and extract(year from payment_date)='2005'; /*年份加單引號的寫法也能通過,但不夠簡練*/ /*針對公司,查詢2005年總的銷售額*/ select sum(amount) from payment where extract(year from payment_date)=2005; /*針對公司,查詢2005年總的銷售額,payment_copy沒有建立索引*/ select sum(amount) from payment_copy where extract(year from payment_date)=2005; explain select sum(amount) from payment where extract(year from payment_date)=2005; /*為payment_copy建立索引*/ create index cust_id on payment_copy(customer_id); /*利用索引提高查詢效率*/ select sum(amount) from payment_copy where customer_id=1 and extract(year from payment_date)=2005; /*刪除索引*/ drop index cust_id on payment_copy; create index pay_date on payment(payment_date); drop index pay_date on payment; /*建立檢視*/ /*利用檢視查詢*/ select title from film_list; /*建立臨時表*/ create temporary table if not exists tmp_user( id integer not null auto_increment COMMENT '使用者ID', name varchar(20) not null default '' COMMENT '名稱', sex integer not null default 0 COMMENT '0為男,1為女', primary key(id) )engine=MyISAM default charset=utf8 auto_increment=1; /*顯示臨時表的細節,show table顯示包括table和view但不包括臨時表*/ desc tmp_user; /*mysql不支援在臨時表上建立檢視,會報錯*/ /*create view v_tmp_user as select * from tmp_user;*/ /* mysql> create view v_tmp_user as select * from tmp_user; ERROR 1352 (HY000): View's SELECT refers to a temporary table 'tmp_user' */ /*建立預處理語句*/ create view pay_view as select sum(amount) from payment where extract(year from payment_date)=2005; /*mysql中連線字串用concat函式,||僅作邏輯運算用*/ create view pay_view as select concat(c.first_name,' ',c.last_name) as name, sum(p.amount) as amount from payment_copy As p,customer As c where extract(year from p.payment_date)=2005 and p.customer_id=c.customer_id group by p.customer_id; select * from pay_view; /*輸出前10條資料*/ select * from pay_view limit 10; /*輸出第11條到20條資料*/ select * from pay_view limit 11,20; /*隨機抽取5條資料,order by rand()*/ select * from pay_view order by rand() limit 5; drop view pay_view; /*不能給檢視新增索引,只能在基本表上新增索引*/ /*create index pay_view_index on pay_view(amount);*/ /*ERROR 1347 (HY000): 'test.pay_view' is not BASE TABLE*/ /*特別注意:如果檢視和基本表一一對應,檢視的更新可以達到同步修改基本表的目的;如果進行抽取,運算等操作得到檢視,對檢視的操作不能同步到 基本表,檢視中資料和基本表中的資料不一致,檢視中的資料在記憶體中,做臨時顯示使用,有必要時才將資料同步到基本表*/ /*事務,mysql中預設每個sql語句是一個事務,就自動提交一次。考慮到效能,多個語句放在一個事務塊中*/ begin drop view pay_view; create view pay_view as select concat(c.first_name,' ',c.last_name) as name, sum(p.amount) as amount from payment_copy As p,customer As c where extract(year from p.payment_date)=2005 and p.customer_id=c.customer_id group by p.customer_id; select * from pay_view limit 10; end /*更改表的儲存引擎*/ alert table payment_copy engine=InnoDB; /*建立mysql定時執行的事件*/ set global event_scheduler=1; create table testduty( time varchar(20) default null )engine=myisam default charset=latin1; create event if not exists test_event on schedule every 10 second do insert into testduty(time) values(now()); /*刪除定時任務*/ drop event test_event; /*優化資料表*/ optimize table payment; /*測試加入索引的效能*/ /*建立兩張表:一個建立索引,另一個不建立*/ create table if not exists test_has_index( id integer not null auto_increment, num integer not null default 0, d_num varchar(30) not null default '0', primary key(id) )engine=MyISAM default charset=utf8 auto_increment=1; create table if not exists test_no_index( id integer not null auto_increment, num integer not null default 0, primary key(id) )engine=MyISAM default charset=utf8 auto_increment=1; /*建立儲存過程,用於初始化資料表*/ delimiter | create procedure i_test(pa integer,tab varchar(30)) begin declare max_num integer default 10000; declare i integer default 0; declare rand_num integer; declare double_num char; if tab!='test_no_index' then select count(id) into max_num from test_has_index; while i < pa do if max_num < 10000 then select cast(rand()*100 as unsigned) into rand_num; select concat(rand_num,rand_num) into double_num; insert into test_has_index(num,d_num) values(rand_num,double_num); end if; set i=i+1; end while; else select count(id) into max_num from test_no_index; while i < pa do if max_num < 10000 then select cast(rand()*100 as unsigned) into rand_num; insert into test_no_index(num) values(rand_num); end if; set i=i+1; end while; end if; end | delimiter ; /*資料表中記錄較少時,索引反而會影響效能*/ call i_test(10,'test_has_index'); /*call呼叫儲存過程,並傳入引數*/ select num from test_has_index where num!=0; explain select num from test_has_index where num!=0; /*Tips: where後的條件,order by ,group by 等這樣過濾時,後面的欄位最好加上索引。根據實際情況,選擇PRIMARY KEY、UNIQUE、INDEX等索引,但是不是越多越好,要適度。*/ select a.num as num1, b.num as num2 from test_no_index as a left join test_has_index as b on a.num=b.num; explain select a.num as num1, b.num as num2 from test_no_index as a left join test_has_index as b on a.num=b.num; /*Tips:資料量特別大的時候,最好不要用聯合查詢,即使你做了索引??*/ /*mysql中使用外來鍵,必須選用innodb儲存引擎,myisam不支援外來鍵*/ /*建立user、order表,二者相關聯,以下也是兩個表關聯的典型例項*/ create table test_user( id int(10) not null auto_increment COMMENT '使用者ID', name varchar(20) not null default '' COMMENT '名稱', sex integer not null default 0 COMMENT '0為男,1為女', primary key(id) )engine=innodb default charset=utf8 auto_increment=1; insert into test_user(name,sex) values("Han",1),("Max",2); /*建立表test_order,並同步設定了主鍵、索引、外來鍵、儲存引擎innodb*/ create table test_order( order_id int(10) not null auto_increment comment '訂單ID', u_id int(10) not null default 0 comment '使用者ID', username varchar(20) not null default '' comment '使用者名稱', money int(10) not null default 0 comment '錢數', datetime timestamp not null default current_timestamp comment '生成時間', primary key(order_id), index(u_id), foreign key order_f_key(u_id) references test_user(id) )engine=innodb default charset=utf8 auto_increment=1; /*向order中插入資料*/ insert into test_order(u_id,username,money,datetime) values(1,'Han',223,current_timestamp); insert into test_order(u_id,username,money,datetime) values(2,'Max',423,current_timestamp); delete fromm user where id=1; insert into test_order(u_id,username,money,datetime) values(5,Sophe,223,current_timestamp); /*外來鍵維護資料完整性的方式有5種 cascade 從父表刪除或更新且自動刪除或更新子表中匹配的行。ON DELETE CASCADE和ON UPDATE CASCADE都可用。 set null 從父表刪除或更新行,並設定子表中的外來鍵列為NULL。ON DELETE SET NULL和ON UPDATE SET NULL子句被支援。 no action InnoDB拒絕對父表的刪除或更新操作。 restrict 拒絕對父表的刪除或更新操作。NO ACTION和RESTRICT都一樣,刪除ON DELETE或ON UPDATE子句。 set default 預設情況下,外來鍵模式是*/ /*查詢test_order表中的外來鍵名稱*/ show create test_order; /*刪除外來鍵*/ alter table test_order drop foreign key test_order_ibfk_1; /*新增外來鍵,增加了on delete cascade on update cascade*/ alter table test_order add foreign key(u_id) references test_user(id) on delete cascade on update cascade; /*此時更新主表,從表的u_id欄位會自動更改*/ update test_user set id=11 where id=1; /*下面學習幾個比較使用的mysql函式*/ /*建立新的練習表*/ create table comment( c_id int(10) not null auto_increment comment '評論ID', u_id int(10) not null comment '使用者ID', name varchar(20) not null default '' comment '使用者名稱', content varchar(1000) not null default '' comment '評論內容', datetime timestamp not null default current_timestamp, num1 int(10) default null, num2 int(10) default null, primary key(c_id) )engine=myisam default charset=utf8 auto_increment=1; /*插入幾條資料*/ insert into comment(u_id,name,content,num1,num2) values (1,'test1','3445212',4,23),(2,'test2','up!!',43,21),(3,'test3','a3235b',23,23); /*greatest(),least()求最值*/ select c_id, greatest(num1,num2) as max, least(num1,num2) as min, num1,num2 from comment where num1!="" and num2!=""; /*concat(), concat_ws()用於連線多個字串,CONCAT_WS() 代表 CONCAT With Separator ,是CONCAT()的特殊形式,第一個引數是其它引數的分隔符。間隔符可以自己指定*/ select concat_ws(',',name, content,datetime) from comment; select concat(',',name, content,datetime) from comment; /*concat會將第一個,當作一個附加的字元*/ select concat(name, ',',content,',',datetime) from comment; /*concat預設不加分隔符,可以手動加入,但不如concat_ws()簡練*/ /*interval()查詢10小時之前的評論*/ select * from comment where datetime <= (select now()-interval 10 hour as time_start); /*last_insert_id()查詢最後插入記錄的id*/ select last_insert_id(); /*mysql中可以加入正則匹配查詢*/ select * from comment where content regexp '[A-z][0-9]+'; select * from comment where content regexp '^u'; /*隨機數使用rand()產生,cast()用於轉換型別*/ select cast(rand()*1000 as unsigned) as rand_num; /*常用的時間處理函式extract(year from payment_date)=2005或者year(),month(),day(), hour(),minute(),second(),week(), */ select day(now()) as day; /*上面day()完全可以代替下面的substring,更簡練*/ select substring(now(),9,2) as day; /*mysql中分表,大表分成多個小表,提高查詢效能*/ /*利用merge進行分表*/ drop table if exists user1; create table if not exists user1( id int(10) not null auto_increment, name varchar(20) not null default '', sex integer not null default 0, primary key(id) )engine=myisam default charset=utf8 auto_increment=1; drop table if exists user2; create table if not exists user2( id int(10) not null auto_increment, name varchar(20) not null default '', sex integer not null default 0, primary key(id) )engine=myisam default charset=utf8 auto_increment=1; insert into user1(name,sex) values('Alice',0),('Apple',1); insert into user2(name,sex) values('Bob',1),('Band',0); /*資料分析筆試題 */ drop table if exists t1; create table if not exists t1( user_id int(10) not null, blog_id int(10) not null ); drop table if exists t2; create table if not exists t2( blog_id int(10) not null, comment_id int(10) not null ); insert into t1 values(1,1),(1,2),(1,3),(2,4),(2,5),(2,6),(2,7),(3,8); insert into t2 values(2,1),(2,2),(2,3),(2,4),(3,5),(4,6),(4,7),(4,8),(5,9),(5,10); alter t2 change user_id blog_id int(10); alter t2 change blog_id comment_id int(10); insert into t1 values(1,9),(1,10); insert into t2 values(9,11),(9,12),(10,13); alter table t2 change user_id blog_id int(10); select t1.user_id,t1.blog_id,t2.comment_id from t1 inner join t2 on t1.blog_id=t2.blog_id; select t1.user_id,t1.blog_id,count(t2.comment_id) from t1 inner join t2 on t1.blog_id=t2.blog_id group by t1.blog_id; select t1.user_id,t1.blog_id,count(t2.comment_id) as counts from t1 inner join t2 on t1.blog_id=t2.blog_id group by t1.blog_id order by counts desc limit 1; /*將上述select的結果插入一個表中*/ drop table if exists t1_t2; create table if not exists t1_t2( user_id int(10), blog_id int(10), comment_counts int(10) ); insert into t1_t2 values(2,5,2),(1,9,2),(1,3,1),(1,10,1),(1,2,4),(2,4,3); /*注意insert into t1_t2表後不加values關鍵詞*/ insert into t1_t2 (select t1.user_id,t1.blog_id,count(t2.comment_id) as counts from t1 inner join t2 on t1.blog_id=t2.blog_id group by t1.blog_id order by counts desc); /*求按user_id分組取最大的2個comment_id對應的blog_id *下面經過驗證*/ select t.user_id,t.blog_id from t1_t2 t where 2>(select count(*) from t1_t2 where user_id=t.user_id and comment_counts>t.comment_counts order by t.user_id,t.comment_counts) order by t.user_id; select t1.user_id,t1.blog_id from t1 inner join t2 on t1.blog_id=t2.blog_id order by counts desc; group by t1.blog_id ; select t1.user_id,t1.blog_id,count(t2.comment_id) as counts from t1 inner join t2 on t1.blog_id=t2.blog_id group by t1.blog_id having count(t2.comment_id)<=2; order by counts desc; limit 1; /* 按照blog_id分組取最大的值所在的行 */ /*將2個表merge成一個表,注意最後一行是engine=merge,而不是type=merge The older term TYPE is supported as a synonym for ENGINE for backward compatibility, but ENGINE is the preferred term and TYPE is deprecated. */ /*但是,如下方式直接建立alluser還是報錯了1168:unable to open underlying table which is differently defined or of non-myiasm*/ /*drop table if exists alluser; create table if not exists alluser( id int(10) not null auto_increment, name varchar(20) default '', sex integer not null default 0, index(id) )engine=MERGE union=(user1,user2) INSERT_METHOD=last AUTO_INCREMENT=1; */ /*最後決定採用曲線方式*/ create table alluser like user1; alter table alluser engine=merge union(user1,user2); alter table alluser insert_method=last; desc alluser; /*從合成的表中查詢*/ select * from alluser; /*總表中插入記錄*/ insert into alluser(name,sex) values('Merry',1),('Han',0); select * from user1; select * from user2; /*更新總表中記錄*/ update alluser set sex=replace(sex,1,0) where id=2; /*特別要明白各種關聯查詢,注重查詢效率*/ /*在一個 INNER JOIN 之中,可以巢狀 LEFT JOIN 或 RIGHT JOIN,但是在 LEFT JOIN 或 RIGHT JOIN 中不能巢狀 INNER JOIN。*/ /*INNER JOIN 運算 組合兩個表中的記錄,只要在公共欄位之中有相符的值*/ select a.actor_id,b.film_id from actor as a inner join film_actor as b on a.actor_id = b.actor_id limit 10; /*兩個表普通連線*/ select a.actor_id,film_id from actor as a, film_actor as b where a.actor_id = b.actor_id limit 10; /*各種查詢關鍵字的順序: join子句 聯結條件 > where子句 聯結條件和查詢條件 > group by子句分組 > having子句搜尋 >order by子句結果排序 > limit顯示某些記錄 */ /*連線查詢常用模式*/ /*1、select * from table1, table2 where table1.id=table2.id 2、select * from table1 left join table2 on table1.id = table2.id 3. select * from table1 left join table2 using(id) 4. select * from table1 left join table2 on table1.id=table2.id left join table3 on table2.id=table3.id 5. select * from table1 use index(key1,key2) where key1=1 and key2=2 and key3=3 6. slect * from table1 ignore index(key1) where key1=1 and key2=2 and key3=3 */ /*驗證各種連線結果,以film, film_actor, actor為例*/ select f.title,fa.actor from film f left join film_actor fa on f.film_id = fa.film_id limit 10; select film.*,film_actor.* from film left join film_actor on film.film_id = film_actor.film_id limit 10; select film.title,film_actor.actor_id from film left join film_actor on film.film_id = film_actor.film_id limit 10; select film.title,film_actor.actor_id from film left join film_actor using(film_id) limit 10; select film.title,film_actor.actor_id from film left join film_actor using(film_id) group by film.film_id limit 10; select film.title,film_actor.actor_id from film inner join film_actor on film.film_id = film_actor.film_id limit 10; /**/ /**/ /**/ /*查詢中去掉重複欄位*/ /*建立測試資料表school_report*/ drop table if exists school_report; create table school_report( id int(10) not null auto_increment comment '表ID', u_id int(10) not null comment '學生ID', name varchar(20) not null default '' comment '學生姓名', score varchar(4) not null default 0 comment '學生成績', message varchar(50) not null default '', dateline timestamp not null default current_timestamp, primary key(id) )engine=innodb default charset=utf8 auto_increment=1; /*插入測試資料*/ insert into school_report(u_id,name,score,message) values(1,'張三',89,'helloworld'),(1,'張三',90,'hello'),(2,'李四',92,'helloworld'), (3,'王五',93,'world'); /*查詢,去掉重複*/ select distinct name,score from school_report; select *, count(distinct name) from school_report group by name; /**/ select * from school_report a inner join( select max(dateline) as dateline from school_report group by u_id) b on a.dateline = b.dateline group by id order by a.dateline desc; /*記錄和分析 花費時間較多的select*/ /*首先進行如下設定,設定long_query_time時間限*/ show variables like "%long%"; set global long_query_time=2; /*檢查並開啟慢查詢,會顯示mysql-slow.log檔案的路徑*/ show variables like "%slow%"; set global slow_query_log='ON'; /*這樣超過long_query_time的查詢會記錄到mysql日誌中*/ /*分組後前n條資料: http://www.jb51.net/article/31590.htm*/ drop table if exists tb; create table tb ( name varchar(10), val int, memo varchar(20) ); insert into tb values('a', 2, 'a2(a的第二個值)'),('a',1,'a1--a第一個值'), ('a',3,'a3--a第三個值'),('b',1,'b1--b第一個值'),('b',3,'b3--b第三個值'), ('b',2,'b3--b2b2b2'),('b',4,'b4b4b4'),('b',5,'b5b5b5b5'); /*按name分組取value 最大的值的記錄*/ --方法1:select a.* from tb a where val = (select max(val) from tb where name = a.name) order by a.name --方法2: select a.* from tb a where not exists(select 1 from tb where name = a.name and val > a.val); --方法3: select a.* from tb a,(select name,max(val) val from tb group by name) b where a.name = b.name and a.val = b.val order by a.name; --方法4: select a.* from tb a inner join (select name , max(val) val from tb group by name) b on a.name = b.name and a.val = b.val order by a.name ; --方法5 select a.* from tb a where 1 > (select count(*) from tb where name = a.name and val > a.val ) order by a.name ; /* name val memo ---------- ----------- -------------------- a 3 a3:a的第三個值 b 5 b5b5b5b5b5 方法三、四效率比較高 */ /*按name分組取val最小的值的記錄*/ --方法1:select a.* from tb a where val = (select min(val) from tb where name = a.name) order by a.name --方法2: select a.* from tb a where not exists(select 1 from tb where name = a.name and val < a.val); --方法3: select a.* from tb a,(select name,min(val) val from tb group by name) b where a.name = b.name and a.val = b.val order by a.name ; --方法4: select a.* from tb a inner join (select name , min(val) val from tb group by name) b on a.name = b.name and a.val = b.val order by a.name ; --方法5 select a.* from tb a where 1 > (select count(*) from tb where name = a.name and val < a.val) order by a.name ; /* name val memo ---------- ----------- -------------------- a 1 a1--a的第一個值 b 1 b1--b的第一個值 */ /*按name分組取出第一次出現的記錄*/ select a.* from tb a where val = (select top 1 val from tb where name = a.name) order by a.name /* name val memo ---------- ----------- -------------------- a 2 a2(a的第二個值) b 1 b1--b的第一個值 */ /*按name分組隨機取一條資料*/ select a.* from tb a where val = (select top 1 val from tb where name = a.name order by newid()) order by a.name/* name val memo ---------- ----------- -------------------- a 1 a1--a的第一個值 b 5 b5b5b5b5b5 */ /*按name分組取最小的2個(N個)val所在記錄*/ select a.* from tb a where 2 > (select count(*) from tb where name = a.name and val < a.val ) order by a.name,a.valselect a.* from tb a where val in (select top 2 val from tb where name=a.name order by val) order by a.name,a.val select a.* from tb a where exists (select count(*) from tb where name = a.name and val < a.val having Count(*) < 2) order by a.name /* name val memo ---------- ----------- -------------------- a 1 a1--a的第一個值 a 2 a2(a的第二個值) b 1 b1--b的第一個值 b 2 b2b2b2b2 */ /*按name分組取最大的2個(N個)val所在記錄*/ select a.* from tb a where 2 > (select count(*) from tb where name = a.name and val > a.val ) order by a.name,a.val select a.* from tb a where val in (select top 2 val from tb where name=a.name order by val desc) order by a.name,a.val select a.* from tb a where exists (select count(*) from tb where name = a.name and val > a.val having Count(*) < 2) order by a.name /* name val memo ---------- ----------- -------------------- a 2 a2(a的第二個值) a 3 a3:a的第三個值 b 4 b4b4 b 5 b5b5b5b5b5 */ /*MySQL中序列有auto_increment,Oracle中使用sequence序列和**.NextVal*/ /*在Oracle中可以新增觸發器,實現mysql形式的自增長;mysql也可以通過定義過程實現Oracle的序列語法*/ /*mysql實現currval()*/ drop table if exists sequence; create table sequence( name varchar(50) not null, current_value int not null, increment int not null default 1, primary key(name) )engine=InnoDB; insert into sequence values('MovieSeq',3,5); Drop function if exists currval; delimiter $ create function currval(seq_name varchar(50)) returns integer contains sql begin declare value integer; set value=0; select current_value into value from sequence where name=seq_name; return value; end$ delimiter ; /*測試定義的currval*/ select currval('MovieSeq'); /*mysql實現nextval()*/ drop function if exists nextval; delimiter $ create function nextval(seq_name varchar(50)) returns integer contains sql begin update sequence set current_value=current_value+increment where name=seq_name; return currval(seq_name); end$ delimiter ; /*測試定義的nextval()*/ select nextval('MovieSeq'); select nextval('MovieSeq'); /*mysql實現setval(). 報錯了!!*/ drop function if exists setval; delimiter $ create function setval(seq_name varchar(50),val integer) returns integer contains sql begin update sequence set current_value=val; where name = seq_name; return currval(seq_name); end$ delimiter ; /*測試定義的setval()*/ select setval('MovieSeq',150); select curval('MovieSeq'); select nextval('MovieSeq'); /*即作為主鍵同時又是外來鍵的情況*/ drop table if exists Issues; create table Issues ( issue_id integer auto_increment primary key ); drop table if exists Bugs; create table Bugs( issue_id integer primary key, foreign key(issue_id) references Issues(issue_id) ); insert into Issues values(); insert into Issues values(); select * from Issues; /*1,2*/ select * from Bugs; /*null*/ insert into Bugs values(4); /*報外來鍵引用錯誤*/ insert into Bugs values(2); /*正常插入,只要插入Issues中存在的資料就OK*/ select * from Bugs; /*2*/ /*浮點數的表示*/ /*浮點數不能比較,要用近似相等*/ drop table if exists Num; create table Num( id integer auto_increment primary key, price float not null default '0.0', sum float not null default '0.0', ); /*float型別的資料儲存時滿足IEEE754二進位制浮點數的標準,表達的範圍很大,舍入方式不是四捨五入; 當儲存的值在Integer和numeric型別所支援的範圍內,就不必選擇float型別。推薦用numeric*/ alter table Num add column price2 numeric(9,2) default '0.0'; /*numeric(9,2)定義的price2列儲存的就有2位小數位,可以進行=精確比較,即使插入了3個小數位,會四捨五入*/ /*限定列的有效值: 如果,可選範圍固定,使用Enum和Check約束,check約束使用範圍更廣,如檢查start永遠小於end; 否則,將可選資料建立一個檢查表*/ drop table if exists PersonalContacts; Create table PersonalContacts( id integer auto_increment primary key, salutation varchar(5) check (salutation in ('Mr.','Mrs.','Ms.','Dr.')) ); drop table if exists PersonalContacts; Create table PersonalContacts( id integer auto_increment primary key, salutation enum('Mr.','Mrs.','Ms.','Dr.') ); /*用Enum限定列的取值範圍,插入不屬於其範圍的值時,未報錯但插入欄位為空。插入範圍內的值,一切正常*/ insert into PersonalContacts(salutation) values('Mz.'); select * from PersonalContacts; insert into PersonalContacts(salutation) values('Ms.'); select * from PersonalContacts; /*注:enum是mysql獨有的特性*/ /*要想增加某列取值範圍,需要更改資料表,ETL(抽取--》轉換--》載入資料),但麻煩*/ alter table PersonalContacts modify column salutation enum('Mr.','Mrs.','Ms.','Dr.','Mz.'); insert into PersonalContacts(salutation) values('Mz.'); select * from PersonalContacts; /*可選資料建立一個檢查表*/ drop table if exists Salutation; create table Salutation( status varchar(5) primary key ); insert into Salutation(status) values('Mr.','Ms.'); drop table if exists PersonalContacts2; /*定義外來鍵時,加上on update cascade,重新命名一個值就比較方便*/ create table PersonalContact2( id integer auto_increment primary key, status varchar(5), foreign key(status) references Salutation(status) on update cascade ); /*方便查詢、插入和更改*/ select status from Salutation order by status; insert into Salutation(status) values('Mss.'); update Salutation set status='Dr.' where status='Mss'; /*使用檢查表,支援廢棄資料(保持歷史資料的值,對新插入的數值加限制)*/ alter table Salutation add column active enum('inactive','active') not null default 'active'; /*使用update代替delete廢棄一個值*/ update Salutation set active='inactive' where status='Dr.'; select status from Salutation where active='active'; /*mysql資料型別: 1.數值型別 MYSQL支援所有標準SQL,這其中包括: 精確數值資料型別:INTERGER/INT,SMALLINT,DECIMAL/DEC,NUMERIC 近似數值資料型別:FLOAT,REAL,DOCULE PRECISION BIT資料型別 作為對標準SQL的擴充套件,MySQL還支援TINYINT,MEDIUMINT及BIGINT 如果ZEROFILL指定給數值列,則MYSQL會自動新增UNSIGNED屬性 整數或浮點型別均可指定AUTO_INCREMENT屬性,當被賦值NULL或0時會自動設定成下一個序列值,AUTO_INCREMENT序列從1開始 MYSQL將DOUBLE與DOUBLE PRECISION等同,將REAL也與DOUBLE PRECISION等同 DECIMAL與NUMERIC用來儲存精確數值資料,NUMERIC是DECIMAL的一種實現,MYSQL5.5將DECIMAL與NUMERIC儲存為二進位制格式 BIT資料型別用來儲存位元數值,BIT(M)中M允許從1到64,位數不足時會自動左側補0 SERIAL 等同於BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE 2.日期時間型別 當使用DATE與TIME型別時通常需要注意的事項: MYSQL會嘗試從各種格式的輸入中解析日期與時間,但還是有格式限制的 只有兩位數的YEAR,會讓MYSQL感到迷惑,所以MYSQL會嘗試作下面的解析:在70~99之間的年會被解析成:1970~1999,在00~69之間的年會被解析成2000~2069 MYSQL在解析日期時,日期的輸入順序必須為:year-month-day,否則無法正確解析 預設情況下,MYSQL會將超出範圍或不合法的日期與時間,轉換成0,但對於超出範圍的TIME,會將其歸整到一個恰當的時間點上。 3.字串型別 字串型別包括:CHAR,VARCHAR,BINARY,VARBINARY,BLOB,TEXT,ENUM和SET. */ /*圖片等多媒體資訊儲存在資料庫內,還是儲存在資料庫外(檔案系統中)*/ /*儲存在資料庫外(僅用varchar存放圖片檔案路徑) 缺點: 1. 不支援delete 2. 不支援事物隔離 3. 不支援回滾 4. 檔案不支援資料庫備份工具 5. 不支援訪問許可權限制 6. 檔案不是SQL資料型別*/ /*儲存在資料庫內(使用Blob型別) 優點:解決 儲存在資料外 的6個缺點 Blob 初始化 可以從檔案中匯入; Blob 內容 也可以匯入檔案中。 缺點:需要資料表佔用空間更大,備份更大 */ drop table if exists Bugs; create table Bugs( bug_id integer auto_increment primary key ); /*image_id integer auto_increment not null,*/ drop table if exists Screenshots; /*SERIAL 等同於BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE*/ create table Screenshots( bug_id integer not null, image_id serial not null, screenshot_image BLOB, caption varchar(100), primary key (bug_id,image_id), foreign key (bug_id) references Bugs(bug_id) ); /*如果採用 記錄路徑名的 方式,儲存在資料庫之外的檔案系統中*/ /* create table Screenshots( bug_id integer not null, image_id serial not null, screenshot_path varchar(100), caption varchar(100), primary key (bug_id,image_id), foreign key (bug_id) references Bugs(bug_id) ); */ /*插入資料*/ insert into Bugs values(); insert into Bugs values(); insert into Bugs values(); insert into Bugs values(); insert into Bugs values(); insert into Bugs values(); /*初始化Blob資料型別*/ insert into Screenshots(bug_id,screenshot_image) values(1,load_file('f:\aaa.jpg')); /*這裡插入時,必須指明bug_id*/ select bug_id,image_id from Screenshots; /*驗證發現image_id是自增的*/ select screen_image from Screenshots; /*會顯示出一大片的圖片二進位制字元*/ insert into Screenshots(bug_id,screenshot_image) values(1,load_file('f:\bbb.jpg')); insert into Screenshots(bug_id,screenshot_image) values(2,load_file('f:\ccc.jpg')); delete from Screenshots where bug_id=1 and image_id=3; /*將資料庫中儲存的Blob圖片,匯出到檔案系統*/ select screenshot_image into dumpfile 'F:\aaa111.jpg' from Screenshots where bug_id=1 and image_id=2; /*問題:生成了 檔名 是aaa111的檔案,但是開啟只顯示沒有預覽1B???????????原圖片249kb*/ select screenshot_image into dumpfile 'F:\\aaa222.jpg' from Screenshots where bug_id=1 and image_id=2; /*索引:在SQL標準中沒有很多的說明,不同資料庫實現有較大的自由度和區別*/ /*合理地使用索引!!!! 錯誤的觀點: 1. 不使用索引或索引不足 2. 使用太多的索引 3. 執行一些讓索引無能為力的查詢 1. 要根據具體情況,分析需要建立哪些索引,在維護索引的開銷 和 索引帶來的加速之間進行比較 2. 通過mentor方法: measure(慢查詢),解釋(explain),挑選,效能測試,優化,重建(定期維護:analyze table or optimize table) 注意: 1. insert update delete都要維護索引 2. 索引可以快速找到要delete或update的記錄 3. 主鍵會自動建立索引,沒有必要手工加入 4. 對於過長的varchar不建議建立索引,不太可能進行全匹配查詢 5. 可以根據實際需求建立組合索引*/ drop table if exists Bugs1; create table Bugs1( bug_id serial primary key, date_reported date not null, summary varchar(80) not null, status varchar(10) not null, hours numeric(9,2), index(bug_id,date_reported,status) ); /*考慮:bugs與多個標籤的關係(多個標籤不互斥)*/ /*一個 bugs對應的最多標籤數確定時,可以採用建立多個tage列,但在查詢、新增和刪除tag都很方便*/ /*一個 bugs對應的最多標籤數確定時,強烈建議使用 從屬表,僅使用一列儲存【多值屬性】,多個值儲存在多行,而不是多列! 從表中定義外來鍵和主記錄關聯*/ drop table if exists Tags; create table Tags( bug_id integer not null, tag varchar(20), primary key(bug_id,tag), foreign key(bug_id) references Bugs(bug_id) ); insert into Tags(bug_id,tag) values('1','crash'),('2','performance'),('2','printing'),('2','crash'),(3,'printing'); select * from Tags where bug_id=2; /*查詢和 某標籤 相關的所有bug*/ select * from Bugs join Tags using(bug_id) where tag='performance'; /*查詢和 某2個標籤 相關的所有bug記錄*/ select * from Bugs join Tags as t1 using (bug_id) join Tags as t2 using (bug_id) where t1.tag='printing' and t2.tag='performance'; /*結果: +--------+----------+-------------+ | bug_id | tag | tag | +--------+----------+-------------+ | 2 | printing | performance | +--------+----------+-------------+ */ /*使用從屬表 可以更方便地 新增和移除 bugs和tag標籤之間的關係*/ insert into Tags(bug_id,tag) values (3,'save'); delete from Tags where bug_id=2 and tag='crash'; /**/ /**/