日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

【数据库04】中级开发需要掌握哪些SQL进阶玩法

發布時間:2023/12/18 数据库 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【数据库04】中级开发需要掌握哪些SQL进阶玩法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前 言
🍉 作者簡介:半舊518,長跑型選手,立志堅持寫10年博客,專注于java后端
?專欄簡介:相當硬核,黑皮書《數據庫系統概念》讀書筆記,講解:
1.數據庫系統的基本概念(數據庫設計過程、關系型數據庫理論、數據庫應用的設計與開發…)
2.大數據分析(大數據存儲系統,鍵值存儲,Nosql系統,MapReduce,Apache Spark,流數據和圖數據庫等…)
3.數據庫系統的實現技術(數據存儲結構,緩沖區管理,索引結構,查詢執行算法,查詢優化算法,事務的原子性、一致性、隔離型、持久性等基本概念,并發控制與故障恢復技術…)
4.并行和分布式數據庫(集中式、客戶-服務器、并行和分布式,基于云系統的計算機體系結構…)
5.更多數據庫高級主題(LSM樹及其變種、位圖索引、空間索引、動態散列等索引結構的拓展,高級應用開發中的性能調整,應用程序移植和標準化,數據庫與區塊鏈等…)
🌰 文章簡介:上篇文章我們把數據庫的增刪改查講解的透透的了,這篇文章我們將學習具有更復雜形式的SQL查詢,視圖定義,事務,完整性約束等。

文章目錄

    • 1.連接表達式
      • 1.1 自然連接
      • 1.2 連接條件
      • 1.3 外連接
    • 2.視圖
      • 2.1 視圖定義
      • 2.2 在SQL查詢中使用視圖
      • 2.3 物化視圖
      • 2.4 視圖更新
    • 3.事務
    • 4.完整性約束
      • 4.1 非空約束
      • 4.2 唯一性約束
      • 4.3 check子句
      • 4.4 引用完整性
      • 4.5 給約束賦名
      • 4.6 事務中對完整性約束的違反
      • 4.7 復雜check條件與斷言
    • 5.SQL的數據類型與模式
      • 5.1 SQL中的日期和時間類型
      • 5.2 類型轉換和格式化函數
      • 5.3 缺省值
      • 5.4 大對象類型
      • 5.5 屬性的時態有效性
      • 5.6 用戶自定義類型
      • 5.7 生成唯一碼值
      • 5.8 create table的擴展
      • 5.9 模式、目錄與環境
    • 6.SQL中的索引定義
    • 7.授權
      • 7.1 權限的授予與收回
      • 7.2 角色
      • 7.3 視圖的授權
      • 7.4 模式的授權
      • 7.5 權限的轉移
      • 7.6 權限的級聯收回
      • 7.7 行級授權

1.連接表達式

前一篇文章我們使用笛卡爾積運算符來組合來自多個關系的信息,本文介紹“連接”查詢,允許程序員以一種更自然的方式編寫一些查詢,并表達只用笛卡爾積很難表達的查詢。

本節所用的示例設計student和takes兩個關系,如下圖所示。請注意對于ID為98988的學生,在2018年夏季選修的BIO-301課程的1號課程段的grade屬性為空值,該空值表示它尚未得到成績。

1.1 自然連接

請考慮以下SQL查詢,該查詢為每名學生計算該學生已經選修的課程的集合。

select name,curse_id from student,takes where student.ID = takes.ID;

請注意,此查詢僅輸出已選修某些課程的學生,未選修任何課程的學生不會被輸出。請注意上面連接條件中student.ID與takes.ID具有相同的屬性名ID,這在實際的SQL查詢中含常見,自然連接被設計出來簡化上述情況的查詢。

自然連接運算作用于兩個關系,并產生一個關系作為結果。與兩個關系的笛卡爾積不同,自然連接只考慮在兩個關系的模式中都出現的那些屬性上取值相同的元組對,而笛卡爾積將第一個關系的每個元組與第二個關系的每個元組進行串接。

上面的SQL也可以這么寫。

student natural join takes

其查詢結果如下,注意屬性的列出順序,受限是兩個關系模式中的公共屬性,其次是第一個關系模式中的那些屬性,最后是只出現在
第二個關系中的那些屬性。

之前有一個查詢,"對于大學中已經選課的所有學生,找出他們的姓名以及他們選修的所有課程的標識。”我們可以這么寫。

select name, course_id from student natural join takes;

在一條SQL查詢的from字句中,可以用自然連接把多個關系結合在一起。

select A1,A2....An from r1 natural join r2 natural join r3... natural join rm where P;

更一般地,from子句可以寫為如下形式。

from E1,E2...En

每個Ei可以是單個關系或者一個涉及自然連接的表達式。例如,假設我們要查詢“列出學生的姓名和他們所選擇的課程的名稱”。可以寫。

select name,title from student natural join takes, course where takes.course_id = course.course_id;

受限計算studnet和takes的自然連接,再計算該結果與course的笛卡爾積,where字句從結果中再過濾,過濾條件是course_id相匹配。

思考如下sql與上面的sql是否會等價。

select name,title from student natural join takes natural join course

不是!!!

請注意student和takes做自然連接后包含的屬性是(ID,name,dept_name,tot_cred,course_id,sec_id),而course包含的屬性是(course_id,titile,dept_name,credits)。上面二者做自然連接,不僅需要course_id取值相同,還需要dept_name取值相同。

為了避免這樣的錯誤出現,我們可以這樣做。

select name,title from (student natural join takes) join course using (course_id);

1.2 連接條件

除了上面的join using外,還可以使用on關鍵字指定連接條件。

select * from student join takes on student.ID = takes.ID;

這與自然查詢的結構是一樣的,唯一的區別在于查詢結果ID出現兩次,一次是student中的,一次是takes結果中的。如果希望ID只出現一次,可以這么做。

select student.ID as ID,name,dept_name,tot_cred,course_id,sec_id,semester,year,grade from student join takes on student.ID = takes.ID;

愛思考的讀者會發現,on關鍵字似乎可以被where所替代,那它是不是一個冗余的語法?實際上,on關鍵字在外連接中與where表現是不同的,其次,如果使用on作為連接條件,并在where字句中出現其余的條件,sql查詢會更加清晰易懂。

1.3 外連接

假設我們希望查詢所有學生的個人信息與選修的課程,可能會想到如下檢索。

select * from student natural join takes

不過如果一個學生沒有選修課程,就不會出現在這個結果中。

我們可以改用外連接來實現我們的需求。外連接與我們已經學習過的連接運算類似,但是它會通過在結果中創建包含空值的元組,來保留那些在連接中會丟失的元組。

外連接分為三種,

  • 左外連接。只保留連接關鍵字之前的關系的元組。
  • 右外連接。只保留連接關鍵字之后的關系的元組。
  • 全外連接。保留出現在兩個關系中的元組。

相比較而言,我們之前學習的不保留未匹配元組的連接運算被稱為內連接運算。

比如"查詢所有學生的個人信息與選修的課程"可以這樣用左外連接實現。

select * from student natural left outer join takes;

查詢“一門課程也沒有選修的學生”。

select ID from student natural left outer join takes where course_id is null;

左外連接與右外連接是對稱的,用右外連接實現"查詢所有學生的個人信息與選修的課程"。

select * from take natural right outer join student ;

全外連接可以看做左外連接與右外連接的并運算。考慮查詢,“顯示Comp.Sci系中所有學生以及他們在2017年春季選修的所有課程段的列表。在2017年春季選修的所有課程段都必須顯示。”

select * from (select * from studentwhere dept_name = 'Comp.Sci')natural full outer join(select *from takeswhere semester = 'Spring' and year = 2017);

在外連接中,where和on關鍵字表現是不同的。on會作為外連接聲明的一部分,而where卻不是。使用where時不會補全具有空值的元組,使用on則會。

另外,常規連接也被稱為內連接,可以使用缺省的關鍵字inner。

2.視圖

讓所有用戶看到數據庫關系中的完整集合并不合適,我們可以通過SQL授權來限制對關系的訪問,但是如果僅需要向用戶隱藏一個關系中的特定數據,可以使用視圖。

除了安全型的考慮,視圖還可以通過定制化更好的匹配特定用戶的需求。

2.1 視圖定義

創建視圖語法是。

create view v as <查詢表達式>;

考慮需要訪問instrutor除了salary外的所有數據的職員。

create view faculty asselect ID,name,dept_namefrom instructor;

視圖在概念上包含查詢結果中的元組,但是不進行預計算和存儲。我通俗的理解成,創建視圖是創建了一個規則,使用視圖時再根據規則進行計算。

2.2 在SQL查詢中使用視圖

創建視圖后可以像使用數據表一樣使用視圖。如。

select ID from faculty ;

可以顯示的指定視圖的屬性名稱。

create view department_total_salary(dept_name, total_salary) asselect dept_name,sum(salary)from instructorgroup by dept_name;

直觀的說,任意給定時刻,視圖關系幾種的元組集都是使用定義視圖查詢表達式求值的結果,因此如果定義并存儲一個視圖關系,一旦定義視圖的關系被修改,那么視圖就會過期。

一個視圖還可以被用到另一個視圖的定義中去。

2.3 物化視圖

某些數據庫系統中的視圖關系保證:如果定義視圖的實際關系發生改變,則視圖也跟著修改以保持更新,這樣的視圖被稱為物化視圖。如果視圖是物化的,則其計算結果會被存儲在計算機中,從而在使用視圖時可以更快的運行。

既然物化視圖會預計算并存儲,那么就需要保持物化視圖的更新,保持物化視圖一直在最新的狀態的過程被稱為物化視圖維護,或者視圖維護。這種維護策略可以是實時維護,周期維護,惰性維護(被使用時才更新),人工維護等,支持的策略與數據庫產品有關。

物化視圖對于頻繁使用的視圖有幫助,對大型關系的聚集運算也較為適用,需要平衡其存儲代價與性能開銷。

2.4 視圖更新

對視圖進行增刪改可能會帶來嚴重的問題,因為用視圖表達的修改必須被翻譯為對數據庫關系的實際修改。一般不允許對視圖進行更新。不同的數據庫可能會指定不同的條件,在滿足這些條件的前提下可以對視圖進行更新,具體可以參考其系統手冊。

一般說來,如果定義視圖的查詢滿足下面條件,那么稱SQL視圖是可更新的

  • from字句中只有一個數據庫關系
  • select子句中只包含關系的屬性名,并不包含任何的表達式、聚集或者distinct聲明。
  • 沒有出現在select子句中的任何屬性都可以取null值。也就是說,這些屬性沒有非空約束,也不構成主碼的一部分。
  • 查詢中不包含有group by或者having子句。

不過要注意,即使滿足上面的限制條件,仍然不一定可以將數據順利插入視圖。定義如下視圖。

create view history_instructors as select * from instructor where dept_name = 'History';

考慮如下查詢。嘗試向history_instructors視圖中插入元組(‘25566’,‘Brown’,‘Biology’,10000)。這個元組可以被插入instructor關系中,但是不滿足視圖的選擇要求dept_name = 'History'。他不應該出現在視圖history_instructors中。

我們可以在視圖定義的末尾添加with check option子句做到這一點,如果新值滿足where子句的條件,就可以插入視圖,否則,數據庫系統會拒絕該插入操作。

SQL:1999對于視圖有更加復雜的規則集。這里不討論。

觸發器機制提供了另外一種視圖修改數據庫的機制,它更加可取,后續文章將詳細介紹。

3.事務

事務有查詢或者更新語句的序列組成。SQL標準規定當一條SQL語句被執行時,就隱式的開始了一個事務。下列SQL語句之一會結束該事務。

  • commit work,事務提交。一個事務提交后就在數據庫中稱為了永久性的,會自動開始一個新的事務。
  • rollback work,事務回滾,也就是它會撤銷事務中的SQL語句執行的所有更新。

關鍵字work在兩條語句中都是可選的。

考慮下面場景,如果一個學生成功修完了一個課程,需要對takes關系進行更新,也需要對student關系進行更新。如果更新完其中一個關系,卻沒有更新完另外一個關系就出現了系統故障,會出現數據不一致的情況。這種情況不應該出現,兩個關系要么同時被更新,要么同時不被更新。這就是事務的原子性,

在包括Mysql和PostgreSQL在內的很多SQL實現中,在缺省方式下每條SQL自動組成一個事務,且語句一旦執行完立刻提交該事務。很多數據庫實現支持關閉自動提交

一種更好的備選方案是,作為SQL:1999標準的一部分,允許多條SQL語句被包含在關鍵字begin atomic ... end之間,這樣關鍵字之間的語句就構成了一個單一的事務,如果執行到end語句,則該事務被默認提交。只有諸如SQL Server的某些數據庫支持上述語法。諸如MySQL和PostgreSQL的其他幾個數據庫支持的是begin語句,該語句啟動包含所有后續SQL語句的事務,但是并不支持end語句,事務必須通過commiy work或者rollback work命令來結束。

但是使用諸如Oracle的數據庫,自動提交并不是DML語句的缺省設置,請保證在添加或者修改數據后發出commit命令。不過Oracle會自動提交DDL語句。雖然Oracle已經關閉了自動提交,不過期缺省設置可能被本地設置所覆蓋。

4.完整性約束

完整性約束保證授權用戶對數據庫所做的修改不會導致數據一致性的丟失。他可以在數據庫關系定義是作為create table的一部分被聲明。也可以通過使用alter table table-name add constraint命令將完整性約束添加到已有關系上。

4.1 非空約束

我們可以用非空約束限制屬性非空。在創建表時就可以聲明屬性非空約束,語法是。

name varchar(20) not null

主碼中禁止出現空值,不需要顯示的指定非空約束。

4.2 唯一性約束

可以采用unique約束屬性唯一,注意唯一性約束允許屬性為null。請回憶一下,空值不等于其他任何值。

4.3 check子句

check§可以制定一個謂詞P,靈活的給所有元組增加約束。

比如在crate table命令中的check(budget>0)子句將保證budget的取值非負。

check子句不能夠限制屬性非空,因為當check子句的計算結果為未知時,也被認為滿足謂詞P(結果不是false即滿足),需要限制非空必須指定單獨的非空約束。

根據定義,check子句中的謂詞可以任意,不過當前還沒有一個被廣泛使用的數據庫允許其包含子查詢的謂詞。

4.4 引用完整性

我們常常希望一個關系中的給定屬性在另外一個關系中也出現。這就是引用完整性約束。外碼是引用完整性約束的一種形式,其中被引用的屬性構成被引用關系的主碼。

比如對course表的定義有一個聲明"foreign key(dept_name) references department ".這個約束說明,對于每個課程元組,元組中指定的系名必須在department關系中存在,這樣即可避免為一門課程指定一個并不存在的系名。

在缺省情況下(Mysql 并不支持缺省),SQL中外碼引用的是被引用表的主碼屬性。SQL還支持顯示指定被引用關系的屬性列表的引用子句版本。例如,course關系的外碼聲明可以指定為

foreign key(dept_name) references department(dept_name)

注意被指定的屬性列表必須聲明為被引用關系的超碼,要么使用主碼約束,要么使用唯一性約束來進行這種聲明。

在更為普遍的引用完整性約束里,被引用的屬性不必是候選碼,但是這樣的形式不能在SQL中直接聲明。SQL標準為其提供了更為普遍的結構,但是,任何廣泛使用的數據庫系統都不支持這些替代結構。

當違反引用完整性約束時,通常的處理時拒絕執行破壞完整性的操作(即執行更新操作的事務回滾)。但是,在外碼子句中可以顯示指定其他策略。請考慮course關系上一個完整性約束的如下定義。

create table course (... foreign key (dept_name) references departmenton delete casecadeon update casecase, ...);

上面制定了外碼聲明相關聯的級聯刪除子句,如果刪除department中的一個元組導致違反了這種引用完整性約束,則系統并不拒絕該刪除,而是進行級聯刪除,即刪除引用了被刪除的系(department)的課程(course)元組。

除了級聯,還可以指定其他策略,比如使用set null將引用域(這里是dept_name)置為null,或者置為該域的缺省值(set default)

如果存在跨多個關系的外碼依賴鏈,則在鏈的一端所做的刪除或者更新可能級聯傳遞至整個鏈上。

空值會使SQL的引用完整性約束變得更加復雜,這里我們暫時不討論。

4.5 給約束賦名

我們可以使用關鍵字contranit為完整性約束賦名,這樣在刪除約束時很有用。比如。

salary numeric(8,2), constraint minsalary check(salary > 29000),

當我們刪除約束時,可以

alter table drop constraint minsalary;

如果名稱缺失,就需要用特定于系統的功能來識別出約束的系統分配名稱。并非所有系統都支持這樣的功能,但是在比如Oracle中,系統表user_constraints就包含了這樣的信息。

4.6 事務中對完整性約束的違反

事務可能包含多個步驟,在某一步也許會暫時違反完整性約束,但是后面的某一步也許就會消除這個違反。例如,假設我們有一個主碼為name的person關系,還有一個spouse屬性,并且假設spouse是在person上的一個外碼。也就是說,該約束要求spouse屬性必須是在person表中出現的姓名。假設我們在關系中插入兩個元組,一個是關于John的,另一個是關于Mary的,他們互為配偶,無論先插入哪個,都會導致違反該外碼約束,直到另一個元組也被插入。

為了處理這樣的情況,SQL標準允許將initially deferred子句加入約束聲明中,這樣約束就不是在事務的中間步驟去檢查,而是在事務的結束時去檢查。一個約束可以被指定為可延遲的(deferrable),這樣在缺省情況它會被立即檢查,但是在需要時可以延遲檢查。對于這種約束,將使用set constraints constraint-list deferred語句的的執行將作為事務的一部分,從而導致對約束的檢查被延遲到事務結束時執行。在約束列表中出現的約束必須指定名稱。缺省方式是立刻檢查約束,并且許多數據庫實現不支持延遲約束檢查。

如果spouse可以置為null,可以在插入John和Mary元組時,將其spouse屬性置為null,后面再更新值,但這會加大編程量,但屬性必須非空時,這種方法就不可行。

4.7 復雜check條件與斷言

在SQL標準中還有其它結構用于指定大多數系統當前不支持的完整性約束。可以通過check子句中復雜謂詞實現更復雜的數據完整性需求,這里我們不贅述。

一個斷言就是一個謂詞,他表達我們希望數據庫總能滿足的一個條件,比如:每個教師不能在同一個學期的同一個時間段在兩個不同的教室授課。

斷言和復雜check條件都需要相當大的開銷,如果系統支持觸發器,可以使用觸發器實現等價的功能。

5.SQL的數據類型與模式

5.1 SQL中的日期和時間類型

SQL中支持的日期和時間相關的數據類型有:

  • 日期(date)。年月日。必須按照2018-04-05這種格式指定。
  • 時間(time)。時分秒。可以使用變量time(p)來指定秒的小數點后的數字位數(缺省值為0),通過指定time with timezone,還可以把時區信息連同時間一起存儲。必須按照09:20:00格式指定,秒后的小數點位數可以變長。
  • 時間戳(timestamo):date和time的結合。可以使用變量timesamp(p)來指定秒的小數點后的數字位數(缺省值為6)。通過指定with timezone,可以把時區信息連同時間一起存儲。必須按照2018-04-25 10:29:01.45格式指定,秒后的小數點位數可以變長。

我們可以利用extract(field from d)來從date或time值d中提取出單獨的域,這里的域(field)可以是year,month,day,hour,minute或者second中的一種。時區信息可以使用timezone_hour和timezone_minute來提取。

SQL定義了一些函數來獲取當前的日期和時間。例如,current_date返回當前日期,current_time返回當前時間(帶有時區),還有localtime返回當前的本地時間(不帶時區)。時間戳(日期加上時間)由current_timestamp(帶有時區)以及localtimestamp(本地,不帶時區)返回。

保留Mysql在內的某些系統提供了datetime數據類型用來表示時區不可調整的時間。在實踐中,時間規范會有許多的特殊情況。

SQL還支持interval數據類型,它表示時間區間

5.2 類型轉換和格式化函數

我們可以使用形如cast(e as t)的表達式來將表達式e轉換為類型t。可能需要數據類型轉換來執行特定的操作或者強制保證特定的排序次序。例如,請考慮instructor的ID屬性,我們已經將其指定為字符串(varchar(5)),如果我們按此屬性排序輸出,則ID11111位于ID9之前,因為第一個字符‘1’在‘9’之前。我們可以強轉獲得我們想要的排序。

select cast(ID as numeric(5)) as inst_id from instructor order by inst_id;

作為查詢結果顯示的數據可能需要不同類型的轉換,例如,我們可能希望數值以特定位的數字顯示,或者數據以特定格式來顯示。顯示格式的轉換并不是數據類型的轉換,而是格式的轉換。不同數據庫產品提供了不同的格式化函數。Mysql提供了format函數,Oracle和PostgreSQL提供了一組函數,to_char,to_number和to_date.SQL Server提供了convert函數。

結果顯示的另一個問題就是處理空值,在本書中,我們使用null來使閱讀更清晰,但是大多數系統的缺省設置只是將字段留空。可以使用coalesce函數來選擇在查詢結果中輸出空值的方式。該函數接受任意數量的參數(所有參數必須是相同的類型),并返回第一個非空參數。例如,如果我們希望顯示教師的ID和工資,但是將空工資顯示為0,我們會寫:

select ID,coalesce(salary, 0) as salary from instructor

coalesce的一個限制就是所有參數必須是相同的類型,如果我們希望將空工資顯示為N/A以表示為不可用,就無法使用coalesce。諸如Oracle提供了**解碼(decode)**函數允許這種轉換,解碼的一般形式是:

decode(value, match-1,replacement-1,match-2,replacement-2,...,match-n,replacement-n,default-replacement);

它將value與match值進行比較,匹配則替換,有點類似程序語言中的switch-case結構。

我們可以這樣實現前面的需求

select ID,decode(salary, null, 'N/A', salary) as salary from instructor;

5.3 缺省值

可以在創建表時指定屬性缺省值。

create table student (ID varchar(5), name varchar(20) not null, to_cred numeric(3,0) default 0, primary key(ID));

5.4 大對象類型

SQL為字符型數據(clob)和二進制數據(blob)提供了大對象數據類型(large-object data type)。例如,

book_review clob(10KB) image blob(10MB)

把一個大對象放入內存是非常低效而且不顯示的,應用程序通常用一個SQL查詢出大對象的"定位器",然后用宿主語言操作這個對象,例如JDBC應用程序接口允許獲取一個定位器,用這個定位器來一點一點取出這個大對象,而不是一次全部取出。

5.5 屬性的時態有效性

在某些情況下可能需存儲歷史數據,比如,我們希望不僅存儲每位教師的當前工資,而且存儲整個工資歷史,可通過向instructor關系模式添加兩個屬性來指定給定工資值的開始時間和結束時間,這些開始日期和結束日期被稱為相對應工資值的有效時間值

請注意在這種情況下,instructor關系中可能存在不止一個具有相同ID值得元組,后續文章將討論在時態數據的上下文中特定主碼和外碼約束的問題。

對支持這種時態結構的數據庫系統來說,第一步就是提供語法來支持指定特定屬性來定義有效的時間區間,比如我們使用Oracle12的語法示例。使用如下的period聲明來擴充instructor的SQL DDL,以表明start_date和end_date屬性指定了一個有效的時間區間。

create table instructor ( ... start_date date, end_date date, period for valid_time(start_date, end_date), ... );

在進行查詢時則使用as of period for結構,以僅獲取其特定有效時間的那些元組。比如

select name,salary,start_date,end_date from instructor as of period for valid_time '20-JAN-2014';

結合between and可以查找時間段。

5.6 用戶自定義類型

SQL支持兩種形式的用戶自定義數據類型,第一種是獨特類型(distinct type),另一種是結構化數據類型(structured data type),允許創建具有嵌套記錄結構、數組和多重集的復雜數據結構,本文介紹前者,后續文章將介紹結構化數據類型。

教師姓名和系的姓名都是字符串,然而我們通常并不認為把一個教師的姓名賦給一個系名,把一個以美元表示的貨幣值與以英鎊表示的貨幣值進行直接比較是合法的。一個好的類型系統應該能夠檢測出這類賦值或者比較,為了支持這種檢測,SQL提供了distinct type的概念,可以定義新類型,如:

create type Dollars as numeric(12,2) final; create type Pounds as numeric(12,2) final;

這樣我們就可以創建下表。

create table department( dept_name varchar(20), building varchar(15), budget Dollars);

由于強類型轉換,表達還(department.budget + 20)將不被接受,可以將budget 強轉為numeric,但是如果需要存回Dollars類型的屬性中,又需要轉換為Dollars類型。

可以使用drop type和alter type子句刪除或者修改以前創建過的類型。

SQL-1999提出創建類型前,還有一個類似概念,創建域domain,二者其實有重大差異,不過大多數數據庫實現并沒有支持創建類型和創建域,這里不做展開。

一個創建域的例子是。

create domain degree_level varchar(10)constraint degree_level_testcheck (value in 'Bachelors','Masters','Dectorate'));

5.7 生成唯一碼值

數據庫系統提供了生成唯一碼值的自動管理,具體語法依賴于數據庫實現。這里我們展示的語法接近Oracle和DB2的語法。

ID number(5) generated always as identity

當使用always選項是,在insert語句是必須避免為相關屬性指定值。如果使用by default則可以選擇是否指定我們自己挑選的ID。

在PostgreSQL中,我們可以將ID類型定義為serial,它告訴PostgreSQL要自動生成標識。在Mysql中,我們使用auto_increment來實現自動生成唯一自增碼值。

此外,許多數據庫都支持創建序列結構,該結構創建域任何關系分離的序列計數器對象,并允許SQL查詢從序列中獲得下一個值,每次獲得的值遞增。這樣,多個關系之間的(如student.ID與instructor.ID)也可以保持唯一。

5.8 create table的擴展

應用常常要求創建域現有的某個表模式相同的表,SQL提供了語法支持。

create table temp like instructor;

在編寫一個復雜查詢時,把查詢的結果存儲成一個新表通常是有用的。SQL:2003提供了一種簡單的支持。

create table t1 as (select * from instuctor where dept_name = 'music') with data;

上面SQL創建了臨時表t1并且把查詢的數據存儲到了t1。通過在關系名后面列出列名,還可以顯示的指定列的名稱。

許多數據庫實現還支持缺省with data但也載入數據,不同數據庫對create table ...like和create table ...as的語法支持并不完全相同,請查閱文檔。

我們發現create table ... as與create view很相似,兩者都是用查詢來定義的。當表創建時表的內容就被加載了,但是視圖內容總是反應當前查詢的結構。

5.9 模式、目錄與環境

現代的數據庫系統提供了三層體系結構用于關系的命名。

體系結構的最頂層由目錄(catalog)構成(一些數據庫實現也將這層稱為數據庫),每個目錄都可以包含模式,視圖和關系等SQL對象都包含在模式中。

為了在數據庫上執行任何操作,用戶(或程序)都必須先連接到數據庫。用戶必須提供用戶名,通常還需要提供密碼來驗證身份。每個用戶有一個唯一的缺省目錄和模式,當一個用戶連接到數據庫系統時,系統將為其連接缺省的目錄和模式。

我們可以這么唯一表示一個關系

catalog2.univ_schema.course

如果目錄(模式)為缺省目錄(模式),可以省略。

缺省的目錄和模式是為了每個連接建立的**SQL環境(SQL environment)**的一部分,環境還包括用戶標識(也稱為授權標識(authorization identifier))。所有通常的SQL語句都在一個模式的環境中運行。

可以使用create schema和drop schema語句來創建和刪除模式。在大多數數據庫系統中,模式還隨著用戶賬戶的創建而自動創建,此時模式名被置為用戶賬戶名。模式要么建立在缺省目錄中,要么建立在創建用戶是所指定的目錄中,新創建的模式將成為該用戶的缺省模式。

目錄的創建和刪除根據數據庫的實現不同而不同,這并不是SQL標準的一部分。

6.SQL中的索引定義

關系屬性上索引(index)是一種數據結構,它允許數據庫系統高效的找到元組,而不必掃描整個數據庫的所有元組。

其語法是

create index dept_idx on instructor(dept_name);

上面創建了關于dept_name的索引,這樣在查找dept_name為’music’的instructor元組時效率會變高。

如果我們想要聲明一個搜索碼就是候選碼,那么需要在索引定義是增加屬性unique

create unique index dept_idx on instructor(dept_name);

如果我們輸入create unique index時,dept_name并不是一個候選碼,那么系統會顯示錯誤信息,索引創建會失敗。如果索引創建成功,則后面違反候選碼聲明的任何元組插入企圖將會失敗。請注意,如果數據庫系統支持標準的唯一性聲明,這里的唯一性特性就是多余的。

刪除索引。

drop index dept_idx;

7.授權

7.1 權限的授予與收回

SQL標準包括的權限由:選擇(select)、插入(insert)、更新(update)、刪除(delete),所有權限(all previlege)。創建一個關系的用戶默認被授予該關系的所有權限。一個授權的sql示例是:

grant select on department to Amit,Satoshi;

更新授權可以指定屬性列表,缺省時為所有屬性。

grant update(budget) on department to Amit,Satoshi;

關系上得插入授權也可以指定屬性列表,對關系的任何插入只針對這些屬性,系統的其余屬性要么賦缺省值(定義缺省值前提下),要么將其置空。

刪除與查詢權限類似。

public代指系統的所有當前用戶及將來的用戶,對public授權隱含著對當前所有用戶和將來的用戶授權。

在缺省情況下,權限接受者不可將權限授予其他用戶,但是SQL可以授予權限接受者進一步將權限授予給其他用戶、角色。

使用invoke可以收回權限。與授權的語法幾乎一致。

invoke select on department from Amit,Satoshi;

如果被收回權限的用戶已經把權限授予給了其他用戶,那么權限的收回會更加復雜,后文討論。

7.2 角色

教師、學生是不同的角色(role),一個角色類型可能需要同樣的權限。比如教師需要授予一類權限,無論何時指派一個新的教師,都應該獲取這些權限。

可以授予用戶的任何權限都可以授予角色。創建角色語法如下。

create role instructor;

授予角色權限的語法與用戶也一樣。

grant select on takes to instructor;

角色可以授予用戶,也可以授予其他角色。

create role dean; grant instructor to dean; grant dean to Satoshi;

用戶或者角色被授予了角色后,就會繼承該角色的所有權限。

7.3 視圖的授權

考慮一個工作人員需要知道地質系的所有員工工資,但是無權看到其他系中的員工相關信息。可以通過給該工作人員視圖授權實現需求。

創建視圖必須要首先擁有關系的選擇權限,并且,視圖的創建者并不會獲得視圖的所有權限。如果一個用戶在關系上沒有更新權限,即使它創建了該關系的視圖,也不能在視圖上獲得更新權限。

在函數和過程上可以授予執行權限,以允許用戶執行該函數和過程。在缺省情況下,函數和過程擁有其創建者所擁有的所有權限。在效果上,函數和過程的運行就像他被其創建者調用了一樣(實際上不一定其創建者就是其調用者)。在SQL:2003開始,如果函數定義有一個額外的sql security invorker子句,那么它就在調用該函數的用戶權限下執行,而不是函數定義者的權限下執行。

7.4 模式的授權

SQL標準為數據庫模式指定了一種基本的授權機制:只有模式的擁有者才能夠執行對模式的任何修改,比如創建刪除關系,對關系的屬性增刪改查等等。

但是,SQL提供了一種引用(reference)權限,它允許一個用戶在創建關系時聲明外碼。語法如下。

grant references(dept_name) on department to Mariano;

為何需要對引用授權呢?乍一看沒必要限制用戶引用其他關系的外碼。但是,請回想下:外碼約束限制了被引用關系的刪除和更新操作。假如Mariano在關系r上創建了一個外碼,引用department的dept_name屬性,然后在r中插入一條屬于地質系的元組,那么除非同時修改關系r,否則再也不可能將地質系在department中刪除了~

參考如下示例,創建一個復雜check約束的情況,可能會影響被引用關系time_slot的更新,也需要授予time_slot上的引用權限,原因與外碼約束一樣。

check(time_slot_id in (select time_slot_id from time_slot))

7.5 權限的轉移

可以增加參數with grant option允許獲得權限的用戶將權限授權給其他用戶。

grant select on department to Amit,Satoshi with grant option;

權限的傳遞可以用授權圖表示,節點就是用戶。

一個用戶獲得權限的充要條件是,當且僅當存在授權圖的根到該用戶節點的路徑。

7.6 權限的級聯收回

上游用戶的權限回收,會導致下游用戶的權限也被回收。比如回收U1的權限,則U21也會被回收權限,但是U22還存在上游U2,因此還擁有權限。這被稱為級聯收權(cascading revocation)。大多數數據庫系統中,級聯收權是默認缺省方式,但是收權語句可以限定來防止級聯收權。

revoke select on department from Amit restrict;

可以把授權權限當成普通權限回收。下面就是回收授權權限,但并不會回收選擇權限。注意并不是所有數據庫都支持該語法。

revoke grant option for select on department from Amit restrict;

級聯收權在許多情況下是不合適的,比如Satishi具有Dean角色,他將instructor權限授予了Amit,即使Satishi退休權限被回收了,Amit還是一個好老師。

為了避免這種情況,SQL允許權限通過角色來授予,而不是通過用戶來授予。SQL有一個與會話相關的當前角色概念。在缺省情況下,一個會話所關聯的當前角色是空。可以通過set role rolename來指定當前會話的角色,在當前會話角色不為空的情況下,我們可以在授權時以角色的身份授權而不是用戶的身份授權。具體語法是為授權語句增加子句:

granted by current_role

7.7 行級授權

一些數據庫系統(Oracle,SQL Server和PostgreSQL)在特定的元組級別提供了細粒度的授權機制。

假如我們允許學生在takes中查看他自己的數據但是不允許查看其他用戶的數據,可以使用行級授權。

Oracle虛擬私有數據庫(Virtual Private Database,VPD)功能支持如下所示的行級授權,允許系統管理員將函數與關系相關聯,該函數返回一個謂詞,該謂詞會自動被添加到使用該關系的任何查詢中。該謂詞可以使用sys_context函數,它返回代表正在執行查詢的用戶的標識。對于需求:允許學生在takes中查看他自己的數據但是不允許查看其他用戶的數據,可以指定如下謂詞:

ID = sys_context('USERENV''SESSION_USER')

系統將此謂詞添加到使用takes關系的每個查詢的where子句中,每個學生就只能看到與其ID相匹配的那些takes元組。但這樣做有一個顯著的隱患,就是可能改變查詢的含義,比如一個用戶需要查找所有課程的平均成績,最后只會得到它的成績的平均值。

總結

以上是生活随笔為你收集整理的【数据库04】中级开发需要掌握哪些SQL进阶玩法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。