轉載自:http://blog.csdn.net/u011001084/article/details/51318434 最近從圖書館借了本介紹SQL的書,打算複習一下基本語法,記錄一下筆記,整理一下思路,以備日後複習之用。 PS:本文適用SQL Server2008語法。 一、關係型資料庫和SQL ...
轉載自:http://blog.csdn.net/u011001084/article/details/51318434
最近從圖書館借了本介紹SQL的書,打算複習一下基本語法,記錄一下筆記,整理一下思路,以備日後複習之用。
PS:本文適用SQL Server2008語法。
一、關係型資料庫和SQL
實際上準確的講,SQL是一門語言,而不是一個資料庫。
什麼是SQL呢?簡而言之,SQL就是維護和使用關係型資料庫中的的數據的一種標準的電腦語言。
1.1 SQL語言主要有3個主要的組成部分。
- DML(Data Manipulation Language)數據操縱語言。這個模塊可以讓我們檢索、修改、增加、刪除資料庫中的數據。
- DDL(Data Definition Language)數據定義語言。是的我們能夠創建和修改資料庫本身。如:DDL提供
ALTER
語句,他讓我們可以修改資料庫中表的設計。 - DCL(Data Control Language)數據控制語言,用於維護資料庫的安全。
在SQL術語中,記錄(record)和欄位(field)實際上就稱為行(row)和列(column)。
1.2 主鍵和外鍵
主鍵之所以有必要:
- 首先使你唯一標識表中單獨的一行。主鍵確保了唯一性。
- 可以很容易的將一個表和另一個表關聯。
- 主鍵一般就會自動預設創建索引,提高了查詢速度。
外鍵就是說A表中的某個欄位,同時是B中的主鍵,那麼這個欄位就是A表中的外鍵。希望A表中的這個外鍵的值必須是B中已經存在的值。
1.3 數據類型
一般來講,有3中重要的數據類型:
- 數字(Numeric)
- 字元(Character)
- 以及日期/時間(Date/Time)
bit
是數字型,它只允許兩個值,0和1。
字元類型區別^1:
類型 | 長度 | 說明 |
---|---|---|
char |
固定長度 | |
nchar |
固定長度 | 處理unicode數據類型(所有的字元使用兩個位元組表示) |
varchar |
可變長度 | 效率沒char高 靈活 |
nvarchar |
可變長度 | 處理unicode數據類型(所有的字元使用兩個位元組表示) |
- 1位元組=8位
- bit就是位,也叫比特位,是電腦表示數據最小的單位。
- byte就是位元組,1byte=8bit,1byte就是1B;
- 一個字元=2位元組;
1.3 空值
空值不等於空格或空白。使用NULL表示空值。
二、簡單增刪改查
2.1 查(列名有空格的情況)
1
|
SELECT [ last name]
FROM Customers
|
用方括弧將有空格的列名括起來。
PS: MySQL中用重音符`(~)按鍵。Oracle用雙引號。
查詢順序,SQL執行順序^2:
1
|
Select -1>選擇列,-2>distinct,-3>top
|
2.2 增
1
|
INSERT INTO tablename
|
2.3 改
1
|
UPDATE table
SET column1=expression1,column2=expression2(repeat any number of times)
WHERE condition
|
2.4 刪
1
|
DELETE
FROM table
WHERE condition
|
刪除前可以驗證一下:
1
|
SELECT
COUNT(*)
FROM table
WHERE condition
|
如果想要刪除所有的行,可以:
1
|
DELETE FROM table
|
或者
1
|
TRUNCATE TABLE table
|
TRUNCATE TABLE
優勢在於速度更快,但是不提供記錄事務的結果。
另外一個不同點是,TRUNCATE TABLE
重新設置了用於自增型的列的當前值,DELETE
不會。
三、別名
關鍵字:AS
3.1 計算欄位
使用計算欄位可以做如下的事情:
- 選擇特定的單詞或者數值
- 對單個或者多個列進行計算
- 把列和直接量組合在一起。
3.2 直接量
這個直接量和表中的數據沒有任何關係,就是為了說明所用,下麵這種類型的表達式就叫做直接量(literal value)。
1
|
SELECT '直接量' AS `類型`,firstname,lastname
FROM `customers` ;
|
3.3 算數運算
例子1:
1
|
SELECT num*price AS total
FROM orders
|
例子2:
1
|
SELECT firstname+' '+lastname AS 'fullname'
FROM users
|
在MySql中連接要是用CONCAT
函數:
1
|
SELECT OrderID,FirstName,LastName,
|
3.4 別名
1)列的別名
1
|
SELECT firstname AS fn
|
2) 表的別名
1
|
SELECT firstname
|
說明:
- 列的別名是為了顯示用的,別名會作為查詢結果的表頭,不能在WHERE中使用列的別名,會出錯!!!
- 表的別名確實是為了方便操作用的,可以在WHERE中使用列的別名進行!
四、使用函數
函數要有一組圓括弧跟在關鍵字後邊,圓括弧告訴我們,這是一個函數!
4.1 字元函數
LEFT&RIGHT
LEFT(CharacterValue,NumberOfCharacters)
含義:選擇CharacterValue
欄位的左邊NumberOfCharacters
幾個字元。
ps:RIGHT是右邊幾個字元。
LTRIM&RTRIM
LTRIM(CharacterValue)
可以刪除左邊開始的空格。RTRIM作用類似。
SUBSTRING
SUBSTRING(CharacterValue,StartPositon,NumberOfCharacters)
含義:選擇從開始位置(包括),N個長度的字元。
1
|
SELECT
SUBSTRING('thewhitegoat',4,5) AS 'The Answer'
|
返回:white
4.2 日期/時間函數
GETDATE
1
|
SELECT GETDATE()
|
返回當前日期和時間。
PS:在MySql中,等價函數是NOW
,在Oracle中是CURRENT_DATE
。
DATEPART
能夠分析具體的日期,並且返回諸如該日期是該月中的第幾天,或者該年份中的第幾周等信息。
1
|
DATEPART(datepart,DateValue)
|
datepart可以是許多不同的值,如下都是有效值:
- year
- quarter
- month
- dayofyear
- day
- week
- weekday
- hour
- minute
- second
DATEDIFF
可以讓我們得到任意兩個日期之間相差的天數(或周數、月數等)。
1
|
DATEDIFF(datepart1,startdate1,startdate2)
|
DATEDIFF Function Expression | Resulting Value |
---|---|
DATEDIFF(day,’7/8/2009’,’8/14/2009’) | 37 |
DATEDIFF(week,’7/8/2009’,’8/14/2009’) | 5 |
DATEDIFF(month,’7/8/2009’,’8/14/2009’) | 1 |
DATEDIFF(year,’7/8/2009’,’8/14/2009’) | 0 |
PS:MySql中,DATEDIFF函數只允許我們計算兩個日期之間的天數,如果想要得到一個正數,結束的日期通常要作為第一個參數:
1
|
DATEDIFF(enddate,startdate)
|
Oracle中沒有等價函數
4.3 數值函數
ROUND
允許我們四捨五入。
1
|
ROUND(numericvalue,decimalpalaces)
|
RAND
用來產生隨機數
1
|
RAND([seed])
|
沒有參數時,它會返回0-1之間的一個隨機數。
1
|
SELECT RAND() AS 'Random Value'
|
可選參數seed有的情況下,每次將返回相同的值。這讓我想起了Python中的Random包。看來很多時候,一些東西是共通的啊。
PI
PI()
函數
如果想要對它保留兩位小數,可以通過複合函數進行:
1
|
SELECT ROUND(PI(),2)
|
將會返回:3.14
4.4 轉換函數
CAST函數
允許我們把數據從一種類型轉換成另一種類型。
1
|
CAST(expression AS DateType)
|
例子:
1
|
SELECT
'2009-04-11' AS 'Original Date',
CAST('2009--04-11' AS DATETIME) AS 'Converted Date'
|
ISNULL函數,很有用
可以把NULL值轉換成一個有意義的值。
1
|
SELECT Description,
ISNULL(Color,'Unknown') AS 'Color'
FROM Products
|
五、排序函數
5.1 添加排序
1
|
SELECT columnlist
|
預設是升序,ASC
,因此,上面等價於:
1
|
SELECT columnlist
|
5.2 降序
使用DESC
關鍵字:
1
|
SELECT columnlist
|
5.3 根據多列
1
|
SELECT
|
註意:列的順序很重要,首先按照LastName排序,然後按照FirstName排序。
5.4 根據計算欄位
1
|
SELECT LastName+','+FirstName AS 'Name'
FROM Customers
ORDER BY Name
|
因此,從這兒可以知道,列別名不可以用在WHERE中,但可以用在ORDER BY中。
例子
1
|
SELECT FirstName,LastName
|
5.5 排序補充內容
當數據升序時,出現順序是如下:
NULL->數字->字元
註意:此時,該列中的數字其實是按照字元來算的,因此,升序時,23也是排在5之前的。
六、基於列的邏輯-CASE
6.1 IF-THEN-ELSE邏輯
包含列和CASE表達式的SELECT語句,大概如下:
1
|
SELECT
column1,
column2,
CaseExpression
FROM table
|
6.2 CASE-簡單格式
1
|
SELECT
CASE ColumnOrExpression
WHEN value1 THEN result1
WHEN value2 THEN result2
(repeat WHEN-THEN any number of times)
[ELSE DefaultResult]
END
|
CASE表達式對於把不好理解的值轉換成有意義的描述是很有用的。
1
|
SELECT
CASE CategoryCode
WHEN 'F' THEN 'Fruit'
WHEN 'V' THEN 'Vegetable'
ELSE 'other'
END AS 'Category',
ProductDescription As 'Description'
FROM Products
|
6.3 CASE-查詢格式
1
|
SELECT
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
(repeat WHEN-THEN any number of times)
[ELSE DefaultResult]
END
|
這種格式允許在關鍵字WHEN後邊放置較為複雜的條件表達式。
相關問題:
七、基於行的邏輯
7.1 應用查詢條件
終於派到WHERE出場了,註意寫法順序,再寫一遍:
1
|
Select -1>選擇列,-2>distinct,-3>top
|
7.2 限制行-TOP
1
|
SELECT
TOP Number
Columnlist
FROM table
|
7.3 TOP和ORDER BY結合
關鍵字TOP的另一個用途是,把它和ORDER BY子句結合起來,基於特定分類,得到帶有最大值的一定數量的行。
假設你想看到Shakespeare所著的銷量最多的書。
1
|
SELECT
|
ps: 學會利用google搜索,例如,我想要知道oracle中類似top作用的關鍵字是什麼,可以:
八、布爾邏輯
關鍵字:AND/OR/NOT/BETWEEN/IN/IS/NULL
8.1 OR
OR子句意味著,如果確定任意條件為真,那麼就該選中該行。
1
|
SELECT userid,name,phone
FROM users
WHERE age<18
OR age>60
|
8.2 使用圓括弧
1
|
SELECT CustomerName,
|
本來想要的結果是對來自IL或者CA的客戶,同時,只看數量大於8的訂單。但是上面執行的結果不是這樣的,因為,SQL總是會先處理AND操作符!!!然後才會處理OR操作符。所以,上述語句中,先看到AND並執行如下的條件
1
|
State= 'CA'
|
因此,要用括弧來規定順序:
1
|
SELECT CustomerName,
|
8.3 NOT操作符
NOT操作符表示對後邊的內容否定或者取反。
1
|
SELECT CustomerName,State
|
這個其實可以用AND改寫的!!!
NOT操作符在邏輯上不是必須的。
8.4 BETWEEN操作符
1
|
SELECT CustomerName,
Sate,
QuantityPurchased
FROM Orders
WHERE QuantityPurchased BETWEEN 8 AND 10
|
8.5 IN操作符
假設你想看到IL或者NY的行:
1
|
SELECT *
|
可以改寫成:
1
|
SELECT *
|
8.9 布爾邏輯-IS NULL
為了將某欄位NULL值的行或0的行包括進來:
1
|
SELECT *
FROM Products
WHERE weight=0
OR weight IS NULL
|
或者
1
|
SELECT *
FROM Products
WHERE ISNULL(weight,0)=0
|
九、模糊匹配
9.1 LIKE和%搭配
%通配符可以表示任意的字元,它可以表示0個,1個,任意多個字元。
9.2 通配符
除了%以外,還有下劃線(_)、方括弧起來的characterlist,以及用方括弧括起來的脫字元號(^)加上characterlist。
- 下劃線表示一個字元
- [characterlist]表示括弧中字元的任意一個
- [^characterlist]表示不能是括弧中字元的任意一個
例子:1
2
3
4
5SELECT FirstName, LastName FROM Actors WHERE FirstName LIKE '[CM]ARY'
檢索以C或者M開頭並以ARY結尾的所有行。
9.3 按照讀音匹配
SOUNDEX和DIFFERENCE
十、彙總數據
10.1消除重覆
使用DISTINCT
1
|
SELECT DISTINCE name,age
FROM users
|
如果age不同,即使name相同,那麼這一行就不會被刪除重覆。
10.2 聚合函數
COUNT\SUM\AVG\MIN\MAX,他們提供了對分組數據進行計數、求和、取平均值、取最小值和最大值等方法。
1
|
SELECT
AVG(Grade) AS 'Average Quiz Score'
MIN(Grade) AS 'Minimum Quiz Score'
FROM Grades
WHERE GradeType='Quiz'
|
COUNT函數可以有3中不同方式使用它。
1.COUNT函數可以用來返回所有選中行的數目,而不管任何特定列的值。
例如:下麵語句返回GradeType為’HomeWork’的所有行的數目:
1
|
SELECT
COUNT(*) AS 'Count of Homework Rows'
FROM Grades
WHERE GradeType='HomeWork'
|
這種方式,會計數所有行的個數,即使其中有*NULL。
2.第二種方式指定具體的列
1
|
SELECT
COUNT(Grades) AS 'Count of Homework Rows'
FROM Grades
WHERE GradeType='HomeWork'
|
第一種方式返回3,這一種方式返回2,為什麼???因為,這種方式要滿足Grades這一列有值,NULL值的行不會計數。
3.使用關鍵字DISTINCT。
1
|
SELECT
COUNT(DISTINCT FeeType) AS 'Number of Fee Types'
FROM Fees
|
這條語句計數了FeeType列唯一值的個數。
10.3 分組數據-GROUP BY
1
|
SELECT
GradeType AS 'Grade Type',
AVG(Grade)AS 'Average Grade'
FROM Grades
GROUP BY GradeType
ORDER BY GradeType
|
感覺像EXCEL中的分類彙總功能。
如果想把Grade為NULL值的當做0,那麼可以用:
1
|
SELECT
GradeType AS 'Grade Type',
AVG(ISNULL(Grade,0))AS 'Average Grade'
FROM Grades
GROUP BY GradeType
ORDER BY GradeType
|
- GROUP BY子句中的列的順序是沒有意義的;
- ORDER BY子句中的列的順序是有意義的。
10.4 基於聚合查詢條件-HAVING
當針對帶GROUP BY的一條SELECT語句應用任何查詢條件時,人們必須要問查詢條件是應用於單獨的行還是整個組。
實際上,WHERE子句是單獨的執行查詢條件。SQL提供了一個名為HAVING的關鍵字,它允許對組級別使用查詢條件。
例子:
查看選修了類型為選修“A”,平均成績在70分以上的學生姓名,平均成績。
1
|
SELECT
Name,
AVG(ISNULL(Grades,0)) AS 'Average Grades'
FROM Grades
WHERE GradeType='A'
GROUP BY Name
HAVING AVG(ISNULL(Grades,0))>70
ORDER BY Name
|
修要修類型為A,那麼,這是這對行的查詢,因此這裡要用WHERE。
但是,還要篩選平均成績,那麼,這是一個平均值,建立在聚合函數上的,並不是單獨的行,這就需要用到關鍵字HAVING。需要先將Student分組,然後把查詢結果應用到基於全組的一個聚合統計上。
WHERE只保證我們選擇了GradeType是A的行,HAVING保證平均成績至少70分以上。
註意:如果想要在結果中添加GradeType的值,如果直接在SELECT後邊添加這個列,將會出錯。這是因為,所有列都必須要麼出現在GROUP BY中,要麼包含在一個聚合函數中。
1
|
SELECT
Name,
GradeType,
AVG(ISNULL(Grades,0)) AS 'Average Grades'
FROM Grades
WHERE GradeType='A'
GROUP BY Name,GradeType
HAVING AVG(ISNULL(Grades,0))>70
ORDER BY Name
|
十一、組合表
11.1 內連接來組合表-Inner Join
通過書中的描述,我感覺內連接更像是用來將主鍵表、外鍵表連接起來的工具。
例如:
A表:
userid | name | age |
---|---|---|
1 | michael | 26 |
2 | hhh | 25 |
3 | xiang | 20 |
B表:
orderid | userid | num | price |
---|---|---|---|
1 | 1 | 2 | 3 |
2 | 2 | 6 | 6 |
3 | 1 | 5 | 5 |
如上表格,那麼要連接這兩個表格,查詢訂單1的客戶姓名,年齡,訂單號:
方式一:
1
|
SELECT name,age,orderid
FROM A,B
WHERE A.userid=B.userid
AND orderid=1
|
方式二,使用現在的內連接實現:
1
|
SELECT name,age,orderid
FROM A
INNER JOIN B
ON A.userid=B.userid
AND orderid=1
|
ON關鍵字指定兩個表如何準確的連接。
內連接中表的順序:FROM 子句指定了A表,INNER JOIN 子句指定B表,我們調換A,B順序,所得到的結果相同的!只是顯示列的順序可能會不同而已。
不建議使用方式一的格式。關鍵字INNER JOIN ON的優點在於顯示地表示了連接的邏輯,那是它們唯一的用途。WEHERE的含義不夠明顯。因為它是條件的意思啊,不是連接的!
11.2 外連接
外連接分為左連接(LEFT OUTER JOIN)、右連接(RIGHT OUTER JOIN)、全連接(FULL OUTER JOIN)。
OUTER是可以省略的。
左連接(LEFT JOIN)
1
|
SELECT name,age,orderid
FROM A
LEFT JOIN B
ON A.userid=B.userid
AND orderid=1
|
外連接的強大之處在於,主表中的數據必然都會保留,從表中列沒有值的情況,用NULL補充。
LEFT JOIN 左邊的表為主表,右邊的表為從表。
11.3 自連接
自連接必然用到表的別名。
1
|
SELECT A.name,B.name as ManagerName
FROM worker as A
LEFT JOIN worker as B
ON A.managerid=B.id
|
11.4 創建視圖
1
|
CREATE VIEW ViewName AS
SelectStatement
[WITH CHECK OPTION]
|
視圖中不能包含ORDER BY子句。
[WITH CHECK OPTION]表示對視圖進行UPDATE,INSERT,DELETE操作時任然保證了視圖定義時的條件表達式。
刪除視圖:
1
|
DROP VIEW ViewName
|
修改視圖:
1
|
ALTER VIEW ViewName AS
SelectStatement
|
視圖的優點
- 簡化用戶的操作
- 使用戶以多角度看待同一數據
- 對重構資料庫提供了一定程度的邏輯獨立性
- 對機密數據提供安全保護
十二、補充
12.1 子查詢
可以用3種主要的方式來指定子查詢,總結如下:
- 當子查詢是tablelist的一部分時,它指定了一個數據源。
- 當子查詢是condition的一部分時,它成為查詢條件的一部分。
- 當子查詢是columnlist的一部分時,它創建了一個單個的計算的列。
12.2 索引
索引是一種物理結構,可以為資料庫表中任意的列添加索引。
索引的目的是,當SQL語句中包含該列的是偶,可以加速數據的檢索。
索引的缺點是,在資料庫中,索引需要更多的存儲硬碟。另一個負面因素是,索引通常會降低相關的列數據更新速度。這是因為,任何時候插入或者修改一行記錄時,索引都必須重新計算該列中的值的正確的排列順序。
可以對任意的列進行索引,但是只能指定一個列作為主鍵。指定一個列作為主鍵意味著兩件事情:首先這個列成為了索引,其次保證這列包含唯一的值。
1
|
CREATE INDEX Index2
|
刪除一個索引:
1
|
DROP INDX Index2
ON MyTable
|