0. 定義變量
-
聲明變量:變量以
@
符號開頭,使用DECLARE
聲明變量(一次可以聲明多個變量),並同時定義變量的數據類型。 -
若是聲明變量時沒有初始化,則變量值為NULL
-
賦值語法:使用
SET
或者使用SELECT
給變量賦值
DECLARE @Num AS INT ,@Result AS INT
SET @Num=10
SELECT @Result=20
SET @Result=@Num+@Result
SELECT @Result
- 注意1: 聲明變量的時候,可以省略
AS
DECLARE @Num INT
SET @Num=10
SELECT @Num
- 注意2:SQL Server 2008新增語法特性:聲明變量的時候可以同時賦值
DECLARE @i INT=100--聲明變量的同時給變量賦值
SELECT @i
- 注意3:使用
SET
一次只能給一個變量賦值,而使用SELECT
可以一次賦值多個變量
SET @Num=10--SET一次只能個一個變量賦值
SELECT @Num=10,@Resutl=100--SELECT一次可以給多個變量賦值
- 注意4:不能使用同一個
SELECT
即對某個變量使用某個字段賦值,又同時從表中查詢另外字段。
DECLARE @Age varchar(50)
SELECT NAME,@AGE=Age FROM T_STUDENTS--這里就是即用Age字段對@Age賦值,又同時查詢Name字段
上面的語句就會報錯:
向變量賦值的 SELECT 語句不能與數據檢索操作結合使用。
但是注意若是SELECT
僅是通過查詢字段賦值給某個變量,則是完全沒有問題的
- 注意5:使用
SELECT
查詢結果給變量賦值,若是查詢結果有多個記錄,則給變量賦值的是記錄的最后一行。若是SELECT
無返回值則變量值為NULL
----------------------------------測試數據
DECLARE @studentVar TABLE
(
Name VARCHAR(10),
Age INT
);
INSERT INTO @studentVar
(
Name,
Age
)
VALUES
('張三', 18),
('李四', 19),
('王五', 18);
----------------------------------測試1,Select查詢結果賦值給變量
DECLARE @Age VARCHAR(50),@Name VARCHAR(50)
SELECT @Name=Name ,@Age=Age FROM @studentVar WHERE Name='張三'
SELECT @Name, @Age
-- 結果:
-- ----- ------
-- 張三 18
-----------------------------------測試2,Select查詢結果有多個記錄
DECLARE @Age2 VARCHAR(50),@Name2 VARCHAR(50)
SELECT @Name2=Name ,@Age2=Age FROM @studentVar WHERE Age=18
SELECT @Name2, @Age2
-- 結果:
-- ----- ------
-- 王五 18
- 【注意6】:使用
SELECT
和SET
將一個查詢語句的結果賦值給一個變量,是有區別的。
若是該查詢無結果,使用SELECT
賦值則則不會對變量做任何改變,而使用SET
賦值則變量變為NULL
DECLARE @subjectStr VARCHAR(100) = '123';
DECLARE @subjectStr2 VARCHAR(100) = '123';
DECLARE @studentVar TABLE
(
Name VARCHAR(10),
Age INT
);
INSERT INTO @studentVar
(
Name,
Age
)
VALUES
('張三', 18),
('李四', 19),
('王五', 18);
SET @subjectStr =
(
SELECT Name FROM @studentVar WHERE Name = '趙六'--無
);
SELECT @subjectStr;
--結果:NULL
SELECT @subjectStr =
(
SELECT Name FROM @studentVar WHERE Name = '趙六'--無
);
SELECT @subjectStr2;
--結果:123
關於T-SQL中的局部變量和全局變量:
-
局部變量:
- 是由用戶自己定義的,只在定義他的批處理和存儲過程中使用。
- 局部變量前用@符號做標記
-
全局變量:
- 是由系統定義並保留在系統中
- 變量前用@@標記
- 用戶只能使用系統預定義的全局變量,而不能自己定義全局變量
- 注意:用戶定義局部變量時候,不要與全局變量重名,否則將產生不可預測的后果
- 常用的全局變量見參考中給出的官方文檔鏈接,這里簡單羅列幾個常用的:
@@ERROR
:返回最后一次執行T-SQL語句的錯誤值,在存儲過程中可用於判讀是否出現錯誤@@VERSION
:返回當前的SQL SERVER的版本@@SERVERNAME
:返回本地運行SQL SERVER的服務器名@@ROWCOUNT
:返回最近一次數據庫操作所涉及的行數
1. 批處理
批處理是作為一個單元而進行分析和執行的一組T-SQL語句。
批處理需要經歷的處理階段:分析(語法檢查)-->解析(檢查查詢的對象和列是否存在,是否具有訪問權限)-->優化(作為一個執行單元)
批處理和事務是不一樣的:簡單的說一個批處理里中可以有多個事務!
在SQL SERVER Management中,可以使用GO命令,表示一個批處理結束標志。但是注意:GO命令是SQL SERVER Management工具的命令,而不是SQL SERVER服務器的命令。
GO
命令可以帶有參數,實現重復執行同一個批處理(SQL SERVER 2005),GO n
,n為執行批處理的次數。
- 簡單實例——重復執行批處理
SELECT SYSDATETIME()
GO 3
結果:
開始執行循環
---------------------------
2020-11-24 23:19:39.8413125
---------------------------
2020-11-24 23:19:39.8523131
---------------------------
2020-11-24 23:19:39.8573134
批處理執行已完成 3 次。
在執行批處理的時候首先是進行分析,如果批處理中出現語法錯誤,則整個批處理就不會執行。
- 簡單實例——批處理中出現一個語法錯誤,則整個批處理中SQL都不會執行
DECLARE @Name NVARCHAR(50) ='Tom'
SELECT @Name
GO--以上是第一個批處理
SELECT GETDATE()
SELECT GETDAT()--有意制造一個錯誤
GO--以上是第二個批處理
執行結果:
------------
Tom
(1 行受影響)
消息 195,級別 15,狀態 10,第 6 行
'GETDAT' 不是可以識別的 內置函數名稱。
說明:第一批處理執行完畢,第二批處理中存在語法錯誤,故第二批處理中的所有SQL都沒有執行。
批處理與變量:定義在批處理中的變量是該批處理的局部變量。
- 簡單實例——變量作用域為定義其的批處理中
DECLARE @Name NVARCHAR(50) ='Tom'
GO
SELECT @Name
結果:
消息 137,級別 15,狀態 2,第 3 行
必須聲明標量變量 "@Name"。
說明:SELECT @Name
不在定義變量@Name的批處理中,故執行失敗
2. 條件邏輯——IF
IF……ELSE
用於更具條件來控制SQL代碼塊的執行流程。如果條件取值為TRUE,則執行IF中的的SQL語句;如果條件取值為FALSE或UNKNOWN,則執行ELSE中的SQL語句(ELSE語句為可選)。
- IF……ELSE
DECLARE @i int =100
IF @i=100
PRINT 'i=100'
ELSE
PRINT 'i!=100'
- BEGIN……END
若是需要在IF或ELSE部分運行多條語句,則可以使用語句塊。語句塊使用BEGIN……END
關鍵字識別,就相當於“{}”
DECLARE @i int =100
IF @i=100
BEGIN
PRINT 'i=100'
END
ELSE
BEGIN
PRINT 'i!=100'
END
- 流程分支超過兩個
在其他語句中,有if……else if……else的語法,在SQL中沒有這樣的語法,但是可以嵌套使用if……else
DECLARE @i int =99
IF @i=101
BEGIN
PRINT 'i=101'
END
ELSE
IF @i=100
BEGIN
PRINT 'i=100'
END
ELSE
BEGIN
PRINT 'i!=101 and i!=100'
END
- 簡單示例
判斷當前數據庫Test中是否存在Employee表
USE Test
GO
IF EXISTS(SELECT * FROM SYSOBJECTS WHERE NAME='Employee')
Begin
PRINT '當前Test數據庫中存在Employee表'
END
ELSE
BEGIN
PRINT '當前Test數據庫中不存在Employee表'
END
另外一種查詢當前數據庫中是否存在指定的T-SQL編程對象的方法
USE Test
GO
IF OBJECT_ID('Employee','U') IS NOT NULL
Begin
PRINT '當前Test數據庫中存在Employee表'
END
ELSE
BEGIN
PRINT '當前Test數據庫中不存在Employee表'
END
3. 邏輯分支——CASE
-
CASE
表達式是一個標量表達式,返回一個基於條件邏輯的值。CASE是一個表達式,而不是一條語句,也就是說不能用它來控制活的的流程,也不能根據條件邏輯做某些處理,相反,它只是根據條件邏輯來返回某個值,故稱其為一個標量表達式。 -
CASE
是一個標量表達式,因此可以在任何允許使用標量表達式的地方使用它。例如:SELECT
,WHERE
,HAVING
和ORDER BY
子句中。 -
如果
CASE
表達式沒有ELSE
子句,默認為ELSE NULL
-
簡單示例1——在SELCET語句中使用--簡單格式表達式
常用的場景,將某個縮寫詞字段中的值替換為完整描述性的值
WITH Temp AS
(
SELECT 'Tom' AS Name ,14 AS Age ,1 AS Grade
UNION ALL
SELECT 'Bob' AS Name ,15 AS Age ,2 AS Grade
UNION ALL
SELECT 'Jery' AS Name,16 AS Age,3 AS Grade
)
SELECT Name,Age,
CASE Grade
WHEN 1 THEN '一年級'
WHEN 2 THEN '二年級'
WHEN 3 THEN '三年級'
ELSE 'NULL'
END AS Grade
FROM Temp
結果:
Name Age Grade
---- ----- ------
Tom 14 一年級
Bob 15 二年級
Jery 16 三年級
- 簡單示例2——在SELECT語句中使用--搜索格式
根據條件在查詢結果集中添加一個列(字段)
WITH Temp AS
(
SELECT 'Tom' AS Name ,13 AS Age
UNION ALL
SELECT 'Bob' AS Name ,15 AS Age
UNION ALL
SELECT 'Jerry' AS Name,16 AS Age
)
SELECT Name,Age ,
CASE
WHEN Age<=14 THEN '未成年'
WHEN Age>14 THEN '成年人'
END AS 類型
FROM Temp
- 簡單示例3——在ORDER BY語句中使用
排序的時候,既不是升序也不是降序,而是按照自定義的順序排序
WITH Temp AS
(
SELECT 'Tom' AS Name ,14 AS Age
UNION ALL
SELECT 'Bob' AS Name ,15 AS Age
UNION ALL
SELECT 'Jerry' AS Name,16 AS Age
)
SELECT Name,Age
FROM Temp
ORDER BY
CASE
WHEN Name='Jerry' THEN 1
WHEN Name='Tom' THEN 2
WHEN Name='Bob' THEN 3
END
結果:
Name Age
----- -----
Jerry 16
Tom 14
Bob 15
- 簡單示例4——在WHERE語句中使用
使用情形1:根據不同的值選擇不同的字段作為篩選條件中使用的字段。
當輸入參數@Flag為1的時候,取數學成績為100的學生,當輸入參數@Flag為2的時候,取語文成績為100的學生
當然這里也可使用使用IF語句判斷不同的@Flag值執行不同的SELECT語句,這里使用CASE WHEN語句演示:
DECLARE @Flag INt=1;
WITH Temp AS
(
SELECT '張三' AS Name ,12 AS Age,'男' AS Gender,100 AS MathGrade,80 AS ChineseGrade
UNION ALL
SELECT '李四' AS Name, 14 AS Age,'女' AS Gender,90 AS MathGrade,80 AS ChineseGrade
UNION ALL
SELECT '王五' AS Name, 15 AS Age,'男'AS Gender,80 AS MathGrade,90 AS ChineseGrade
UNION ALL
SELECT '趙六' AS Name, 15 AS Age,'女'AS Gender,80 AS MathGrade,100 AS ChineseGrade
)
--select * from temp where (case when @Flag=1 then MathGrade=100 when @Flag=2 then ChineseGrade=100 end)--錯誤寫法
--select * from temp where (case @Flag when 1 then MathGrade when 2 then ChineseGrade end)=100
--等價於下面寫法:
SELECT * FROM Temp WHERE (CASE WHEN @Flag=1 Then MathGrade WHEN @Flag=2 THEN ChineseGrade END)=100
--更常規,更便於理解的寫法
SELECT * FROM temp WHERE (@Flag=1 AND MathGrade=100) OR (@Flag=2 AND ChineseGrade=100)
使用情形2:篩選條件中出現IN(……),再對某個特定的值,做篩選
首先年齡在12~15歲的人,且15歲年齡的只取女性
WITH Temp AS
(
SELECT '張三' AS Name ,12 AS Age,'男' AS Gender,100 AS MathGrade,80 AS ChineseGrade
UNION ALL
SELECT '李四' AS Name, 14 AS Age,'女' AS Gender,90 AS MathGrade,80 AS ChineseGrade
UNION ALL
SELECT '王五' AS Name, 15 AS Age,'男'AS Gender,80 AS MathGrade,90 AS ChineseGrade
UNION ALL
SELECT '趙六' AS Name, 15 AS Age,'女'AS Gender,80 AS MathGrade,100 AS ChineseGrade
)
SELECT * FROM Temp WHERE Age IN (12,13,14,15) AND (CASE WHEN age=15 AND gender<>'女' THEN 0 ELSE 1 END)=1
結果:
張三 12 男 100 80
李四 14 女 90 80
趙六 15 女 80 100
4. 循環語句——WHILE
T-SQL中使用WHILE
循環執行代碼。只要在WHILE關鍵字之后指定的表達式為TRUE,WHILE會重復執行一個語句塊
- 簡單示例1——循環打印
DECLARE @i INT =0;
WHILE @i<10
BEGIN
PRINT @i;
SET @i=@i+1;
END;
- 簡單實例——打斷循環
DECLARE @i INT =0;
WHILE @i<10
BEGIN
IF @i=6 BREAK;--當@i=6的時候,就停止循環
PRINT @i;
SET @i=@i+1;
END;
- 簡單示例——跳出本次循環
DECLARE @i INT =0;
WHILE @i<10
BEGIN
SET @i=@i+1;
IF @i=6 CONTINUE;--當@i=6的時候,跳出本次循環
PRINT @i;
END;
- 注意:使用WHILE循環的時候,尤其是在配合IF語句的時候,注意不要進入死循環
5. 附錄——關於CASE表達式的實現函數
T-SQL支持的某些函數,本質上是可以看作是CASE表達式的縮寫:
ISNULL()
:使用指定的替換值替換 NULL。
DECLARE @Name VARCHAR
SELECT ISNULL(@Name,'')
COALESCE()
:返回列表中第一個非null表達的值。如果所有表達式求值為null,則返回null
DECLARE @Name VARCHAR
DECLARE @Age INT
SELECT Coalesce(@Name,@Age,2)
結果:
Result
-------
2
IFF()
:根據布爾表達式計算為 true 還是 false,返回其中一個值。
語法:IFF(boolean_expression, true_value, false_value)
其作用就是一個三元運算符
DECLARE @a INT = 45, @b INT = 40;
SELECT IIF ( @a > @b, 'TRUE', 'FALSE' ) AS Result;
結果:
Result
------
TRUE
關於IFF()的使用,其實可以替代CASE兩個分支的情形,當前CASE分支是兩個相互對象的情形的時候,可以使用IFF()簡單的實現:
WITH Temp AS
(
SELECT 'Tom' AS Name ,13 AS Age
UNION ALL
SELECT 'Bob' AS Name ,15 AS Age
UNION ALL
SELECT 'Jerry' AS Name,16 AS Age
)
SELECT Name,Age, IIF(Age<14,'未成年人','成年人') AS AgeType FROM temp
結果:
Name Age AgeType
----- ----------- --------
Tom 13 未成年人
Bob 15 成年人
Jerry 16 成年人
CHOOSE
:從值列表返回指定索引處的項。
語法:CHOOSE ( int_index, val_1, val_2 [, val_n ] )
第一個參數是后面值列表的索引,后面的參數就是值列表
注意值列表的索引是從1開始的計數的。
SELECT CHOOSE ( 3, '第一名', '第二名', '第三名', '第四名' ) AS Result;
結果:
Result
------
第三名
其作用和CASE的簡單表達式的作用一樣,將某一列縮寫類的值轉換為描述性的值
簡單示例:根據出生日期,確定出生季節
WITH Temp AS
(
SELECT 'Tom' AS Name ,'2020-1-11' AS Birthday
UNION ALL
SELECT 'Bob' AS Name ,'2020-5-11' AS Birthday
UNION ALL
SELECT 'Jerry' AS Name,'2020-10-11' AS Birthday
)
SELECT Name, Birthday,
CHOOSE(MONTH(Birthday), 'Spring','Spring','Spring','Summer','Summer', 'Summer','Autumn','Autumn','Autumn','Winter','Winter','Winter') AS Birth_Quarter
FROM Temp
結果:
Name Birthday Birth_Quarter
----- ---------- -------------
Tom 2020-1-11 Spring
Bob 2020-5-11 Summer
Jerry 2020-10-11 Winter