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 查(列名有空格的情況)
SELECT [ last name] FROM Customers
用方括號將有空格的列名括起來。
PS: MySql中用重音符`(~)按鍵。Oracle用雙引號。
查詢順序,SQL執行順序2:
Select -1>選擇列,-2>distinct,-3>top 1>…From 表 2>…Where 條件 3>…Group by 列 4>…Having 篩選條件 6>…Order by 列
2.2 增
INSERT INTO tablename (columnlist) VALUES (RowValues1) (RowValues2) (repeat any number of times)
2.3 改
UPDATE table SET column1=expression1,column2=expression2(repeat any number of times) WHERE condition
2.4 刪
DELETE FROM table WHERE condition
刪除前可以驗證一下:
SELECT COUNT(*) FROM table WHERE condition
如果想要刪除所有的行,可以:
DELETE FROM table
或者
TRUNCATE TABLE table
TRUNCATE TABLE
優勢在於速度更快,但是不提供記錄事務的結果。
另外一個不同點是,TRUNCATE TABLE
重新設置了用於自增型的列的當前值,DELETE
不會。
三、別名
關鍵字:AS
3.1 計算字段
使用計算字段可以做如下的事情:
-
選擇特定的單詞或者數值
-
對單個或者多個列進行計算
-
把列和直接量組合在一起。
3.2 直接量
這個直接量和表中的數據沒有任何關系,就是為了說明所用,下面這種類型的表達式就叫做直接量(literal value)。
SELECT '直接量' AS `類型`,firstname,lastname FROM `customers` ;
如圖,結果中直接量就在一列中了。
3.3 算數運算
例子1:
SELECT num*price AS total FROM orders
例子2:
SELECT firstname+' '+lastname AS 'fullname' FROM users
在MySql中連接要是用CONCAT
函數:
SELECT OrderID,FirstName,LastName, CONCAT(FirstName,' ',LastName) AS 'fullname' FROM orders
3.4 別名
1)列的別名
SELECT firstname AS fn FROM customers
2) 表的別名
SELECT firstname FROM customers AS cu
說明:
-
列的別名是為了顯示用的,別名會作為查詢結果的表頭,不能在WHERE中使用列的別名,會出錯!!!
-
表的別名確實是為了方便操作用的,可以在WHERE中使用列的別名進行!
四、使用函數
函數要有一組圓括號跟在關鍵字后邊,圓括號告訴我們,這是一個函數!
4.1 字符函數
LEFT&RIGHT
LEFT(CharacterValue,NumberOfCharacters)
含義:選擇CharacterValue
字段的左邊NumberOfCharacters
幾個字符。
ps:RIGHT是右邊幾個字符。
LTRIM&RTRIM
LTRIM(CharacterValue)
可以刪除左邊開始的空格。RTRIM作用類似。
SUBSTRING
SUBSTRING(CharacterValue,StartPositon,NumberOfCharacters)
含義:選擇從開始位置(包括),N個長度的字符。
SELECT SUBSTRING('thewhitegoat',4,5) AS 'The Answer'
返回:white
4.2 日期/時間函數
GETDATE
SELECT GETDATE()
返回當前日期和時間。
PS:在MySql中,等價函數是NOW
,在Oracle中是CURRENT_DATE
。
DATEPART
能夠分析具體的日期,並且返回諸如該日期是該月中的第幾天,或者該年份中的第幾周等信息。
DATEPART(datepart,DateValue)
datepart可以是許多不同的值,如下都是有效值:
-
year
-
quarter
-
month
-
dayofyear
-
day
-
week
-
weekday
-
hour
-
minute
-
second
DATEDIFF
可以讓我們得到任意兩個日期之間相差的天數(或周數、月數等)。
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函數只允許我們計算兩個日期之間的天數,如果想要得到一個正數,結束的日期通常要作為第一個參數:
DATEDIFF(enddate,startdate)
Oracle中沒有等價函數
4.3 數值函數
ROUND
允許我們四舍五入。
ROUND(numericvalue,decimalpalaces)
RAND
用來產生隨機數
RAND([seed])
沒有參數時,它會返回0-1之間的一個隨機數。
SELECT RAND() AS 'Random Value'
可選參數seed有的情況下,每次將返回相同的值。這讓我想起了Python中的Random包。看來很多時候,一些東西是共通的啊。
PI
PI()
函數
如果想要對它保留兩位小數,可以通過復合函數進行:
SELECT ROUND(PI(),2)
將會返回:3.14
4.4 轉換函數
CAST函數
允許我們把數據從一種類型轉換成另一種類型。
CAST(expression AS DateType)
例子:
SELECT '2009-04-11' AS 'Original Date', CAST('2009--04-11' AS DATETIME) AS 'Converted Date'
ISNULL函數,很有用
可以把NULL值轉換成一個有意義的值。
SELECT Description, ISNULL(Color,'Unknown') AS 'Color' FROM Products
五、排序函數
5.1 添加排序
SELECT columnlist FROM tablelist ORDER BY columnlist
默認是升序,ASC
,因此,上面等價於:
SELECT columnlist FROM tablelist ORDER BY columnlist ASC
5.2 降序
使用DESC
關鍵字:
SELECT columnlist FROM tablelist ORDER BY columnlist DESC
5.3 根據多列
SELECT FirstName, LastName FROM Customers ORDER BY LastName, FirstName
注意:列的順序很重要,首先按照LastName排序,然后按照FirstName排序。
5.4 根據計算字段
SELECT LastName+','+FirstName AS 'Name' FROM Customers ORDER BY Name
因此,從這兒可以知道,列別名不可以用在WHERE中,但可以用在ORDER BY中。例子
SELECT FirstName,LastName FROM Customers ORDER BY LastName+FirstName AS 'Name'
5.5 排序補充內容
當數據升序時,出現順序是如下:
NULL->數字->字符
注意:此時,該列中的數字其實是按照字符來算的,因此,升序時,23也是排在5之前的。
六、基於列的邏輯-CASE
6.1 IF-THEN-ELSE邏輯
包含列和CASE表達式的SELECT語句,大概如下:
SELECT column1, column2, CaseExpression FROM table
6.2 CASE-簡單格式
SELECT CASE ColumnOrExpression WHEN value1 THEN result1 WHEN value2 THEN result2 (repeat WHEN-THEN any number of times) [ELSE DefaultResult] END
CASE表達式對於把不好理解的值轉換成有意義的描述是很有用的。
SELECT CASE CategoryCode WHEN 'F' THEN 'Fruit' WHEN 'V' THEN 'Vegetable' ELSE 'other' END AS 'Category', ProductDescription As 'Description' FROM Products
6.3 CASE-查詢格式
SELECT CASE WHEN condition1 THEN result1 WHEN condition2 THEN result2 (repeat WHEN-THEN any number of times) [ELSE DefaultResult] END
這種格式允許在關鍵字WHEN后邊放置較為復雜的條件表達式。
相關問題:
七、基於行的邏輯
7.1 應用查詢條件
終於派到WHERE出場了,注意寫法順序,再寫一遍:
Select -1>選擇列,-2>distinct,-3>top 1>…From 表 2>…Where 條件 3>…Group by 列 4>…Having 篩選條件 6>…Order by 列
7.2 限制行-TOP
SELECT TOP Number Columnlist FROM table
7.3 TOP和ORDER BY結合
關鍵字TOP的另一個用途是,把它和ORDER BY子句結合起來,基於特定分類,得到帶有最大值的一定數量的行。
假設你想看到Shakespeare所著的銷量最多的書。
SELECT TOP1 Title AS 'Book Title', CurrentMonthSales AS 'Quantuty Sold' FROM Books WHERE Author='Shakespeare' ORDER BY CurrentMonthSales DESC
ps: 學會利用google搜索,例如,我想要知道oracle中類似top作用的關鍵字是什么,可以:
八、布爾邏輯
關鍵字:AND/OR/NOT/BETWEEN/IN/IS/NULL
8.1 OR
OR子句意味着,如果確定任意條件為真,那么就該選中該行。
SELECT userid,name,phone FROM users WHERE age<18 OR age>60
8.2 使用圓括號
SELECT CustomerName, Sate, QuantityPurchased FROM Orders WHERE State ='IL' OR State='CA' AND QuantityPurchased>8
本來想要的結果是對來自IL或者CA的客戶,同時,只看數量大於8的訂單。但是上面執行的結果不是這樣的,因為,SQL總是會先處理AND操作符!!!然后才會處理OR操作符。所以,上述語句中,先看到AND並執行如下的條件
State= 'CA' AND QuantityPurchased>8
因此,要用括號來規定順序:
SELECT CustomerName, Sate, QuantityPurchased FROM Orders WHERE (State ='IL' OR State='CA') AND QuantityPurchased>8
8.3 NOT操作符
NOT操作符表示對后邊的內容否定或者取反。
SELECT CustomerName,State FROM Orders WHERE NOT (State='IL' OR Sate='NY')
這個其實可以用AND改寫的!!!NOT操作符在邏輯上不是必須的。
8.4 BETWEEN操作符
SELECT CustomerName, Sate, QuantityPurchased FROM Orders WHERE QuantityPurchased BETWEEN 8 AND 10
8.5 IN操作符
假設你想看到IL或者NY的行:
SELECT * FROM Orders WHERE State='IL' OR State='CA'
可以改寫成:
SELECT * FROM Orders WHERE State IN ('IL','CA')
8.9 布爾邏輯-IS NULL
為了將某字段NULL值的行或0的行包括進來:
SELECT * FROM Products WHERE weight=0 OR weight IS NULL
或者
SELECT * FROM Products WHERE ISNULL(weight,0)=0
九、模糊匹配
9.1 LIKE和%搭配
%通配符可以表示任意的字符,它可以表示0個,1個,任意多個字符。
9.2 通配符
除了%以外,還有下划線(_)、方括號起來的characterlist,以及用方括號括起來的脫字符號(^)加上characterlist。
-
下划線表示一個字符
-
[characterlist]表示括號中字符的任意一個
-
3表示不能是括號中字符的任意一個
例子:
SELECT FirstName, LastName FROM Actors WHERE FirstName LIKE '[CM]ARY'
檢索以C或者M開頭並以ARY結尾的所有行。
9.3 按照讀音匹配
SOUNDEX和DIFFERENCE
十、匯總數據
10.1消除重復
使用DISTINCT
SELECT DISTINCE name,age FROM users
如果age不同,即使name相同,那么這一行就不會被刪除重復。
10.2 聚合函數
COUNT\SUM\AVG\MIN\MAX,他們提供了對分組數據進行計數、求和、取平均值、取最小值和最大值等方法。
SELECT AVG(Grade) AS 'Average Quiz Score' MIN(Grade) AS 'Minimum Quiz Score' FROM Grades WHERE GradeType='Quiz'
COUNT函數可以有3中不同方式使用它。
1.COUNT函數可以用來返回所有選中行的數目,而不管任何特定列的值。例如:下面語句返回GradeType為'HomeWork'的所有行的數目:
SELECT COUNT(*) AS 'Count of Homework Rows' FROM Grades WHERE GradeType='HomeWork'
這種*方式,會計數所有行的個數,即使其中有NULL。
2.第二種方式指定具體的列
SELECT COUNT(Grades) AS 'Count of Homework Rows' FROM Grades WHERE GradeType='HomeWork'
第一種方式返回3,這一種方式返回2,為什么???因為,這種方式要滿足Grades這一列有值,NULL值的行不會計數。
3.使用關鍵字DISTINCT。
SELECT COUNT(DISTINCT FeeType) AS 'Number of Fee Types' FROM Fees
這條語句計數了FeeType列唯一值的個數。
10.3 分組數據-GROUP BY
SELECT GradeType AS 'Grade Type', AVG(Grade)AS 'Average Grade' FROM Grades GROUP BY GradeType ORDER BY GradeType
感覺像EXCEL中的分類匯總功能。如果想把Grade為NULL值的當做0,那么可以用:
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分以上的學生姓名,平均成績。
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中,要么包含在一個聚合函數中。
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的客戶姓名,年齡,訂單號:方式一:
SELECT name,age,orderid FROM A,B WHERE A.userid=B.userid AND orderid=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)
SELECT name,age,orderid FROM A LEFT JOIN B ON A.userid=B.userid AND orderid=1
外連接的強大之處在於,主表中的數據必然都會保留,從表中列沒有值的情況,用NULL補充。
LEFT JOIN 左邊的表為主表,右邊的表為從表。
11.3 自連接
自連接必然用到表的別名。
SELECT A.name,B.name as ManagerName FROM worker as A LEFT JOIN worker as B ON A.managerid=B.id
11.4 創建視圖
CREATE VIEW ViewName AS SelectStatement [WITH CHECK OPTION]
視圖中不能包含ORDER BY子句。
[WITH CHECK OPTION]表示對視圖進行UPDATE,INSERT,DELETE操作時任然保證了視圖定義時的條件表達式。
刪除視圖:
DROP VIEW ViewName
修改視圖:
ALTER VIEW ViewName AS SelectStatement
視圖的優點
-
簡化用戶的操作
-
使用戶以多角度看待同一數據
-
對重構數據庫提供了一定程度的邏輯獨立性
-
對機密數據提供安全保護
十二、補充
12.1 子查詢
可以用3種主要的方式來指定子查詢,總結如下:
-
當子查詢是tablelist的一部分時,它指定了一個數據源。
-
當子查詢是condition的一部分時,它成為查詢條件的一部分。
-
當子查詢是columnlist的一部分時,它創建了一個單個的計算的列。
12.2 索引
索引是一種物理結構,可以為數據庫表中任意的列添加索引。
索引的目的是,當SQL語句中包含該列的是偶,可以加速數據的檢索。
索引的缺點是,在數據庫中,索引需要更多的存儲硬盤。另一個負面因素是,索引通常會降低相關的列數據更新速度。這是因為,任何時候插入或者修改一行記錄時,索引都必須重新計算該列中的值的正確的排列順序。
可以對任意的列進行索引,但是只能指定一個列作為主鍵。指定一個列作為主鍵意味着兩件事情:首先這個列成為了索引,其次保證這列包含唯一的值。
CREATE INDEX Index2 ON MyTable (ColumnFour)
刪除一個索引:
DROP INDX Index2 ON MyTable
參考:
##轉自##michael翔的IT私房菜##👍##