1. 程式人生 > >數據庫筆記(mysql)(3)

數據庫筆記(mysql)(3)

pri font key ati 而且 麻煩 auto arc aci

數據庫高級簡介

  • 實體與實體之間有3種對應關系,這些關系也需要存儲下來
  • 在開發中需要對存儲的數據進行一些處理,用到內置的一些函數
  • 視圖用於完成查詢語句的封裝
  • 事務可以保證復雜的增刪改操作有效

關系

  • 創建成績表scores,結構如下
    • id
    • 學生
    • 科目
    • 成績
  • 思考:學生列應該存什麽信息呢?
  • 答:學生列的數據不是在這裏新建的,而應該從學生表引用過來,關系也是一條數據;根據範式要求應該存儲學生的編號,而不是學生的姓名等其它信息
  • 同理,科目表也是關系列,引用科目表中的數據
  • 創建表的語句如下
create table scores(
id int primary key auto_increment,
stuid int,
subid int,
score decimal(5,2)
);

外鍵

  • 思考:怎麽保證關系列數據的有效性呢?任何整數都可以嗎?
  • 答:必須是學生表中id列存在的數據,可以通過外鍵約束進行數據的有效性驗證
  • 為stuid添加外鍵約束
alter table scores add constraint stu_sco foreign key(stuid) references students(id);
  • 此時插入或者修改數據時,如果stuid的值在students表中不存在則會報錯
  • 在創建表時可以直接創建約束
create table scores(
id int primary key auto_increment,
stuid int,
subid int,
score decimal(5,2),
foreign key(stuid) references students(id),
foreign key(subid) references subjects(id)
);

外鍵的級聯操作

  • 在刪除students表的數據時,如果這個id值在scores中已經存在,則會拋異常
  • 推薦使用邏輯刪除,還可以解決這個問題
  • 可以創建表時指定級聯操作,也可以在創建表後再修改外鍵的級聯操作
  • 語法
alter table scores add constraint stu_sco foreign key(stuid) references students(id) on delete cascade;
  • 級聯操作的類型包括:
    • restrict(限制):默認值,拋異常
    • cascade(級聯):如果主表的記錄刪掉,則從表中相關聯的記錄都將被刪除
    • set null:將外鍵設置為空
    • no action:什麽都不做

連接查詢

(先看個問題)

  • 問:查詢每個學生每個科目的分數
  • 分析:學生姓名來源於students表,科目名稱來源於subjects,分數來源於scores表,怎麽將3個表放到一起查詢,並將結果顯示在同一個結果集中呢?
  • 答:當查詢結果來源於多張表時,需要使用連接查詢
  • 關鍵:找到表間的關系,當前的關系是
    • students表的id---scores表的stuid
    • subjects表的id---scores表的subid
  • 則上面問題的答案是:
select students.sname,subjects.stitle,scores.score
from scores
inner join students on scores.stuid=students.id
inner join subjects on scores.subid=subjects.id;
  • 結論:當需要對有關系的多張表進行查詢時,需要使用連接join

連接查詢

  • 連接查詢分類如下:
    • 表A inner join 表B:表A與表B匹配的行會出現在結果中
    • 表A left join 表B:表A與表B匹配的行會出現在結果中,外加表A中獨有的數據,未對應的數據使用null填充
    • 表A right join 表B:表A與表B匹配的行會出現在結果中,外加表B中獨有的數據,未對應的數據使用null填充
  • 在查詢或條件中推薦使用“表名.列名”的語法
  • 如果多個表中列名不重復可以省略“表名.”部分
  • 如果表的名稱太長,可以在表名後面使用‘ as 簡寫名‘或‘ 簡寫名‘,為表起個臨時的簡寫名稱

練習

  • 查詢學生的姓名、平均分
select students.sname,avg(scores.score)
from scores
inner join students on scores.stuid=students.id
group by students.sname;
  • 查詢男生的姓名、總分
select students.sname,avg(scores.score)
from scores
inner join students on scores.stuid=students.id
where students.gender=1
group by students.sname;
  • 查詢科目的名稱、平均分
select subjects.stitle,avg(scores.score)
from scores
inner join subjects on scores.subid=subjects.id
group by subjects.stitle;
  • 查詢未刪除科目的名稱、最高分、平均分
select subjects.stitle,avg(scores.score),max(scores.score)
from scores
inner join subjects on scores.subid=subjects.id
where subjects.isdelete=0
group by subjects.stitle;

自關聯


  • 設計省信息的表結構provinces
    • id
    • ptitle
  • 設計市信息的表結構citys
    • id
    • ctitle
    • proid
  • citys表的proid表示城市所屬的省,對應著provinces表的id值
  • 問題:能不能將兩個表合成一張表呢?
  • 思考:觀察兩張表發現,citys表比provinces表多一個列proid,其它列的類型都是一樣的
  • 意義:存儲的都是地區信息,而且每種信息的數據量有限,沒必要增加一個新表,或者將來還要存儲區、鄉鎮信息,都增加新表的開銷太大
  • 答案:定義表areas,結構如下
    • id
    • atitle
    • pid
  • 因為省沒有所屬的省份,所以可以填寫為null
  • 城市所屬的省份pid,填寫省所對應的編號id
  • 這就是自關聯,表中的某一列,關聯了這個表中的另外一列,但是它們的業務邏輯含義是不一樣的,城市信息的pid引用的是省信息的id
  • 在這個表中,結構不變,可以添加區縣、鄉鎮街道、村社區等信息
  • 創建areas表的語句如下:

create table areas(
id int primary key,
atitle varchar(20),
pid int,
foreign key(pid) references areas(id)
);

  • 從sql文件中導入數據

source areas.sql;

  • 查詢一共有多少個省
  • 查詢省的名稱為“山西省”的所有城市

select city.* from areas as city
inner join areas as province on city.pid=province.id
where province.atitle=‘山西省‘;

  • 查詢市的名稱為“廣州市”的所有區縣

select dis.*,dis2.* from areas as dis
inner join areas as city on city.id=dis.pid
left join areas as dis2 on dis.id=dis2.pid
where city.atitle=‘廣州市‘;

內置函數

字符串函數


  • 查看字符的ascii碼值ascii(str),str是空串時返回0

select ascii(‘a‘);

  • 查看ascii碼值對應的字符char(數字)

select char(97);

  • 拼接字符串concat(str1,str2...)

select concat(12,34,‘ab‘);

  • 包含字符個數length(str)

select length(‘abc‘);

  • 截取字符串
    • left(str,len)返回字符串str的左端len個字符
    • right(str,len)返回字符串str的右端len個字符
    • substring(str,pos,len)返回字符串str的位置pos起len個字符

select substring(‘abc123‘,2,3);

  • 去除空格
    • ltrim(str)返回刪除了左空格的字符串str
    • rtrim(str)返回刪除了右空格的字符串str
    • trim([方向 remstr from str)返回從某側刪除remstr後的字符串str,方向詞包括both、leading、trailing,表示兩側、左、右
select trim(‘  bar   ‘);
select trim(leading ‘x‘ FROM ‘xxxbarxxx‘);
select trim(both ‘x‘ FROM ‘xxxbarxxx‘);
select trim(trailing ‘x‘ FROM ‘xxxbarxxx‘);

  • 返回由n個空格字符組成的一個字符串space(n)

select space(10);

  • 替換字符串replace(str,from_str,to_str)
select replace(‘abc123‘,‘123‘,‘def‘);

  • 大小寫轉換,函數如下
    • lower(str)
    • upper(str)

select lower(‘aBcD‘);

數學函數


  • 求絕對值abs(n)

select abs(-32);

  • 求m除以n的余數mod(m,n),同運算符%

select mod(10,3);
select 10%3;

  • 地板floor(n),表示不大於n的最大整數

select floor(2.3);

  • 天花板ceiling(n),表示不小於n的最大整數

select ceiling(2.3);

  • 求四舍五入值round(n,d),n表示原數,d表示小數位置,默認為0

select round(1.6);

  • 求x的y次冪pow(x,y)

select pow(2,3);

  • 獲取圓周率PI()

select PI();

  • 隨機數rand(),值為0-1.0的浮點數

select rand();

  • 還有其它很多三角函數,使用時可以查詢文檔

日期時間函數


  • 獲取子值,語法如下
    • year(date)返回date的年份(範圍在1000到9999)
    • month(date)返回date中的月份數值
    • day(date)返回date中的日期數值
    • hour(time)返回time的小時數(範圍是0到23)
    • minute(time)返回time的分鐘數(範圍是0到59)
    • second(time)返回time的秒數(範圍是0到59)

select year(‘2016-12-21‘);

  • 日期計算,使用+-運算符,數字後面的關鍵字為year、month、day、hour、minute、second

select ‘2016-12-21‘+interval 1 day;

  • 日期格式化date_format(date,format),format參數可用的值如下

    • 獲取年%Y,返回4位的整數

      * 獲取年%y,返回2位的整數

      * 獲取月%m,值為1-12的整數

    • 獲取日%d,返回整數

      * 獲取時%H,值為0-23的整數

      * 獲取時%h,值為1-12的整數

      * 獲取分%i,值為0-59的整數

      * 獲取秒%s,值為0-59的整數


select date_format(‘2016-12-21‘,‘%Y %m %d‘);

  • 當前日期current_date()

select current_date();

  • 當前時間current_time()

select current_time();

  • 當前日期時間now()

select now();

視圖


  • 對於復雜的查詢,在多次使用後,維護是一件非常麻煩的事情
  • 解決:定義視圖
  • 視圖本質就是對查詢的一個封裝
  • 定義視圖

create view stuscore as 
select students.*,scores.score from scores
inner join students on scores.stuid=students.id;

  • 視圖的用途就是查詢

select * from stuscore;

事務


  • 當一個業務邏輯需要多個sql完成時,如果其中某條sql語句出錯,則希望整個操作都退回
  • 使用事務可以完成退回的功能,保證業務邏輯的正確性
  • 事務四大特性(簡稱ACID)
    • 原子性(Atomicity):事務中的全部操作在數據庫中是不可分割的,要麽全部完成,要麽均不執行
    • 一致性(Consistency):幾個並行執行的事務,其執行結果必須與按某一順序串行執行的結果相一致
    • 隔離性(Isolation):事務的執行不受其他事務的幹擾,事務執行的中間結果對其他事務必須是透明的
    • 持久性(Durability):對於任意已提交事務,系統必須保證該事務對數據庫的改變不被丟失,即使數據庫出現故障
  • 要求:表的類型必須是innodb或bdb類型,才可以對此表使用事務
  • 查看表的創建語句

show create table students;

  • 修改表的類型

alter table ‘表名‘ engine=innodb;

  • 事務語句

開啟begin;
提交commit;
回滾rollback;


 
 

數據庫筆記(mysql)(3)