《MySQL必知必會》代碼總結

本文主要總結了Ben Forta著的《MySQL必知必會》的代碼,可以用作初學者快速查找代碼。

  1. 檢索列中數據的種類數
# 假設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
*/
  1. 限制結果
# 返回前5行
select prod_name from products limit 5;

# 返回第1行開始的3行數據
select prod_name from products limit 0,3;
  1. 排列數據
# 按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;
  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';
  1. 正則表達式
# 返回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
*/
  1. 計算字段
# 將列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
*/
  1. 文本處理函數
函數 說明
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  
*/
  1. 日期和時間處理函數
函數 說明
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;
  1. 聚集函數
函數 說明
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
*/
  1. 分組數據

  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
*/
  1. 子查詢
# 查詢包含物品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
*/
  1. 內部聯結

  products表只存儲產品信息,除了存儲供應商ID(vendors表的主鍵)外不存儲供應商的其他信息。vendors表的主鍵又叫做products表的外鍵,它將vendors表與products表關聯。

  將數據分開兩個表存儲的好處爲:

  1. 在products表中不需存儲大量重複的供應商信息
  2. 如果供應商信息變動,只需修改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;
  1. 自聯結

  針對同一個表中,需要先查到該表生產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';
  1. 外部聯結

  當需要查詢全部用戶的訂單情況,需要聯結查詢用戶表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
*/
  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);
  1. 使用全文本搜索
# 在建表時,啓動全文本搜索功能
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);
  1. 插入行
# 一次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;
  1. 更新和刪除數據
# 更新數據
update customers
set cust_name = 'The Fudds',
    cust_email = '[email protected]'
where cust_id = 10005;

# 刪除數據
delete from customers
where cust_id = 10006;
  1. 表的操作
# 創建表,其中列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;
  1. 視圖

  視圖可以理解爲對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. 存儲過程

  存儲過程可以理解爲函數。

例子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;
  1. 遊標

  遊標相當於指針,其指向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
*/
  1. 觸發器
# 每插入一行,都顯示一次文本'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);
  1. 事務處理
# 當順利執行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;
  1. 管理用戶
# 創建用戶
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');
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章