SQL 操作
檢索數據 SELECT
檢索數據
-- 檢索單個列
SELECT 列名 FROM table_name;-- 檢索多個列
SELECT 列1, 列2 FROM table_name;-- 檢索所有列
SELECT * FROM table_name;-- 檢索不同的值
SELECT DISTINCT 列名 FROM table_name;
限制檢索結果
-- SQL Server / Access
SELECT TOP 5 列名 FROM table_name;-- DB2
SELECT 列名 FROM table_name FETCH FIRST 5 ROWS ONLY;-- Oracle
SELECT prod_name FROM table_name WHERE ROWNUM <= 5;-- MySQL / MariaDB / PostgreSQL / SQLite
SELECT prod_name FROM table_name LIMIT 5;-- MySQL 從第六行開始,檢索五行
SELECT prod_name FROM table_name LIMIT 5 OFFSET 6;-- MySQL 與 MariaSQL 快捷鍵,上一條語句等價于:
SELECT prod_name FROM table_name LIMIT 5,6
排序檢索數據 ORDER BY
-- 按單個列排序,默認從小到大
SELECT field1, field2 from table_name ORDER BY field1;-- 按多個列排序,先按第一個排,第一個相同再按第二個排
SELECT field1, field2 from table_name ORDER BY field1, field2;-- 按列位置排序
SELECT field1, field2 from table_name ORDER BY 4,5;-- 降序排序,與DESC相對的是ASC,但ASC是默認的,DESC只作用于他前面的那一列
SELECT field1, field2 from table_name ORDER BY field1 DESC,field2 DESC;
過濾數據 WHERE
-- ORDER BY 語句應該始終放在最后
SELECT field1, field2 FROM table_name WHERE field1 = 3;
WHERE操作符
操作符 | 說明 |
---|---|
= | 等于 |
!=或<> | 不等于 |
<(>) | 小于(大于) |
<= (》=) | 小于等于(大于等于) |
!< | 不小于 |
!> | 不大于 |
BETWEEN | 在指定兩個值之間 |
IS NULL | 為NULL值 |
-- 范圍檢查,范圍需要用AND連接,包括邊界
SELECT * FROM stu WHERE grade BETWEEN 70 AND 100;
+----+----------+-----+-------+---------------------+
| id | name | sex | grade | birthday |
+----+----------+-----+-------+---------------------+
| 1 | zhangsan | boy | 99 | 2019-09-12 19:21:31 |
| 3 | wangwu | boy | 77 | 2019-09-03 19:22:52 |
| 4 | zhaoliu | boy | 77 | 2019-09-10 19:28:22 |
+----+----------+-----+-------+---------------------+
3 rows in set (0.33 sec)
高級數據過濾
-- AND 操作
SELECT * FROM stu WHERE grade>90 AND sex = "boy";-- OR 操作
SELECT * FROM stu WHERE grade > 90 OR grade < 60;-- IN 操作
SELECT * FROM stu WHERE name IN ('zhangsan', "lisi");-- NOT操作
SELECT * FROM stu WHERE NOT name IN ('zhangsan', "lisi");
- AND 操作符優先級高于OR,可以加括號改變優先級
- IN比OR執行更快
- IN可以包含其他SELECT語句
- NOT否定跟在它后面的語句
使用通配符進行數據過濾 LIKE
通配符 | 作用 |
---|---|
% | 匹配任何字符出現任意次 |
_ | 匹配單個字符 |
[] | 匹配指定位置的一個字符(只有SQL Server支持) |
-- 匹配name中帶有n的字段
select * from stu where name like "%n%";-- 匹配name以z或w開頭的字段(SQL Server)
select * from stu where name like "[zw]%";
- 通配符搜索耗時比其他搜索長,不要依賴于通配符搜索
創建計算字段
計算字段并不存在于數據庫,只是在執行SELECT語句時生成的
拼接字段
DBMS | 符號 |
---|---|
Access, SQL Server | + |
DB2,Oracle,PostgreSQL,SQLite,Open Office Base | || |
Mysql,MariaDB | 使用Concat() 函數 |
-- SQL Server
SELECT name + "(" + grade + ")" FROM stu ORDER BY grade;-- MySQL
SELECT CONCAT(name,"(",grade,")") FROM stu ORDER BY grade;
+----------------------------+
| CONCAT(name,"(",grade,")") |
+----------------------------+
| lisi(66) |
| wangwu(77) |
| zhaoliu(77) |
| zhangsan(99) |
+----------------------------+
使用別名
-- SQL Server
SELECT
name + "(" + grade + ")" AS new_name
FROM stu ORDER BY grade;-- MySQL
SELECT CONCAT(name,"(",grade,")") AS new_name
FROM stu ORDER BY grade;
+--------------+
| new_name |
+--------------+
| lisi(66) |
| wangwu(77) |
| zhaoliu(77) |
| zhangsan(99) |
+--------------+
執行算數運算
支持 +,-,*,/
SELECT * ,
grade*0.1 AS new_grade
FROM stu ORDER BY grade;
+----+----------+-----+-------+---------------------+-----------+
| id | name | sex | grade | birthday | new_grade |
+----+----------+-----+-------+---------------------+-----------+
| 2 | lisi | boy | 66 | 2019-09-04 19:22:05 | 6.6 |
| 3 | wangwu | boy | 77 | 2019-09-03 19:22:52 | 7.7 |
| 4 | zhaoliu | boy | 77 | 2019-09-10 19:28:22 | 7.7 |
| 1 | zhangsan | boy | 99 | 2019-09-12 19:21:31 | 9.9 |
+----+----------+-----+-------+---------------------+-----------+
4 rows in set (0.00 sec)
函數
每個DBMS都支持自己特定的函數,只有少數函數被大多DBMS支持
數據處理函數
文本處理函數
函數 | 說明 |
---|---|
LEFT() | 返回字符串左邊的字符 |
RIGHT() | 返回字符串右邊字符 |
LENGTH()或DATALENGTH()或LEN() | 返回字符串長度 |
LOWER() Access使用LCASE() | 將字符串轉換為小寫 |
UPPER() Access使用UCASE() | 將字符串轉換為大寫 |
LTRIM() | 去掉字符串左邊空格 |
RTRIM() | 去掉字符串右邊空格 |
SOUNDEX() | 返回字符串的SOUNDEX值 |
- soundex是判斷讀音是不是相同,可惜中文不行,有趣的是這個算法發明的時間比計算機發明的時間還早,哈哈哈
mysql> SELECT * FROM stu WHERE SOUNDEX(name) = SOUNDEX("enn");
+----+------+-----+-------+---------------------+
| id | name | sex | grade | birthday |
+----+------+-----+-------+---------------------+
| 5 | en | boy | 33 | 2019-09-29 20:41:41 |
+----+------+-----+-------+---------------------+
時間日期處理函數
-- SQL Server
SELECT * FROM stu WHERE DATEPART(yy, birthday) = 2012;-- Access
SELECT * FROM stu WHERE DATEPART("yyyy", birthday) = 2012;-- PostgreSQL
SELECT * FROM stu WHERE DATE_PART('year', birthday) = 2012;-- Oracle
SELECT * FROM stu WHERE to_number(to_char(birthday,'yyyy')) = 2012;-- MySQL MairiaDB
SELECT * FROM stu WHERE YEAR(birthday) = 2012;-- SQLite
SELECT * FROM stu WHERE strftime('%Y', birthday) = 2102;
數值處理函數
函數 | 說明 |
---|---|
ABS() | 絕對值 |
COS(),SIN(),TAN() | 余弦,正弦,正切 |
PI() | 圓周率 |
EXP() | 指數 |
SQRT() | 平方根 |
聚集函數
SQL聚集函數
函數 | 說明 |
---|---|
AVG() | 返回某列平均值 |
COUNT() | 返回某列行數 |
MAX() MIN() | 返回某列最大最小值 |
SUM() | 返回某列之和 |
- COUNT(*)對表中所有行計數,不管是否包含空值
- COUNT(列)對特定列中具有特定值的行計數,忽略空值
- 可以使用DISTINCT聚集不同的值(Access不支持)
SELECT
COUNT(*) AS count_num,
AVG(DISTINCT grade) AS avg_grade,
MAX(grade) AS max_grade,
MIN(grade) AS min_grade,
SUM(grade) AS sun_grade
FROM stu;
+-----------+-----------+-----------+-----------+-----------+
| count_num | avg_grade | max_grade | min_grade | sun_grade |
+-----------+-----------+-----------+-----------+-----------+
| 6 | 74.2000 | 99 | 33 | 448 |
+-----------+-----------+-----------+-----------+-----------+
1 row in set (0.00 sec)
分組數據 GROUP BY
select grade, count(*) AS nums from stu group by grade;
+-------+------+
| grade | nums |
+-------+------+
| 99 | 1 |
| 66 | 1 |
| 77 | 2 |
| 33 | 1 |
| 96 | 1 |
+-------+------+
5 rows in set (0.00 sec)
- GROUP BY 子句可以包含任意數目的列,因此可以對分組進行嵌套,進行更細致的分組
- 如果嵌套了分組,數據將在最后指定的分組上進行匯總。(所有列一起計算)
- GROUP BY 子句中列出的每一列都必須是檢索列或有效的表達式(不能是聚集函數),如果在SELECT中使用表達式,則必須在GROUP子句中指定相同的表達式,不能使用別名.
- 大多數DBMS不允許GROUP BY 帶有長度可變的數據類型
- 除聚集計算語句外,SELECT語句中的每一列都必須在GROUP BY中給出
- 如果分組列中包含一個NULL值,則NULL作為一個分組返回,多個NULL作為一個分組。
- GROUP BY應該出現在WHERE之前,ORDER BY 之前。
過濾分組 HAVING
select grade, count(*) AS nums from stu group by grade having grade > 60;
+-------+------+
| grade | nums |
+-------+------+
| 99 | 1 |
| 66 | 1 |
| 77 | 2 |
| 96 | 1 |
+-------+------+
4 rows in set (0.10 sec)
HAVING 與 WHERE 的區別:
WHERE在數據分組前進行過濾,HAVING在數據分組后進行過濾,WHERE排除的行不包括在分組中,這可能會改變計算值,從而影響HAVING中基于這些值過濾掉的分組。
如果不指定GROUP BY 大多數DBMS會同等對待他們,不過,使用HAVING時應該結合GROUP BY 而WHERE應該用于標準的行級過濾。
分組和排序
GROUP BY 與 ORDER BY 經常完成相同的工作,但他們非常不同,ORDER BY 是對產生的輸出進行排序,而GROUP BY 是對行進行排序,但輸出的可能不是分組的順序,所以在使用GROUP BY時,也應該給出ORDER BY 子句。
--- 除ACCESS外,大部分DBMS支持用別名排序
select grade, count(*) AS nums from stugroup by grade having grade > 60order by count(*);
+-------+------+
| grade | nums |
+-------+------+
| 66 | 1 |
| 96 | 1 |
| 99 | 1 |
| 77 | 2 |
+-------+------+
子查詢
select * from songs where singer in -> (select id from singer where name = "張靚穎");
+-----------+---------------------+--------------------------------------------------------+--------+
| id | name | link | singer |
+-----------+---------------------+--------------------------------------------------------+--------+
| 169794 | 天下無雙 | http://music.163.com/song/media/outer/url?id=169794 | 10561 |
| 327089 | 畫心 | http://music.163.com/song/media/outer/url?id=327089 | 10561 |
| 327163 | 我們說好的 | http://music.163.com/song/media/outer/url?id=327163 | 10561 |
| 327225 | 如果愛下去 | http://music.163.com/song/media/outer/url?id=327225 | 10561 |
| 5233037 | 另一個天堂 | http://music.163.com/song/media/outer/url?id=5233037 | 10561 |
| 31877130 | 餓狼傳說 (Live) | http://music.163.com/song/media/outer/url?id=31877130 | 10561 |
| 431853688 | 我的夢 (Live) | http://music.163.com/song/media/outer/url?id=431853688 | 10561 |
+-----------+---------------------+--------------------------------------------------------+--------+
7 rows in set (0.25 sec)
- 子查詢可以嵌套,但出于效能考慮,不應該嵌套過多。
作為計算字段使用子查詢
mysql> SELECT name,-> (SELECT COUNT(*) FROM songs WHERE songs.singer = singer.id) AS nums-> FROM singer WHERE type IN-> (SELECT id FROM singer_type WHERE type = "華語男歌手")-> ORDER BY name-> LIMIT 5;
+-----------------+------+
| name | nums |
+-----------------+------+
| “阿蘭姐” | 50 |
| 023 GC | 0 |
| A3 | 32 |
| abduwali tohti | 8 |
| ABSDJHONG | 22 |
+-----------------+------+
5 rows in set (0.69 sec)
聯結表
聯結是一種機制,用來在一條SELECT語句中關聯表,因此,稱為聯結
--- 等值聯結
mysql> SELECT songs.name,link,singer.name FROM songs,singer-> WHERE songs.singer = singer.id-> LIMIT 5;
+-----------------+----------------------------------------------------+--------+
| name | link | name |
+-----------------+----------------------------------------------------+--------+
| Happy Birth Day | http://music.163.com/song/media/outer/url?id=59867 | 阿信 |
| 幾年了 | http://music.163.com/song/media/outer/url?id=59870 | 阿杜 |
| Valentines Day | http://music.163.com/song/media/outer/url?id=59875 | 阿杜 |
| 再唱一首 | http://music.163.com/song/media/outer/url?id=59877 | 阿杜 |
| 圣堂之門 | http://music.163.com/song/media/outer/url?id=59886 | 阿沁 |
+-----------------+----------------------------------------------------+--------+
5 rows in set (0.01 sec)
- 創建表聯結時的WGERE語句非常重要,他作為過濾條件,只包含那些匹配給定條件的行,沒有聯結條件則會返回要聯結的表的笛卡爾積(叉聯結)
- 完全限定名:引用列可能出現歧義,這種情況應該使用
表名.列名
的完全限定名
內連接(inner-join)
上面的等值連接也叫內連接,可以顯式聲明聯結類型
mysql> SELECT songs.name, link, singer.name AS singer-> FROM songs INNER JOIN singer ON-> songs.singer = singer.id-> LIMIT 5;
+-----------------+----------------------------------------------------+--------+
| name | link | singer |
+-----------------+----------------------------------------------------+--------+
| Happy Birth Day | http://music.163.com/song/media/outer/url?id=59867 | 阿信 |
| 幾年了 | http://music.163.com/song/media/outer/url?id=59870 | 阿杜 |
| Valentines Day | http://music.163.com/song/media/outer/url?id=59875 | 阿杜 |
| 再唱一首 | http://music.163.com/song/media/outer/url?id=59877 | 阿杜 |
| 圣堂之門 | http://music.163.com/song/media/outer/url?id=59886 | 阿沁 |
+-----------------+----------------------------------------------------+--------+
5 rows in set (0.00 sec)
- SQL本身不限制聯結表的數量,但許多DBMS有限制
- 聯結表越多,性能下降越厲害
- 允許使用表別名(Oracle 不用 AS)
自聯結(self-join)
mysql> SELECT s1.name,s1.singer-> FROM songs AS s1,songs AS s2-> WHERE s1.singer = s2.singer AND s2.name="光年之外";
+-----------------------------+--------+
| name | singer |
+-----------------------------+--------+
| 來自天堂的魔鬼 | 7763 |
| 畫 (Live Piano Session II) | 7763 |
| 光年之外 | 7763 |
| 斷訊 | 916042 |
| 光年之外 | 916042 |
| 那個她 | 916042 |
+-----------------------------+--------+
6 rows in set (4.53 sec)
- 聯結中的兩張表是同一張表,必須使用別名區分。
- 許多DBMS處理自聯結比處理子查詢快。
自然聯結
自然聯結是一種特殊的等值聯結(內聯結),他要求兩個關系中進行比較的分量必須是同名的屬性組,并且在結果中把重復的屬性列去掉,事實上,我們迄今為止建立的每個內聯結都是自然聯結,也很可能永遠都不會用到不是自然聯結的內聯結。通常對一個表使用通配符(SELECT *)其他表使用明確的子集來完成。
mysql> SELECT s.* ,e.name-> FROM songs AS s,singer AS e-> WHERE s.singer = e.id AND e.name = "袁婭維";
外聯結
兩個關系R和S在做自然連接時,他們在公共屬性上值相等的元組構成新的關系,但是關系R中某些元組可能在關系S中不存在公共屬性上值相等的元組,從而造成R中的這些元組被舍棄了,同樣的S中的元組也有可能被舍棄,這些被舍棄的元組被稱為 懸浮元組
如果把懸浮元組也保存到結果關系中,而在其他屬性上填空值,這種聯結叫做外聯結,如果只保留左邊關系R中的懸浮元組就叫做左外連接,如果只保留右邊關系S中的懸浮元組就叫做右外連接。
-- 原來表的數據
mysql> select * from r;
+----+----+----+
| A | B | C |
+----+----+----+
| a1 | b1 | 5 |
| a1 | b2 | 6 |
| a2 | b3 | 8 |
| a2 | b4 | 12 |
+----+----+----+
4 rows in set (0.00 sec)mysql> select * from s;
+----+----+
| B | E |
+----+----+
| b1 | 3 |
| b2 | 7 |
| b3 | 10 |
| b3 | 2 |
| b5 | 2 |
+----+----+
5 rows in set (0.00 sec)-- 左外連接
mysql> SELECT r.*,s.*-> FROM r LEFT OUTER JOIN s-> ON r.b = s.b;
+----+----+----+------+------+
| A | B | C | B | E |
+----+----+----+------+------+
| a1 | b1 | 5 | b1 | 3 |
| a1 | b2 | 6 | b2 | 7 |
| a2 | b3 | 8 | b3 | 10 |
| a2 | b3 | 8 | b3 | 2 |
| a2 | b4 | 12 | NULL | NULL |
+----+----+----+------+------+
5 rows in set (0.00 sec)-- 右外聯結
mysql> SELECT r.*,s.*-> FROM r RIGHT OUTER JOIN s-> ON r.b = s.b;
+------+------+------+----+----+
| A | B | C | B | E |
+------+------+------+----+----+
| a1 | b1 | 5 | b1 | 3 |
| a1 | b2 | 6 | b2 | 7 |
| a2 | b3 | 8 | b3 | 10 |
| a2 | b3 | 8 | b3 | 2 |
| NULL | NULL | NULL | b5 | 2 |
+------+------+------+----+----+
5 rows in set (0.00 sec)
還有一種全外聯結(FULL OUTER JOIN)包含兩個表中不相關的行,Access,MariaDB,MySQL,Open Office Base,SQLite不支持。
使用帶聚集函數的聯結
組合查詢 UNION
mysql> SELECT id, name from singer where name="阿沁"-> UNION-> SELECT name, id FROM singer WHERE name="林俊呈";
+-----------+----------+
| id | name |
+-----------+----------+
| 1872 | 阿沁 |
| 林俊呈 | 30107224 |
+-----------+----------+
2 rows in set (0.07 sec)
- UNION 語句中必須包含相同的列,表達式或聚集函數(次序可以不同)
- 列數據類型必須兼容
- 只能使用一條ORDER BY 語句,位于最后一個select之后
- UNION會自動刪除相同的行,如果不希望這樣,可以使用 UNION ALL
插入數據 INSERT
-- 不安全
mysql> INSERT INTO stu-> VALUES(-> 7,-> "dapeng",-> "girl",-> 99,-> "2019-10-9 10:11:21");
Query OK, 1 row affected (0.09 sec)
應該給出列名(雖然更加麻煩),尤其是你只打算插入部分行時。
mysql> INSERT INTO stu(id,-> name,-> sex,-> grade)-> VALUES(8,-> "xiaowei",-> "girl",-> 99);
Query OK, 1 row affected (0.05 sec)
插入檢索出的數據
mysql> INSERT INTO stu(name,-> sex,-> grade,-> birthday)-> SELECT name,-> sex,-> grade,-> birthday-> FROM stu WHERE id = 1;
Query OK, 1 row affected (1.67 sec)
Records: 1 Duplicates: 0 Warnings: 0
- 可以從本表中檢索插入,也可以從其他表中檢索插入。
從一個表復制到另一個表 SELECT INTO
- DB2 不支持
-- MariaDB,MySQL,Oracle,PostgreSQL,SQLite
mysql> CREATE TABLE s_copy AS SELECT * FROM s;
Query OK, 5 rows affected (0.11 sec)
Records: 5 Duplicates: 0 Warnings: 0mysql> show tables;
+----------------------+
| Tables_in_sqlstudent |
+----------------------+
| r |
| s |
| s_copy |
| stu |
+----------------------+
4 rows in set (0.00 sec)-- 其他DBMS
SELECT * INTO s_copy FROM s;
更新和刪除數據
mysql> UPDATE stu-> SET sex="boy",-> birthday=Null-> WHERE name = "dapeng";
Query OK, 1 row affected (0.08 sec)
Rows matched: 1 Changed: 1 Warnings: 0
- 可以只寫一條UPDATE語句更新多列數據
- 部分DBMS支持FROM語法,把別的表中的數據更新到這張表里
- 不寫WHERE語句會更新所有行
- UPDATE允許使用子查詢
mysql> DELETE FROM stu WHERE id=2;
Query OK, 1 row affected (0.04 sec)
- 不寫WHERE語句會刪除所有數據
- DELETE不需要列名或通配符,應為它刪除的是整個行
- 如果想刪除所有行,應該使用TRUNCATE TABLE,它更快,所以無論何時,使用DELETE時記得加WHERE
創建和操縱表
刪除表
mysql> DROP TABLE s_copy;
Query OK, 0 rows affected (0.07 sec)
- 沒提示確認
創建表
mysql> CREATE TABLE Products(-> id int(255) NOT NULL,-> name VARCHAR(100) NULL-> );
Query OK, 0 rows affected (0.08 sec)
- 不同DBMS的表創建語句有差異
- 創建新表時,指定的表名必須不存在
- 創建表時字段允許為空則指定NULL,否則,如果要求插入時必須給出值,則指定為NOT NULL
NULL
不同于''
,前者是沒有值,后者是空字符串- 不指定時大部分DBMS默認為NULL,但DB2不指定會報錯
- 允許NULL值的列不允許作為主鍵
- DEFAULT 用來指定默認值,常用于時間或時間戳列
獲取系統日期
DBMS | 函數 |
---|---|
Access | NOW() |
DB2 | CURRENT_DATE |
MySQL | CURRENT_TIMESTAMP |
Oracle | SYSDATE |
PostgreSQL | CURRENT_DATE |
SQL Server | GETDATE() |
SQLite | date(‘now’) |
CREATE TABLE User
(id INT(255) NOT NULL,name VARCHAR(255) NOT NULL,create_time timestamp DEFAULT CURRENT_TIMESTAMP
);
更新表 ALTER TABLE
- 一般不要在表中包含數據時更新表
- 所有DBMS都允許怎加列,不過對所增加列的數據類型(NULL和DEFAULT的使用)有限制
- 許多DBMS不允許刪除或更改列
- 許多DBMS允許重命名列
-- 增加列
ALTER TABLE User ADD phone CHAR(20);mysql> DESCRIBE User;
+-------------+--------------+------+-----+-------------------+-------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+-------------------+-------------------+
| id | int(255) | NO | | NULL | |
| name | varchar(255) | NO | | NULL | |
| create_time | timestamp | YES | | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
| phone | char(20) | YES | | NULL | |
+-------------+--------------+------+-----+-------------------+-------------------+
4 rows in set (0.00 sec)
-- 刪除列
ALTER TABLE User DROP COLUMN phone;
視圖
視圖是一張虛擬的表,不包含數據,只包含使用時動態檢索數據的查詢。
為什么使用視圖:
- 重用SQL語句
- 簡化復雜的SQL操作
- 只是用表的一部分而不是整個表
- 保護數據,可以授予用戶訪問表的特定部分的權限,而不是整個表的訪問權限
- 更改數據格式和表示
性能問題
視圖不包含數據,每次使用視圖時,都必須處理查詢執行時需要的所有檢索,如果使用多個聯結和過濾創立了復雜的視圖或嵌套了視圖,性能可能會下降的很厲害
視圖的規則和限制
- 必須擁有唯一命名
- 創建視圖的數目沒有限制
- 必須擁有足夠的訪問權限
- 可以嵌套,嵌套層數因DBMS而異
- 許多DBMS禁止使用ORDER BY
- 有些DBMS要求對所返回的所有列命名,如果是計算字段,需要使用別名
- 有些DBMS把視圖作為只讀查詢
- 有些DBMS允許創建這樣的視圖:不能進行導致行不再屬于視圖的插入或更新
創建視圖 CREATE VIEW
CREATE VIEW song_singer AS
SELECT songs.name AS song_name,
songs.link,
singer.name AS singer_name,
singer_type.type
FROM songs,singer,singer_type
WHERE songs.singer = singer.id AND
singer.type = singer_type.id;
創建視圖時可以使用格式化語句或計算字段
使用視圖
SELECT語句中的所有約束條件在視圖中都適用。
mysql> SELECT * FROM song_singer WHERE singer_name = "薛之謙";
存儲過程
存儲過程可以理解為保存一條或多條語句,將其視為批文件,也可以看作是編程語言中的函數
為什么使用存儲過程
- 把處理分裝在一個易用的單元中,可以簡化操作
- 由于不要求反復建立一系列處理步驟,從而保證了數據的一致性
- 簡化對變動的管理存儲過程通常以編譯過的形式存儲,所以DBMS處理命令的工作較少,提高了性能
- 存在一些只能用在單個請求中的SQL元素和特性,存儲過程可以使用他們編寫功能更強,更靈活的代碼
- 存在一些只能用在單個請求中的SQL元素和特性,存儲過程可以使用他們編寫更強更靈活的代碼。
缺點
- 不同DBMS的存儲過程語法不同,可移植性差
- 編寫復雜
參考