本文主要總結了Ben Forta著的《MySQL必知必會》的代碼,可以用作初學者快速查找代碼。
- 檢索列中數據的種類數
# 假設products表中列vend_id存在很多重複的數據
select vend_id from products;
/*輸出
* vend_id
* 1001
* 1001
* 1001
* 1002
* 1002
* 1003
* 1003
* 1004
* 1004
*/
# 使用DISTINCT關鍵字,返回該列數據的集合
select distinct vend_id from products;
/*輸出
* vend_id
* 1001
* 1002
* 1003
* 1004
*/
- 限制結果
# 返回前5行
select prod_name from products limit 5;
# 返回第1行開始的3行數據
select prod_name from products limit 0,3;
- 排列數據
# 按prod_name中的字母升序(默認爲升序)來排序
select prod_name from products order by prod_name;
# 按prod_name中的字母降序來排序
select prod_name from products order by prod_name desc;
# 先按價格、再按商品名稱進行排序。僅在多個相同的prod_price中,再按prod_name排序。如果prod_price所有值都是不同的,則不會按prod_name排序。
select prod_id, prod_price, prod_name from products order by prod_price, prod_name;
# 先按價格降序,再按商品升序排列。其中desc直接作用於其前面的列名
select prod_id, prod_price, prod_name from products order by prod_price desc, prod_name;
# 結合order by 和 limit,找出最大值
select prod_price from products order by prod_price desc limit 1;
- 過濾數據
# where 語句
select prod_name, prod_price from products where prod_price<10;
# where的between語句
select prod_name, prod_price from products where prod_price between 5 and 10;
# where的and語句
select prod_id, prod_price, prod_name from products where vend_id=1003 and prod_price<=10;
# where的or語句
select prod_id, prod_price, prod_name from products where vend_id=1002 or vend_id=1003;
# in語句:返回供應商1002和1003製造的所有產品
select prod_name, prod_price from products where vend_id in (1002,1003) order by prod_name;
# not in語句:返回除1002和1003之外的所有供應商的產品
select prod_name, prod_price from products where vend_id not in (1002,1003) order by prod_name;
# 通配符%:找出以jet開頭的產品
select prod_id, prod_name from products where prod_name like 'jet%';
# 通配符%:找出產品名稱包含anvil的結果
select prod_id, prod_name from products where prod_name like '%anvil%';
# 通配符_:只匹配單個字符,結果只返回'1 ton anvil'和'2 ton anvil',而不返回'.5 ton anvil'
select prod_id, prod_name from products where prod_name like '_ ton anvil';
- 正則表達式
# 返回prod_name包含文本1000的結果
select prod_name from products where prod_name regexp '1000' order by prod_name;
/*輸出
* prod_name
* JetPack 1000
*/
# 返回任何以'000'爲結尾的結果
select prod_name from products where prod_name regexp '.000' order by prod_name;
/*輸出
* prod_name
* JetPack 1000
* JetPack 2000
*/
# 返回包含'1000'或'2000'的結果
select prod_name from products where prod_name regexp '1000|2000' order by prod_name;
# 返回任何包含'2 Ton'或'5 Ton'字符的結果
select prod_name from products where prod_name regexp '[2 5] Ton' order by prod_name;
/*輸出
* prod_name
* 2 ton anvil
* .5 ton anvil
*/
# 返回包含數字1~5的結果
select prod_name from products where prod_name regexp '[1-5] Ton' order by prod_name;
/*輸出
* prod_name
* .5 ton anvil
* 1 ton anvil
* 2 ton anvil
*/
# 匹配包含特殊字符'.'或'-'等,需要使用'\\'作爲轉義符
select vend_name from vendors where vend_name regexp '\\.' order by vend_name;
/*輸出
* prod_name
* Furball Inc.
*/
# 重複元字符?:?匹配它前面單個字符0次或1次
select prod_name from products where prod_name regexp '\\([0-9] colou?r\\)'
/*輸出
* prod_name
* TNT (1 color)
* TNT (5 colour)
*/
# 重複元字符{n}:匹配連續4個數字字符
select prod_name from products where prod_name regexp '[0-9]{4}'
/*輸出
* prod_name
* JetPack 1000
* JetPack 2000
*/
# 定位元字符^:只返回'0-9'或'.'在匹配串開頭的結果
select prod_name from products where prod_name regexp '^[0-9\\.]' order by prod_name;
/*輸出
* prod_name
* .5 ton anvil
* 1 ton anvil
* 2 ton anvil
*/
- 計算字段
# 將列vend_name和vend_country的信息以'vend_name(vend_country)'的形式返回,並將返回結果命名爲新的列vend_title
select concat(vend_name, '(', vend_country, ')') as vend_title from vendors order by vend_name;
/*輸出
* vend_title
* ACME (USA)
* Furball Inc. (USA)
*/
# 可將列的信息直接進行 加減乘除 後返回
select
prod_id,
quantity,
item_price,
quanttty*item_price as expanded_price
from orderitems where order_num=20005;
/*輸出
* prod_id quantity item_price expanded_price
* ANV01 10 5.99 59.90
* ANV02 3 9.99 29.97
*/
- 文本處理函數
函數 | 說明 |
---|---|
Left(s,k) | 截取串s左邊的k個字符,例如select left(‘12345’,2) 結果就是 12 |
Length(s) | 返回字符串s的長度 |
Locate(s,ss) | 返回子串ss在串s的位置,例如select locate(‘bar’, ‘foobarbar’)的結果爲4 |
Lower(s), Upper(s) | 轉爲爲小寫、大寫 |
LTrim(s) | 去除串s左邊的空格 |
Soundex(s) | 返回串的SOUNDEX值,即發音值 |
# 將列的數據轉爲爲大寫
select vend_name, Upper(vend_name) as vend_name_upcase from vendors order by vend_name;
/*輸出
* vend_name vend_name_upcase
* anvils ANVILS
*/
# 返回英語發音相似的結果
select cust_name, cust_contact from customers where soundex(cust_contact) = soundex('Y Lie');
/*輸出
* cust_name cust_contact
* Coyote Inc. Y Lee
*/
- 日期和時間處理函數
函數 | 說明 |
---|---|
Date() | 返回日期部分 |
Day() | 返回天數部分 |
Hour() | 返回小時部分 |
Minute | 返回分鐘部分 |
# 如果列order_date的格式爲'2005-09-01 11:30:05',則可以用函數Date()只對日期進行搜索
select cust_id, order_num from orders where Date(order_data) = '2005-09-01';
# 如果列order_date的格式爲'2005-09-01 11:30:05',這時需要檢索2005年9月份的所有記錄,則可以:
select cust_id, order_num from orders where Year(order_data) = 2005 and Month(order_data) = 9;
- 聚集函數
函數 | 說明 |
---|---|
AVG() | 求平均 |
COUNT() | count(*)返回該表的行數,count©計算列c中非NULL的數量 |
MAX() | 求最大值 |
MIN() | 求最小值 |
# 求平均值
select AVG(prod_price) as avg_price from products;
# 求表customers的行數
select COUNT(*) as num_cust from customers;
# 彙總統計
select COUNT(*) as num_items,
MIN(prod_price) as price_min,
MAX(prod_price) as price_max,
AVG(prod_price) as price_AVG,
SUM(prod_price*quantity) as total_price
from products;
/*輸出
* num_items price_min price_max price_AVG total_price
* 14 2.50 55.00 16.133571 260
*/
- 分組數據
having
針對分組進行過濾,where
針對行進行過濾
# 以cust_id進行分組,並計算每個分組內的行數,返回行數>=2的分組
select cust_id, count(*) as orders from orders group by cust_id having count(*)>=2;
# 先選出prod_price>=10的數據,然後以vend_id進行分組,並計算每個分組內的行數,返回行數>=2的分組
select vend_id, count(*) as num_prods from products where prod_price >=10 group by vend_id having count(*) >= 2;
# 以order_num進行分組,並計算每個分組內的總價,返回總價>=50的數據
/*表ordertiems的格式如下:
* order_num order_item item_price quantity
* 20005 6 55.00 16
* 20005 7 10.00 8
* 20005 8 20.00 20
* ...
* ...
* ...
*/
select order_num, sum(quantity*item_price) as ordertotal from orderitems group by order_num having sum(quantity*item_price) >= 50 order by ordertotal;
/*輸出
* order_num ordertotal
* 20006 55.00
* 20008 125.00
* 20005 149.87
* 20007 1000.00
*/
- 子查詢
# 查詢包含物品TNT2的訂單編號,然後查詢這些訂單的用戶編號,最後返回這些用戶的信息
select cust_name, cust_contact from customers where cust_id in
(select cust_id from orders where order_num in
(select order_num from orderitems where prod_id = 'TNT2')
);
# 先從customers表檢索用戶列表,然後統計每個用戶在orders表中的訂單數目
select
cust_name,
cust_state,
(select count(*) from orders where orders.cust_id = customers.cust_id) as orders
from customers
order by cust_name;
/*輸出
* cust_name cust_state orders
* Coyote Inc. MI 2
* E Fudd IL 1
*/
- 內部聯結
products表只存儲產品信息,除了存儲供應商ID(vendors表的主鍵)外不存儲供應商的其他信息。vendors表的主鍵又叫做products表的外鍵,它將vendors表與products表關聯。
將數據分開兩個表存儲的好處爲:
- 在products表中不需存儲大量重複的供應商信息
- 如果供應商信息變動,只需修改vendors表中的單個記錄,而不需修改products表
# 通過供應商id聯結查詢表vendors和表products
select vend_name, prod_name, prod_price
from vendors, products
where vendors.vend_id = products.vend_id
order by vend_name, prod_name;
# 上面語句,採用inner join語法,實現一樣的結果
select vend_name, prod_name, prod_price
from vendors inner join products
on vendors.vend_id = products.vend_id;
- 自聯結
針對同一個表中,需要先查到該表生產ID爲DTNTR的物品的供應商ID,再根據該供應商ID查詢其生產的其他物品。這種情況爲需要對同一個表查詢兩次,需要用到子查詢或自聯結。
# 子查詢:先查到該表生產ID爲DTNTR的物品的供應商ID,再根據該供應商ID查詢其生產的其他物品。
select prod_id, prod_name from products where vend_id = (select vend_id from products where prod_id = 'DTNTR');
# 自聯結:先查到該表生產ID爲DINTER的物品的供應商ID,再根據該供應商ID查詢其生產的其他物品。
select p1.prod_id, p1.prod_name from products as p1, products as p2
where p1.vend_id = p2.vend_id
and p2.prod_id = 'DTNTR';
- 外部聯結
當需要查詢全部用戶的訂單情況,需要聯結查詢用戶表customers和訂單表orders。
# 內聯結:不包括那些沒有訂單的客戶
select customers.cust_id, orders.order_num
from customers inner join orders
on customers.cust_id = orders.cust_id;
/*輸出
* cust_id order_num
* 10001 20005
* 10003 20007
*/
# 外聯結:包括那些沒有訂單的客戶
select customers.cust_id, orders.order_num
from customers left outer join orders
on customers.cust_id = orders.cust_id;
/*輸出
* cust_id order_num
* 10001 20005
* 10002 NULL
* 10003 20007
*/
# 聚集函數+外聯結:查詢全部用戶及所下訂單數
select customer.cust_name,
customer.cust_id,
count(orders.order_num) as num_ord
from customers left outer join orders
on customers.cust_id = orders.cust_id
group by customers.cust_id;
/*輸出
* cust_name cust_id num_ord
* Coyote 10001 2
* Mouse 10002 0
* House 10003 1
*/
- 組合查詢
雖然使用where語法更簡潔,但是面對複雜條件時union語法是更簡單的方式。
# where語法:查詢vend_id爲1001和1002的商品,和價格小於5的商品
select vend_id, prod_id, prod_price
from products
where prod_price<=5 or vend_id in (1001,1002);
# union語法:查詢vend_id爲1001和1002的商品,和價格小於5的商品
select vend_id, prod_id, prod_price
from products
where prod_price<=5
union
select vend_id, prod_id, prod_price
from products
where vend_id in (1001,1002);
- 使用全文本搜索
# 在建表時,啓動全文本搜索功能
create tabel rpoductnotes
(
note_id int not null auto_increment,
prod_id char(10) not null,
note_date datetime not null,
note_text text null,
primary key(note_id),
fulltext(note_text)
)engine=myisam;
# 使用全文本搜索功能,查詢包含'rabbit'的記錄
select note_text
from productnotes
where match(note_text) against('rabbit');
# 檢索包含單詞'heavy',且排除任何以'rope'開頭的單詞的記錄
select note_text from productnotes where match(note_text) against ('heavy -rope*' in boolean mode);
# 匹配包含單詞'rabbit'和'bait'的行
select note_text from productnotes where match(note_text) against ('+rabbit +bait' in boolean mode);
# 匹配包含rabbit和bait中的至少一個詞的行
select note_text from productnotes where match(note_text) against ('rabbit bait' in boolean mode);
# 匹配短語'rabbit bait'
select note_text from productnotes where match(note_text) against ('"rabbit bait"' in boolean mode);
# 匹配'rabbit'和'carrot',增加前者的等級,降低後者的等級
select note_text from productnotes where match(note_text) against ('>rabbit <carrot' in boolean mode);
# 匹配詞'safe'和'combination',降低後者的等級
select note_text from productnotes where match(note_text) against ('+safe +(<combination)' in boolean mode);
- 插入行
# 一次insert語句插入多個行
insert into customers(cust_name,
cust_address,
cust_city,
cust_state,
cust_zip
cust_country)
values('Pep E. Lapew',
'100 Main Street',
'Los Angeles',
'CA',
'90046',
'USA'),
('M. Martian',
'42 Galaxy Way',
'New York',
'NY',
'11213',
'USA'
);
# 插入由select語句檢索到的數據
insert into customers(cust_id,
cust_contact,
cust_email,
cust_name,
cust_address,
cust_city,
cust_state,
cust_zip,
cust_country)
select cust_id,
cust_contact,
cust_email,
cust_name,
cust_address,
cust_city,
cust_state,
cust_zip,
cust_country
from custnew;
- 更新和刪除數據
# 更新數據
update customers
set cust_name = 'The Fudds',
cust_email = '[email protected]'
where cust_id = 10005;
# 刪除數據
delete from customers
where cust_id = 10006;
- 表的操作
# 創建表,其中列order_num必須爲非空(如果爲空值則插入失敗,其中''不算空值),列quantity允許爲空值,主鍵爲order_num和order_item
create table orderitems
(
order_num int not null,
order_item int not null,
quantity int null,
primary key (order_num, order_item)
)
# 新增一列
alter table vendors add vend_phone char(20);
# 刪除一列
alter table vendors drop column vend_phone;
# 定義外鍵: alter table 表名 add constraint 約束名稱 約束類型 (列名) references 被引用的表名稱 (列名)
alter table orderitems add constraint
fk_orderitems_orders foreign key (order_num)
references orders (order_num);
# 刪除表
drop table customers;
# 重命名錶
rename table customers2 to customers;
- 視圖
視圖可以理解爲對select語句進行函數封裝,以後調用該視圖就是調用該select語句。
# 創建視圖vendorlocations
create view vendorlocations as
select concat(RTrim(vend_name),'(',RTrim(vend_country),')')
as vend_title
from vendors
order by vend_name;
# 使用視圖vendorlocations
select * from vendorlocations;
/*輸出
* vend_title
* ACME (USA)
* Anvils R Us (USA)
*/
- 存儲過程
存儲過程可以理解爲函數。
例子1:
# 創建存儲過程ordertotal,能根據輸入的訂單號onumber,計算該訂單的總價並返回到變量ototal
create procedure ordertotal(
in onumber int,
out ototal decimal(8,2)
)
begin
select sum(item_price*quantity)
from ordertiems
where order_num = onumber
into ototal;
end;
# 調用存儲過程ordertotal
call ordertotal(20005, @ototal);
select @ototal;
/*輸出
* @ototal
* 149.87
*/
例子2:
# 創建存儲過程ordertotal,能根據輸入的訂單號onumber,計算該訂單在有或無稅收的情況下的總價並返回到變量ototal
create procedure ordertotal(
in onumber int,
in taxable boolean,
out ototal decimal(8,2)
)
begin
-- 定義局部變量
declare total decimal(8,2);
declare taxrate int default 6;
select sum(item_price*quantity)
from orderitems
where order_num = onumber
into total;
if taxable then
select total+(total/100*taxrate) into total;
end if;
select total into ototal;
end;
# 調用,並計算爲無稅收的總價
call ordertotal(20005,0,@ototal)
select @ototal;
/*輸出
* @ototal
* 149.87
*/
# 調用,並計算爲有稅收的總價
call ordertotal(20005,1,@ototal)
select @ototal;
/*輸出
* @ototal
* 158.862200000
*/
# 顯示存儲過程ordertotal的內部代碼
show create procedure ordertotal;
# 刪除存儲過程ordertotal
drop procedure ordertotal;
- 遊標
遊標相當於指針,其指向select語句查詢結果的第一行,每次進行讀取(fetch)後,自動跳到下一行。
create procedure processorders()
begin
-- 定義局部變量
declare done boolean default 0;
declare o int;
declare t decimal(8,2);
-- 定義遊標
declare ordernumbers cursor
for
select order_num from orders;
-- 定義continue handler,當循環repeat沒有更多的行時出現錯誤代碼'02000'時,設置停止信號done=1
declare continue handler for sqlstate '02000' set done=1;
-- 創建table用於存儲結果
create table if not exists ordertotals
(order_num int, total decimal(8,2));
-- 打開遊標
open ordernumbers;
-- 循環
repeat
-- 遊標讀取一行數據
fetch ordernumbers into o;
-- 上一節定義的procedure,根據給定的訂單編號o,在算上稅的情況下(1),計算訂單總價t
call ordertotal(o,1,t);
insert into ordertotals(order_num, total) values(o,t);
until done end repeat;
--關閉遊標
close ordernumbers;
end;
-- 查看運行結果
select * from ordertotals;
/*輸出
* order_num total
* 20005 158.86
* 20006 58.30
*/
- 觸發器
# 每插入一行,都顯示一次文本'Product added'
create trigger newproduct after insert on products
for each row select 'product added';
# 每刪除一行信息,都將該信息(在old變量中)插入另一個表中
create trigger deleteorder before delete on orders
for each row
begin
insert into archive_orders(order_num, order_date, cust_id)
values(old.order_num, old.order_date, old.cust_id)
end;
# 每更新一條信息前,都將該信息改爲全部大寫
create trigger updatevendor before update on vendors
for each row set new.vend_state = upper(new.vend_state);
- 事務處理
# 當順利執行delete後,進行事務回退,即回退至'start transaction'前的狀態
select * from ordertotals;
start transaction
delete from ordertotals;
select * from ordertotals;
rollback;
select * from ordertotals;
# 當完全順利執行兩條delete後,纔將最終結果寫入數據庫
start transaction;
delete from orderitems where order_num = 20010;
delete from orders where order_num = 20010;
commit;
# 回退至存檔點
savepoint delete1;
rollback to delete1;
- 管理用戶
# 創建用戶
create user ben identified by 'p@$$w0rd';
# 修改用戶已名
rename user ben to bforta;
# 刪除用戶
drop user bforta;
# 賦予權限:允許用戶bforta在數據庫crashcourse中的全部表中,有select權限
grant select on crashcourse.* to bforta;
show grants for bforta;
# 撤銷權限:撤銷用戶bforta在數據庫crashcourse中的全部表中所具有的select權限
revoke select on crashcourse.* from bforta;
# 更改用戶密碼
set password for bforta = Password('n3w p@$$w0rd');