本文轉自http://www.cnblogs.com/Jolinson/p/3552786.htmlhtml
這裏的摘抄來自《Microsoft SQL Server 2008技術內幕:T-SQL語言基礎》,書中用到的案例數據庫是這個 TSQLFundamentals2008 ,官網給出的鏈接是這個(貌似有的要穿牆), 冠軍也有一份。本博也有一份git
SQL (Structured Query Language)程序員
爲查詢和管理關係型數據庫管理系統(RDBMS--Relational Database Management System)中的數據而專門設計的一種標準語言。算法
RDBMS是一種基於關係模型的數據庫管理系統,而關係模型則是一種用於表示數據的語義模型。該模型基於兩種數學理論:集合論和謂詞邏輯。sql
關係模型是獨立於語言的,除了SQL外,還能夠用其餘的語言來實現關係模型,例如,C#的類模型。數據庫
SQL是基於關係模型的ANSI和ISO標準語言。編程
SQL有幾種不一樣類型的語句: c#
數據定義語言(DDL--Data Definition Language):用於處理數據對象的定義,包括Create、Alter、Drop語句。 架構
數據處理語言(DML--Data Manipulation Language):用於查詢和修改數據,包括Select、Insert、Update、Delete、Merge語句。 框架
數據控制語言(DCL--Data Control Language):用於處理權限管理,包括Grant,Revoke語句。
此書重點介紹的是DML數據處理語言。
集合
所謂集合是把咱們直觀或思惟中肯定的、不一樣的哪些對象做爲一個總體來考慮的結果。這些對象就是集合的元素或成員。
謂詞邏輯:True or False
約束:經過規則或約束來確保關係模型數據的完整性。
範式:
第一範式,表中的行必須是惟一的。屬性應該是原子的(即列不可再拆分)。
第二範式,有兩條,第一:首先必須知足第一範式;
第二要求非鍵屬性和候選鍵屬性之間必須知足必定的條件,對於每一個候選鍵,每一個非鍵屬性都必須徹底函數依賴於整個候選鍵。
第三範式,有兩條,第一:首先必須知足第二範式;
第二全部非鍵屬性必須非傳遞依賴於候選鍵。 第2、第三範式歸納起來說:每一個非鍵屬性都依賴與鍵。
本身的話歸納,第一範式,表中的各個列不可拆分,有明確的屬性;
第二範式,在知足第一範式的同時,每一個表還要有一個惟一的主鍵標識,經過主鍵能夠查到這個實例的表中全部信息;
第三範式:在知足第二範式的同時,兩表聯合,不能經過兩表的主鍵與主鍵聯接,因存在表1的主鍵與表2的非主鍵聯合。(救命實在是不知道怎麼表達了...)
例子,員工表(employe),部門表(department),員工表中有員工編號,員工姓名,員工性別,員工住址,所屬部門編號等等;部門表中有部門編號,部門名稱,部門信息等等。
數據生命週期
聯機事務處理(OLTP--OnLine Transctional Processing):重點是數據輸入,主要處理的事務包括插入、更新 刪除數據。
數據倉庫(DW--Data Warehouse):專門針對數據檢索和生成報表而設計的環境。
當這樣的環境服務於整個企業時,就稱之爲數據倉庫;而只服務於企業一部分時,如一個特定的部門,就稱之爲數據集市(data mart)。
數據集市主要是爲了支持數據檢索,而對數據庫倉庫中的數據模型進行設計和優化。
聯機分析處理(OLAP--OnLine Analytical Processing)系統,支持對聚合後的數據進行動態的在線分析。
數據挖掘(DM--Data Mining)由數據挖掘算法梳理數據,從中篩選出有用的信息。
文件擴展名
.mdf(Master Data File主數據文件)
.ndf(Not Master Data File非主數據文件)
.ldf(Log Data File日誌數據文件)
架構(Schema)和對象:
一個數據庫包含多個架構,而每一個架構又包含多個對象(對象能夠是表,視圖,存儲過程等)。
能夠在架構級別上控制對象的訪問權限。表是屬於架構,而架構又是屬於數據庫的。
CREATE SCHEMA xxx AUTHORIZATION dbo;
建表:
DB_ID(databaseName) return int,函數接受一個數據庫名稱做爲輸入,返回它的內部數據庫ID
若是輸入的數據庫不存在,那麼返回的將是NULL,這是檢查數據庫是否存在的簡單方法。
--若是不存在testdb的數據庫,那麼從新建立一個叫testdb的數據庫 IF DB_ID('testdb') IS NULL CREATE
DATABASE testdb
更多詳細的建庫建表,另看:SQL_DDL_建庫建表
select
select語句的目的是對錶進行查詢、應用必定的邏輯處理,並返回結果。
查詢處理順序
1. from
2. where
3. group by
4. having
5. select
6. order by
邏輯處理順序
SELECT empid,YEAR(orderdate) AS orderyear,COUNT(*) AS numorders FROM Sales.Orders WHERE custid=71 GROUP BY empid,YEAR(orderdate) HAVING COUNT(*) > 1
ORDER BY empid,orderyear --按照查詢邏輯順序 --1. from --2. where --3. group by --4. having --5. select --6. order by --上面的select查詢語句可解釋成
FROM Sales.Orders--從Sales.Orders表中查詢記錄
WHERE custid=71--數據篩選,只留下custid=71的數據
GROUP BY empid,YEAR(orderdate)--按照僱員id和訂單年份進行分組
HAVING COUNT(*) > 1--分組後篩選,一年中下單超過1份的留下,不包括1
SELECT empid,YEAR(orderdate) AS orderyear,COUNT(*) AS numorders--select查詢出來
ORDER BY empid,orderyear--按照僱員id和年份排序
From 子句
from子句是在邏輯階段第一個要處理的查詢子句。這個子句用於指定要查詢的表名,以及對這些表進行操做的表運算符。
爲了不SQL Server本身主動隱式去解析一個對象的架構,咱們有必要經過顯示指定架構名稱,這樣既能保證獲得的對象確實是你原來想要的又減小了一些額外的代價(隱式推算架構),還減小了有可能產生的錯誤。
Where 子句
在where子句中,能夠指定一個謂詞或者邏輯表達式,從而過濾由from階段返回的行,where階段只返回讓邏輯表達式爲True的哪些行。
這裏須要強調記憶的是:T-SQL使用的是三值謂詞邏輯,True,False,Unknow
Group By 子句
Group by 階段能夠將前面邏輯查詢處理階段返回的行按「組」進行組合。 由於聚合函數只爲每一個組返回一個值,因此一個元素若是不在Group by列表中出現。就只能做爲聚合函數(count、sum、avg、min、max)的輸入。
Having 子句
Having子句用戶指定對組裝進行過濾的謂詞或邏輯表達式。Having子句只會留下邏輯表達式爲True組的數據,False和Unknow將會被過濾。
Select 子句
select子句用於指定須要在查詢返回的結果集中包含的屬性(列),select列中的表達式能夠直接基於正在查詢的表的各個列上作進一步的處理。
關於別名
在select查詢中,T-SQL容許查詢返回沒有名稱的結果集列(但會沒有列名),但關係模型不容許這樣,因此最好是加上別名。
取別名的三種方式
除了<表達式>as<別名> 這種格式,T-SQL還支持<別名>=<表達式>(別名 等於 表達式) 和 <表達式><別名>(表達式 空格 別名)三種方式,
不過最好仍是用 <...>as<...>這種方式,直觀,方便閱讀。 關於取別名還有一個要注意的是,如:
把select col1,col2 from table_1 寫成了 select col1 col2 from table_1它仍是成立的,只是原本查兩列的,成了一列並且列名爲col2了,這樣的bug很很差被發現,因此要當心編寫。
另外一個易犯的錯
select子句是在from、where、group by、having子句以後處理的。這意味着對select子句以前處理的那些子句,在select子句中爲表達式分配的別名不存在。如:
SELECT orderid,YEAR(orderdate) AS orderyear FROM Sales.Orders WHERE orderyear > 2006
這樣作,是會報錯的!由於邏輯順序from,where...select,處理where階段的時候,並無別名orderyear,因此會報錯:Invalid column name 'orderyear'.
Order by 子句(ASC 升序<默認> DESC降序)
Order by子句用於展現數據對輸出結果中的進行排序。 SQL最重要的一點:表不保證是有序的,由於表是爲了表明一個集合,而集合是無序的。
Top 選項
Top選項是T-SQL特有的,用於限制查詢返回的行數或百分比。依靠了Order by就會起到雙重做用。在select階段。
在Top選項中,還可使用Percent關鍵字,如: select top(1) percent ,id,name,age from tabName
在top選項中,咱們還能夠加入 with ties 選項
1.
SELECT TOP 5 * FROM Sales.Orders ORDER BY custid DESC
SELECT TOP 5 WITH TIES * FROM Sales.Orders ORDER BY custid DESC
2.
DECLARE @table TABLE ( id INT NULL, Aid INT NULL ) INSERT INTO @table ( id, Aid )VALUES (1,1) INSERT INTO @table ( id, Aid )VALUES (2,1) INSERT INTO @table ( id, Aid )VALUES (3,1) INSERT INTO @table ( id, Aid )VALUES (4,2) INSERT INTO @table ( id, Aid )VALUES (5,2) INSERT INTO @table ( id, Aid )VALUES (6,2) INSERT INTO @table ( id, Aid )VALUES (7,3) INSERT INTO @table ( id, Aid )VALUES (8,3) INSERT INTO @table ( id, Aid )VALUES (9,4) INSERT INTO @table ( id, Aid )VALUES (10,4) INSERT INTO @table ( id, Aid )VALUES (11,4) INSERT INTO @table ( id, Aid )VALUES (12,5) INSERT INTO @table ( id, Aid )VALUES (13,5) INSERT INTO @table ( id, Aid )VALUES (14,6) INSERT INTO @table ( id, Aid )VALUES (15,6) INSERT INTO @table ( id, Aid )VALUES (16,6) INSERT INTO @table ( id, Aid )VALUES (17,6) SELECT TOP 5 * FROM @table ORDER BY Aid desc
SELECT TOP 5 WITH TIES* FROM @table ORDER BY Aid DESC
加入with ties選項以後,能夠篩選出更多的與最後一行相同值的其餘行,更多更詳細可看參考二。
Over 子句 開窗函數(window function)
Over子句用於爲行(row)一個窗口,以便進行特定的運算。能夠把行的窗口簡單的認爲是運算將要操做的一個行的集合。
若是想對行(row)進行限制或者分區,這可使用Partition by 子句。
以下,第一個查詢的是全部行,二個查詢的是全部價格的總和,三個則是查詢當前客戶(和當前行具備相同custid的全部行)的總價格,
Sum(val) Over (Partition by custid)
--1
SELECT orderid ,custid ,val FROM Sales.OrderValues ORDER BY custid ASC
--2
SELECT orderid ,custid ,val , SUM(val) OVER ( ) AS totalValue FROM Sales.OrderValues ORDER BY custid ASC
--3
SELECT orderid ,custid ,val , SUM(val) OVER ( PARTITION BY custid ) AS CurrTotalValue FROM Sales.OrderValues
Over子句的一個有點就是可以在返回基本列的同時,在同一行對它們進行聚合;也能夠在表達式中混合使用基本列和聚合值列。
SELECT orderid,custid,val, 100*val/SUM(val) OVER() AS alltotal, --每行val佔總val的百分比
100*val/SUM(val) OVER(PARTITION BY custid) AS totalbyaustid--每行val佔當行custid的總val的百分比
FROM Sales.OrderValues
Over子句也支持四種排名函數:ROW_NUMBER(行號)、 RANK(排名)、 DENSE_RANK(密集排名) NTILE。
SELECT orderid,custid,val, ROW_NUMBER() OVER(ORDER BY val ) AS [rownum], RANK() OVER (ORDER BY val) AS [rank], DENSE_RANK() OVER (ORDER BY val) AS [dense_rank], NTILE(10) OVER (ORDER BY val) AS [ntile]
FROM Sales.OrderValues
--圖片 1
row_number 函數用於爲查詢的結果集中的各行分配遞增的序列號,其邏輯順序經過over子句中的order by 語句進行指定。
rank 和 dense_rank 函數與row_number相似,但它們爲具備相同邏輯排序值的因此行生產相同的排名。
rank 和 dense_rank 函數的區別是 如圖 1,若是rank有相同的val值,兩個都是 7 ,那麼下一個 rank 的值是 9,跳過了 8; 而dense_rank卻不一樣,上兩個是7,下面接上仍是8;
ntile 函數能夠把結果中的行關聯到組(tile,至關於由行組成的指定數目的組) ,併爲每一行分配一個所屬的組的編號。
好比,如今有一個集合是20條數據,利用ntile(5) 函數,我將1-4 條分爲一組,組號爲 1 ,5-8 一組,組號 2 這樣以此類推。
ntile 函數在邏輯上須要依賴與row_number函數。
整個過程是先根據對val的排序結果,爲每一行分配行號,再等量分組,若是除不盡,若有22條數據要分10組, ntile(10),那麼一二組將會有3條記錄。
SELECT * ,NTILE(10) OVER ( ORDER BY val ) AS [ntile]
FROM ( SELECT orderid ,custid , val , ROW_NUMBER() OVER ( ORDER BY val ) AS [rownum]
FROM Sales.OrderValues ) v WHERE rownum BETWEEN 1 AND 22
圖二
和聚合開窗函數同樣,排名函數也支持在over子句中使用partition by 語句。rank 、dense_rank與 row_number差很少
SELECT orderid ,custid ,val , rank() OVER ( PARTITION BY custid ORDER BY val ) AS [rownum]
FROM Sales.OrderValues SELECT orderid ,custid ,val , NTILE(2) OVER ( PARTITION BY custid ORDER BY val ) AS [rownum]
FROM Sales.OrderValues
圖三
加入了over distinct top 以後的SQL邏輯處理順序
1. from
2. where
3. group by
4. having
5. select
5.1 over
5.2 distinct
5.3 top
6. order by
若是想利用不一樣的val生成行號,不用使 row_number 和 distinct 同級使用,由於row_number是在distinct以前處理的,並且row_number是惟一的 後面的distinct無效。
但咱們能夠採用下面兩中方案。
--一
SELECT val ,ROW_NUMBER() OVER ( ORDER BY val ) AS [rownum]
FROM Sales.OrderValues GROUP BY val --二
SELECT * ,ROW_NUMBER() OVER ( ORDER BY val ) AS [rownum]
FROM ( SELECT DISTINCT val FROM Sales.OrderValues ) v
圖四
謂詞和運算符
謂詞:T-SQL支持的謂詞包括IN、Between、以及Like。
in 用於檢查一個值(或標量表達式)是否與一組元素中的至少一個相等。
如:select c1,c2,c3 from tab_1 where id in (1001,1101)
between用於檢查一個值是否在必定的範圍內,包括兩個指定的邊界值。
如:select c1,c2,c3 from tab_1 where id between 1 and 5 --包括1和5
like用於檢查一個字符串值是否與指定的模式匹配。
如:select c1,c2,c3 from tab_1 where name like '%D%'
運算符:T-SQL支持的比較運算符 =、>、<、>=、<=、<>、!=、!>、!<,最後三個運算符不是標準運算符
小數運算 5/2 整數等於2 而不是2.5,若是想獲得小數的話,能夠這樣
SELECT CAST(5 AS NUMERIC(12,2))/CAST(2 AS NUMERIC(12,2))
NUMERIC(12,2)這個數據類型的精確度爲12,帶有2位小數
SQL運算符的優先級 1.() 2.*,/,%
3.+,-
4.=,>,<,>=,<=,<>,!=,!>,!<
5.not
6.and
7.between,in,like,or
8.=
以下句子
SELECT * FROM Sales.Orders WHERE custid =1 AND empid IN(1,3,5) OR custid = 85 AND empid IN(2,4,6)
由於and比or的優先級高,因此是先出現 由客戶1下的並由僱員1,3,5處理的訂單,在返回由客戶85下的並由僱員2,4,6處理的訂單。
SELECT * FROM Sales.Orders WHERE (custid =1 AND empid IN(1,3,5)) OR (custid = 85 AND empid IN(2,4,6))
圓括號的優先級最高,雖然咱們在這裏加上了,並無改變他的邏輯運算,但明顯的提升了代碼的可讀性,邏輯清晰了不少,這個一個很好的編程習慣!
Case表達式
case表達式是一個標量表達式,它基於條件邏輯來返回一個值。
在這裏值得注意的是,case是一個表達式,而不是一條語句,也就是說,不能用它來控制活動的流程,也不能根據條件邏輯來作某些處理。相反,它只是根據條件邏輯來返回某個值。
由於case是一個標量表達式,因此他能夠支持任何標量表達式(如:select、where、having、order by子句)check約束等等。
case表達式有兩種格式:簡單表達式 和 搜索表達式。
簡單格式:將一個值(或者一個標量表達式)與一組可能的取值進行比較,並返回第一個匹配的結果。
若是列表沒有值等於測試值,case表達式就返回其else子句中列出的值。若是case表達式中沒有else子句,這默認將其視爲else null。
SELECT c1 ,c2 ,c3 ,c4 , CASE empid WHEN 1 THEN 'Monday'
WHEN 2 THEN 'Tuesday'
WHEN 3 THEN 'Wednesday'
WHEN 4 THEN 'Thursday'
WHEN 5 THEN 'Friday'
WHEN 6 THEN 'Saturday'
WHEN 7 THEN 'Sunday'
ELSE 'Unknow'
END AS 'a week'
FROM table_1
下面一個例子利用case與開窗函數(over),將集合中的數據根據val生成三個層次Low、Medium、High
SELECT orderid,custid,val, NTILE(3) OVER(ORDER BY val) AS Tile, CASE NTILE(3) OVER(ORDER BY val) WHEN 1 THEN 'Low'
WHEN 2 THEN 'Medium'
WHEN 3 THEN 'High'
ELSE 'Unknow'
END AS 'TitleDesc'
FROM Sales.OrderValues
圖 2 部分截圖
Case搜索表達式
case簡單表達式只有一個測試值(或表達式),它緊跟在case關鍵字後面,與where子句中的一組可能值進行比較。
而case搜索表達式要更靈活些,他能夠在when子句中指定謂詞或邏輯表達式,而不是隻進行相等比較。
case搜索表達式返回結果爲true的第一個when邏輯表達式所關聯的then子句中指定的值。
若是沒有任何when表達式結果爲true,case表達式就返回else子句中出現的值(若是else子句也沒指定,就返回null)。
SELECT orderid ,custid ,val , CASE WHEN val < 1000.00 THEN 'Less then 1000' WHEN val BETWEEN 1000.00 AND 3000.00 THEN 'Between 1000 and 300' WHEN val > 3000.00 THEN 'More then 3000' ELSE 'Unkown' END AS 'ValueCategory' FROM Sales.OrderValues
NULL值
SQL用NULL符號來表示缺乏的值。
null 與三值謂詞邏輯,
表達式 salary > 0 ,當salary 等於 1 時 ,表達式的結果爲 true
當salary 等於-1 時 ,表達式的結果爲 false
當salary 等於null時 ,表達式的結果爲 unknow
表達式 null=null ,其結果是unknow ,無論什麼值與null比較獲得的邏輯值都是unknow
在三值謂詞邏輯中,接受true 則會拒絕unknow,而拒絕false 則會接受unknow。
where條件後面只接受爲true的邏輯結果,若是想獲得指定的值和列爲NULL的集合,能夠這樣
SELECT c1 ,c2 ,c3 ,c4 ,c5 FROM tableName WHERE c1 = '' OR c1 IS NULL
在SQL中,有的時候又會認爲兩個NULL彼此相等,當進行分組和排序時,兩個NULL值是相等的。
對於多個NULL的排序,ANSI SQL把它留給了具體的產品實現。T-SQL是把NULL值排在了有效值以前。
ANSI SQL有兩種unique約束,一種是將多個null值視爲相等的(值容許有一個null值),另外一個則將多個null值視爲不一樣的(容許有多個null值)。SQL Server只實現了前者。
同時操做(All-At-Once-Operation)這一章不是很理解,第二的例子徹底在打P
概念:在同一邏輯查詢處理階段中出現的全部表達式都是同時進行計算的。
--來看
SELECT orderid , orderdate , YEAR(orderdate) AS yearDate, yearDate + 1 AS nextyeat FROM Sales.Orders
--這樣是不行的,看起來可行,但實際上是會報錯的
Invalid column name 'yearDate'.
--再來看
SELECT *
FROM Sales.OrderDetails WHERE col1 <> 0
AND col2 / col1 > 2
由於SQL存在同時操做的概念,上面的語句,咱們擔憂出問題,so將條件改動,由於若是是 col2 / col1 > 2 ,遇到col=0就sb了。
--1
SELECT *
FROM Sales.OrderDetails WHERE CASE WHEN col1 = 0 THEN 'no'
WHEN col2 / col1 > 2 THEN 'yes'
ELSE 'no'
END = 'yes'
--2
SELECT *
FROM Sales.OrderDetails WHERE col1 <> 0
AND col2 > 2 * col1 --3
SELECT *
FROM Sales.OrderDetails WHERE col1 <> 0
AND col2 / 2 > col1
數據類型
SQL Server支持兩種字符數據類型:普通字符和Unicode字符
普通的字符數據類型包括 char、varchar、 變量表示 'XXX'
Unicode字符數據類型包括Nchar、Nvarchar 變量表示 N'XXX'
兩者的區別
普通字符使用一個字節(byte)來保存每一個字符,而Unicode字符則須要兩個字節。普通字符只能表明256(2^8)個不一樣的字符,Unicode能夠表明65536(2^16)個不一樣的字符。
char、Nchar都是固定長度的。比例 char(25) 長度就是25個字符,沒法擴展。
Nchar、Nvarchar是可變長的。SQL會按照實際長度來保存數據,外加兩個額外的本身以保存數據的偏移值。比例varchar(25)最多隻能保存25個字符。
排序規則
排序規則是字符數據的一個屬性,封裝了幾個方面的特徵,包括多語言支持(和Unicode類型有關,由於它支持全部語言)、排序規則、區分大小寫、區分重音,等等。
要獲得系統中目前支持的全部排序規則及其描述,能夠查詢表函數sys.fn_helpcollations()
SELECT [name] , [description] FROM sys.fn_helpcollations()
例如,排序規則 Latin1_General_CI_AS
Latin1_General 支持的語言是英語
字典排序 基於字段順序對字符數據進行排序和比較('A'和'a'<'B'和'b')。
CI 數據不區分大小寫
AS 數據區分重音
SQL Server實例的排序規則是在安裝時設置的,他決定了全部系統數據庫的排序規則,同時也是用戶數據庫默認使用的排序規則。
當建立用戶數據庫時,可使用COLLATE子句指定數據庫的排序規則。若是不指定,則默認採用SQL Server實例的排序規則。
若是想在列的排序規則是不區分大小寫的前提下,讓過濾條件區分大小寫的,則能夠按照以下所示的方法來修改表達式的排序規則:
--默認排序規則 SELECT empid , firstname , lastname FROM HR.Employees WHERE lastname = N'davis' --利用表達式修改排序規則 SELECT empid , firstname , lastname FROM HR.Employees WHERE lastname COLLATE Latin1_General_CS_AS = N'davis'
分隔符
在標準SQL中,單引號用於分割文字字符串,而雙引號用於分割不規則的標識符(表名或列名包含空格或以數據做爲開始)。除了雙引號分割符外,還有[]做爲分隔符。
運算符和函數
--1
SELECT region ,country , region + N',' + country AS 'Address'
FROM Sales.Customers --若是 region 列的值爲null的話,Address 拼接的值也爲NULL。 --經過SET CONCAT_NULL_YIELDS_NULL OFF會話就能夠改變SQL Server處理串聯的方式 --2
SET CONCAT_NULL_YIELDS_NULL OFF
SELECT region ,country , region + N',' + country AS 'Address'
FROM Sales.Customers SET CONCAT_NULL_YIELDS_NULL ON --可是!強烈建議避免修改SQL Server的標準行爲,大多數程序員(或接口)都默認代碼會以標準行爲來進行處理。
--若是隻是將NULL值用''替換,咱們能用coalesce函數。
--3
SELECT region ,country , COALESCE(region,'') + N',' + country AS 'Address'
FROM Sales.Customers
函數
T-SQL提供了一套字符串處理函數,其中包括substring、left、right、len、charindex、patindex、replace、replicate、stuff、upper、lower、rtrim、ltrim等等。
substring 函數用於從字符串中提取子串。
語法
substring(string,start,length)
start :從1開始,不能超過輸入字符串的長度
length:從1開始,可超過輸入字符串的長度,但只能取得輸入長度的最長值。
該函數對輸入的字符串進行處理,提取從指定位置開始,遇有特定長度的子字符串。
如:PRINT SUBSTRING('jolinson',1,10) --jolinson
left 和 right函數
left 和 right函數是substring函數的簡略形式,他們分別返回輸入字符串從左邊或右邊開始指定個數的字符。
left(string,n),right(string,n)
string 要處理的字符串
n 從字符的左邊或右邊提取的字符個數
PRINT LEFT('jolinson',8)--jolinson
PRINT LEFT('jolinson',8)--jolinson
len 和 datalength函數
len函數返回輸入字符串中的字符數。
語法
len(string)
datalength函數返回字符串字節數的長度。
語法
datalength(string)
PRINT LEN('jolinson')--8
PRINT DATALENGTH('jolinson')--8
PRINT LEN(N'jolinson')--8
PRINT DATALENGTH(N'jolinson')--16
還有一個區別:len和datalength函數,前者不包含尾隨空格,然後者會包含尾隨的空格。
PRINT LEN(' jolinson ')--9
PRINT DATALENGTH(' jolinson ')--10
PRINT LEN(N' jolinson ')--9
PRINT DATALENGTH(N' jolinson ')--20
charindex函數
charindex函數返回字符串中某個字符串第一次出現的起始位置。
語法
charindex(substring,string,[,start_pos])
substring 要搜索的字符
string 輸入的字符串,從這裏找
start_pos 開始位置,可選,若是沒有從字符串第一個字符開始搜索
返回 找到則出現第一次出現的位置,沒找到則返回0
PRINT CHARINDEX('on','jolinson',6)--7
patindex函數
patindex函數返回字符串中某個模式第一次出現的起始位置。
語法
patindex(pattern,string)
pattern 通配符
string 輸入的string
PRINT PATINDEX('%[0-9]%','sdfas1321asdf') --6
replace函數
replace函數將字符串中出現的全部某個子字符串替換爲另外一個字符串。
replace(string,substring1,substring2)
將string中的substring1 替換爲 substring2
PRINT REPLACE('1-2 , 2-3','-',':') --1:2 , 2:3
還能夠利用replace函數計算出某個substring在string中出現的次數
SELECT custid , contactname , LEN(contactname) - LEN(REPLACE(contactname, 'a', '')) AS 'count'
FROM Sales.Customers
replicate 函數
replicate函數以指定的次數複製字符串值
語法
replicate(string,n)
string 要被賦值的字符串
n 複製的次數
PRINT REPLICATE('jolinson ', 3)--jolinson jolinson jolinson
利用replicate、right函數,成生列以0開頭10位數字的數據
SELECT RIGHT(REPLICATE('0', 9) + CAST(supplierid AS VARCHAR(10)), 10) AS strsupplierid FROM Production.Suppliers 0000000029
0000000028
0000000004
0000000021
0000000002
0000000022
0000000014
0000000011
首先利用replicate函數將0複製了9個,而後拼接supplierid,再利用right函數從右邊開始截取10個字符.
stuff函數
stuff函數對輸入參數string,從輸入參數pos指定的位置開始刪除delete_length參數指定長度的字符,而後將insertstring 參數指定的字符串插入到pos指定的位置
語法
stuff(string,pos,delete_length,insertstring)
string 被輸入的string pos 開始刪除位置,位置從1開始。從0開始的話會獲得一個null
delete_length 刪除長度,是0,是0的話,將不刪除任何字符將字符插在string最前面
insertstring 從新插入的字符串
print STUFF('jolinson',1,1,'J')--Jolinson
upper 和 lower 函數
upper和lower函數將輸入字符串中的全部字符都轉爲大寫或小寫字符。
語法
upper(string) lower(string)
PRINT UPPER('jolinson')--JOLINSON
PRINT LOWER('JOLINSON')--jolinson
rtrim 和 ltrim函數
用於刪除輸入字符串中的尾部空格或開頭處空格。
語法
rtrim(string)、ltrim(string)
PRINT RTRIM(' jolinson ')-- jolinson
若是既想刪除開頭空格又想刪除末尾空格可使用兩個函數嵌套
SELECT LTRIM(RTRIM(' jolinson '))-- jolinson
模式匹配
Like謂詞 用於檢查字符串是否可以匹配指定的模式。
%(百分號) 通配符表明任意長度的字符串,包括空字符串。'A%' ----匹配任意A字符開頭的字符串。
_(下劃線) 表明任意單個字符。'A_C' ----匹配A開頭C結尾中間一個爲任意字符的字符串
[<字符列>]通配符,方括號中包含一列字符(例如'[ABC]'),表示必須匹配列指定字符中的一個字符。'[ABC]%' ----匹配A、B或者C開頭的字符串。
[<字符>-<字符>]通配符方括號中包含一個字符範圍(例如['A-Z']),表示必須匹配指定範圍內的一個字符。'[A-G]'匹配的只能是ABCDEFG其中的一個字符。
[^<字符列或範圍>]通配符表示不屬於指定字符列或範圍內的任意單個字符串。 '[^A-G]'匹配的只能是除ABCDEFG之外的任一個字符
轉移字符,當搜索的通配符中出現了特定的通配符如'%','_','[',']'的時候,咱們須要把他們轉義。 LIKE '%!_%' ESCAPE '!' 或者 LIKE '%[!]_%'
處理日期和時間數據
數據類型 存儲大小(字節) 日期範圍 準確度 推薦格式及示例
datetime 8 1753-01-01到9999-12-31 3.33毫秒 'YYYYMMDD hh:mm:ss:nnn' '20090212 12:30:15:123'
smalldatetime 4 1900-01-01到2079-06-06 1分鐘 'YYYYMMDD hh:mm' '20090212 12:30'
date 3 0001-01-01到9999-12-31 1天 'YYYYMMDD'
time 3-5 00:00:00.0000000到23:59:59.9999999 100納秒 'hh:mm:ss.nnnnnn' '12:30:15.1234567'
datetime2 6-8 0001-01-01 00:00:00.0000000到 100納秒 'YYYYMMDD hh:mm:ss.nnnnnn'
9999-12-31 23:59:59.9999999 '20090212 12:30:15.1234567'
Datetimeoffset 8-10 0001-01-01 00:00:00.0000000到 100納秒 'YYYYMMDD hh:mm:ss.nnnnnn[+|-]' hh:mm
9999-12-31 23:59:59.9999999 '20090212 12:30:15.1234567+02.00'
最後三種數據類型(time、datetime二、datetimeoffset)的存儲空間大小要依賴於所選擇的精度,能夠經過0-7之間的整數來指定其精度
DECLARE @time DATETIME2=GETDATE() DECLARE @time0 DATETIME2(0)=GETDATE() DECLARE @time1 DATETIME2(1)=GETDATE() DECLARE @time2 DATETIME2(2)=GETDATE() DECLARE @time3 DATETIME2(3)=GETDATE() DECLARE @time4 DATETIME2(4)=GETDATE() DECLARE @time5 DATETIME2(5)=GETDATE() DECLARE @time6 DATETIME2(6)=GETDATE() DECLARE @time7 DATETIME2(7)=GETDATE() SELECT @time,@time0,@time1,@time2,@time3,@time4,@time5,@time6,@time7
--2014-03-03 16:09:30.3030000 --2014-03-03 16:09:30 --2014-03-03 16:09:30.3 --2014-03-03 16:09:30.30 --2014-03-03 16:09:30.303 --2014-03-03 16:09:30.3030 --2014-03-03 16:09:30.30300 --2014-03-03 16:09:30.303000 --2014-03-03 16:09:30.3030000
set language 命令改寫會話中默認語言(不推薦,由於代碼中的某些地方可能會依賴與用戶的默認語言)
set dateformat 命令能夠設置當把字符串類型轉換成日期和時間類型時,SQL Server如何解釋輸入的字符串常量。
dateformat 設置是由字符d、m、y的組合表示的。例如 us_english語言設計會把dateformat設置爲mdy,而british語言設置則將dateformat設置爲dmy。
當一個表達式涉及了兩種不一樣類型的操做數,會將其中類型隱式轉換成另一種類型在進行比對,老是將數據類型優先級低的向高的轉換。
數據類型優先級 當兩個不一樣數據類型的表達式用運算符組合後,數據類型優先級規則指定將優先級較低的數據類型轉換爲優先級較高的數據類型。若是此轉換不是所支持的隱式轉換,則返回錯誤。
當兩個操做數表達式具備相同的數據類型時,運算的結果便爲該數據類型。
SQL Server 對數據類型使用如下優先級順序:
1.用戶定義數據類型(最高)
2.sql_variant
3.xml
4.datetimeoffset
5.datetime2
6.datetime
7.smalldatetime
8.date
9.time
10.float
11.real
12.decimal
13.money
14.smallmoney
15.bigint
16.int
17.smallint
18.tinyint
19.bit
20.ntext
21.text
22.image
23.timestamp
24.uniqueidentifier
25.nvarchar(包括 nvarchar(max))
26.nchar
27.varchar(包括 varchar(max))
28.char
29.varbinary(包括 varbinary(max))
30.binary(最低)
爲了潛在地有效利用索引,就須要對謂詞進行調整,一邊對過濾條件中的列不進行處理----在謂詞條件中不作過多的處理
cast和convert函數
cast 和 convert函數用於轉換值的數據類型。
語法
cast(value as datatype)
convert(datatype , value , [style_number])
這兩個函數均可以將輸入的值轉換爲指定的數據類型。在一些狀況下,還能用convert提供的第三個參數來指定轉換的樣式。
注意 cast是ANSI標準SQL,而convert不是,因此除非須要使用樣式值,不然推薦優先使用cast函數。
DateAdd函數
DateAdd函數 能夠將指定日期的部分做爲單位,爲輸入的日期和時間值增長指定的數量。
語法
dateadd(part,n,dt_val)
日期部分的有效值包括year、quarter、month、dayofyear、day、week、weekday、hour、minite、second、millisecond、microsecond、nanosecond,最後兩個是SQL 2008新增長的。
也能夠用縮寫代替如 year(yy).
SELECT DATEADD(YEAR,2,'20120228')--2014-02-28 00:00:00.000
datadiff函數
datediff返回兩個日期和時間值之間相差的指定部分的計數
語法
datediff(part,dt_val,dt_val2)
返回兩個值之間的相差的天數 SELECT DATEDIFF(DAY,'20130228','20140228')--365
--返回兩個值之間的相差的天數
SELECT DATEDIFF(DAY,'20130228','20140228')--365 --當天午夜
SELECT DATEADD(DAY,DATEDIFF(DAY,0,CURRENT_TIMESTAMP),0);--2014-02-26 00:00:00.000 --當月第一天
SELECT DATEADD(month,DATEDIFF(month,0,CURRENT_TIMESTAMP),0);--2014-02-01 00:00:00.000 --當月的最後一天
SELECT DATEADD(month,DATEDIFF(month,'19911231',CURRENT_TIMESTAMP),'19911231');--2014-02-28 00:00:00.000
datepart函數
datepart函數返回一個表示給定日期和時間值的指定部分的總數。
語法
patepart(part,dt_val)
part參數的有效值包括year、quater、month、dayofyear、day、week、weekday、hour、minute、second、milliseconde、milliseconde、microsecond,manosecond,
TZoffset、ISO_WEEK
year、month、day函數
year、month、day函數是datepart函數的簡略版本,他們分別返回一個表明輸入日期和時間值中年月日部分的整數。
語法
year(dt_val)
month(dt_val)
day(dt_val)
datename 函數
datename函數返回一個表示給定日期和時間值的指定部分的字符串。
語法
datename(part,dt_val)
SELECT DATENAME(year,'20240225')--2024
SELECT DATENAME(month,'20240225')--February
SELECT DATENAME(day,'20240225')--25
datename返回的月份名稱是依賴語言的。
isdate函數
isdate函數接受一個字符串做爲輸入,若是能把這個字符串轉換爲日期和時間數據類型的值,則返回1,若是不能則返回0。
語法 isdate(string)
select ISDATE('20240225')--1
查看更多時間與轉型的例子 日期函數與轉型
查詢元數據
若是想列出數據庫中的各個表,以及他們的框架名稱,查詢sys.tables
SELECT SCHEMA_NAME([schema_id]) AS table_schema_name , name AS table_name FROM sys.tables
上面利用了SCHEMA_NAME()函數把表示框架Id的整數轉換成它的名稱。
若是你想獲得有關某個表的列的信息,你能夠查詢sys.columns表。
SELECT name AS column_name ,--列名 TYPE_NAME(system_type_id) AS column_type ,--數據類型 max_length ,--最大長度 collation_name ,--排序規則 is_nullable--名稱 FROM sys.columns WHERE object_id = OBJECT_ID(N'Sales.orders')
更多資料更多內容可在SQL Server聯機叢書的「查詢SQL Server系統目錄(queryint the SQL Server System Catalog)」章節中查找
練習題
--練習題 --1.返回2007年六月生成的訂單。 --1.1
SELECT orderid,orderdate,custid,empid FROM Sales.Orders WHERE orderdate >= '20070601' AND orderdate < '20070701'
ORDER BY orderid --1.2
SELECT orderid,orderdate,custid,empid FROM Sales.Orders WHERE orderdate BETWEEN '20070601' AND '20070630'
ORDER BY orderid --2.返回每月最後一天生成的訂單
--每月的最後一天
SELECT DATEADD(MONTH, DATEDIFF(MONTH, '20140131', GETDATE()), '20140131') AS '當月最後一天'
SELECT orderid ,orderdate ,custid ,empid FROM Sales.Orders WHERE CAST(orderdate AS DATE) = CAST(DATEADD(MONTH,DATEDIFF(MONTH, '20140131',orderdate), '20140131') AS DATE) --3.返回姓氏(last name)中包含字母‘a’兩次或者更屢次的僱員。
SELECT empid ,firstname ,lastname FROM HR.Employees WHERE lastname LIKE '%a%a%'
--4.返回總價格(數量*單價)大於10000的全部訂單,並按照總價格排序。
SELECT orderid , SUM(unitprice * qty) AS totalvalue FROM Sales.OrderDetails GROUP BY orderid HAVING SUM(unitprice * qty) > 10000
--5.返回2007年平均運費最高的三個發貨國家 --5.1
SELECT TOP 3 shipcountry , AVG(freight) AS avgfreight FROM Sales.Orders WHERE YEAR(orderdate) = 2007
GROUP BY shipcountry ORDER BY avgfreight DESC
--5.2
SELECT TOP 3 shipcountry , AVG(freight) AS avgfreight FROM Sales.Orders WHERE orderdate >= '20070101' AND orderdate < '20080101'
GROUP BY shipcountry ORDER BY avgfreight DESC
--6.爲每一個顧客單獨根據訂單日期的順序(用order ID做爲附加屬性)來計算其訂單的行號。
SELECT custid ,orderdate ,orderid , ROW_NUMBER() OVER ( PARTITION BY custid ORDER BY orderid ) AS rownum FROM Sales.Orders --7.構造一個select語句,讓他根據每一個僱員的友好稱呼,而返回其性別。 --對於‘Ms.’和‘Mrs.’,則返回‘Female’,對於‘Mr.’ 則返回‘Male’;對於其餘狀況(例如,‘Dr.’),則返回‘Unknow’。 --7.1
SELECT empid ,lastname ,firstname ,titleofcourtesy , CASE titleofcourtesy WHEN 'Ms.' THEN 'Female'
WHEN 'Mr.' THEN 'Male'
ELSE 'Unknow'
END AS gender FROM hr.Employees --7.2
SELECT empid ,lastname ,firstname ,titleofcourtesy , CASE WHEN titleofcourtesy = 'Ms.' THEN 'Female'
WHEN titleofcourtesy = 'Mr.' THEN 'Male'
ELSE 'Unknow'
END AS gender FROM hr.Employees --8.返回每一個客戶的客戶ID和所在區域。對輸出中的行按區域排序,NULL值排在最後面。 --8.1
SELECT custid ,region FROM Sales.Customers ORDER BY CASE WHEN region IS NULL THEN 1 ELSE 0 END ,region --8.2
SELECT custid ,region FROM ( SELECT custid ,region , CASE WHEN region IS NULL THEN 1 ELSE 0 END AS Orderregion FROM Sales.Customers ) v ORDER BY Orderregion --8.3
SELECT custid ,region FROM Sales.Customers WHERE region IS NOT NULL
UNION ALL
SELECT custid ,region FROM Sales.Customers WHERE region IS NULL
參考一:SQL_DDL_建庫建表
參考二:SQL with ties的理解與_huanghai223
參考三:日期函數與轉型
參考四 :SQL_DDL_建庫建表