1. 程式人生 > 其它 >CMU15445 Lecture 2 Advanced SQL

CMU15445 Lecture 2 Advanced SQL

本節介紹SQL的高階用法

關係型語言

當用戶使用宣告式語言,他只需要說明他所需要的結果。DBMS會優化產生結果的過程。

Relational algebra是基於集合(無序,不可重複),而SQL是基於揹包(無序,可重複)

SQL歷史

SQL來源於IBM的System R專案。其主要由三種命令組成:

  • DML(Data Manipulation Language),SELECT, INSERT, UPDATE 和 DELETE等語句
  • DDL(Data Definition Language),對於表,索引,檢視,或其它物件的Schema的定義,就是建表,建索引的語句之類的
  • DCL(Data Control Language),許可權控制,訪問控制
  • 當然還有一些操作,諸如view的定義,完整性或引用約束,事務的開啟與關閉等

SQL的一些高階語法

展示語法所用的資料庫例項:

CREATE TABLE student (
sid INT PRIMARY KEY,
name VARCHAR(16),
login VARCHAR(32) UNIQUE,
age SMALLINT,
gpa FLOAT
);
CREATE TABLE course (
cid VARCHAR(32) PRIMARY KEY,
name VARCHAR(32) NOT NULL
);
CREATE TABLE enrolled (
sid INT REFERENCES student (sid),
cid VARCHAR(32) REFERENCES course (cid),
grade CHAR(1)
);

Aggreates

  • MAX(col),返回一列中值的最大值
  • MIN(col),返回一列中值的最小值
  • AVG(col),返回一列中值的平均值
  • SUM(col),返回一列中值的和
  • COUNT(col),用於返回一列中值的#

如果想在student表中查詢有著以'@cs'結尾的login的學生的數量可以這樣寫(有三種方式)

SELECT COUNT(*) FROM student WHERE login LIKE '%@cs';
SELECT COUNT(login) FROM student WHERE login LIKE '%@cs';
SELECT COUNT(1) FROM student WHERE login LIKE '%@cs';

也可以在一條SELECT語句中使用多個aggregates函式

SELECT AVG(gpa), COUNT(sid)
FROM student WHERE login LIKE '%@cs';


一些aggreagate函式支援DISTINCT關鍵字

SELECT COUNT(DISTINCT login)
FROM student WHERE login LIKE '%@cs';


輸出相對於一個aggregate的其他列,會出錯,該語句中e.cid是未定義的

SELECT AVG(s.gpa), e.cid
FROM enrolled AS e, student AS s
WHERE e.sid = s.sid;


這個時候需要用到group by命令,

SELECT AVG(s.gpa), e.cid
FROM enrolled AS e, student AS s
WHERE e.sid = s.sid
GROUP BY e.cid;

如此一來就可以正確的顯示了,將tuples按照group by劃分為子集,再對子集做aggregate

另外,可以使用HAVING子句對aggregation之後的結果做過濾,HAVIN就像是GROUP BY的WHERE子句

SELECT AVG(s.gpa) AS avg_gpa, e.cid
FROM enrolled AS e, student AS s
WHERE e.sid = s.sid
GROUP BY e.cid
HAVING avg_gpa > 3.9;

字串操作

雖然MYSQL對於字母大小寫不敏感,並且使用雙引號與單引號皆可,但其他SQL不是這樣的

模式匹配:

  • "%"匹配任何的子串(包括空串)
  • "_"匹配任意一個字元
    字串連線:
  • "||"用來連線兩個字串

輸出重定向

除了將查詢結果顯示到終端,可以將結果放一個新的表中,可以用如下語句:

  • 新建表:
SELECT DISTINCT cid INTO CourseIds FROM enrolled;
  • 對於已經存在的表,可以將SELECT插入到資料庫中已經存在的表中,SELECT的查詢結果必須與表的列的數量與屬性的型別一致,但是列名可以不一樣:
INSERT INTO CourseIds (SELECT DISTINCT cid FROM enrolled);

輸出控制

可以用ORDER BY對SQL的結果進行排序,可以用謂詞ASCDESC與屬性去對結果做想要的排序

SELECT sid FROM enrolled WHERE cid = '15-721' ORDER BY grade DESC;
SELECT sid FROM enrolled WHERE cid = '15-721' ORDER BY grade DESC, sid ASC;
SELECT sid FROM enrolled WHERE cid = '15-721' ORDER BY UPPER(grade) DESC, sid + 1 ASC;

可以用LIMIT子句限定查詢結果的tuple的數量

SELECT sid, name FROM student WHERE login LIKE '%@cs'
LIMIT 10;

也可以提供一個位移來到達獲取一個範圍的結果

SELECT sid, name FROM student WHERE login LIKE '%@cs' LIMIT 10 OFFSET 20;

如果不使用ORDER BY,那麼使用LIMIT每次返回的結果可能不同

內嵌查詢

inner queries和out queries組成一個nested queries,inner queries可以引用outer queries中的內容,但反過來不行
一個例子是,獲取註冊了15-445的學生的名字

SELECT name FROM student WHERE sid IN ( SELECT sid FROM enrolled WHERE cid = '15-445' );

內嵌查詢支援的謂詞:

  • ALL: 所有 inner queries 返回的記錄都必須滿足條件
  • ANY:任意 inner queries 返回的記錄滿足條件即可
  • IN:與 = ANY() 等價
  • EXISTS:inner queries 返回的表不為空
    ANY的用法,獲取註冊了15-445的學生的名字
SELECT name FROM student
 WHERE sid = ANY (
   SELECT sid FROM enrolled
    WHERE cid = '15-445'
 )

ALL,IN的用法,找到至少參與一門課程的所有學生中,id 最大的

SELECT sid, name FROM student
 WHERE sid >= ALL (
   SELECT sid FROM enrolled
 );

SELECT sid, name FROM student
 WHERE sid IN (
   SELECT MAX(sid) FROM enrolled
 );

SELECT sid, name FROM student
 WHERE sid IN (
   SELECT sid FROM enrolled
    ORDER BY sid DESC LIMIT 1
 );

NOT 的用法

SELECT * FROM course
 WHERE NOT EXISTS (
   SELECT * FROM enrolled
    WHERE course.cid = enrolled.cid
 );

nested queries 比較難被優化(具體原因暫不知道)

DATA/TIME OPERAIONS

用來操作與修改DATA/TIME屬性,每個SQL的用法差別極大

視窗函式

類似於聚合函式,但是會保留原tuple的所有元素



Common Table Expressions(CTE)

CTE就像對於一次查詢的生成一個臨時的表,使用WITH子句來繫結一個子查詢的結果給WITH子句所給定的名字

關於遞迴CTE,可以檢視這篇文章

參考

note2