1. 程式人生 > >T-SQL——基礎語法

T-SQL——基礎語法

[TOC] shanzm-2020年11月30日 20:47:15
### 0. 定義變數 在T-SQL中,變數以`@`符號開頭,使用`DECLARE`宣告變數(一次可以宣告多個變數),並同時定義變數的資料型別。 * 語法:使用`SET`或者使用`SELECT`給變數賦值 ```sql DECLARE @Num AS INT ,@Result AS INT SET @Num=10 SELECT @Result=20 SET @Result=@Num+@Result SELECT @Result ``` * 注意1: 宣告變數的時候,可以省略`AS` ```sql DECLARE @Num INT SET @Num=10 SELECT @Num ``` * 注意2:SQL Server 2008新增語法特性:宣告變數的時候可以同時賦值 ```sql DECLARE @i INT=100--宣告變數的同時給變數賦值 SELECT @i ``` * 注意3:使用`SET`一次只能給一個變數賦值,而使用`SELECT`可以一次賦值多個變數 ```sql SET @Num=10--SET一次只能個一個變數賦值 SELECT @Num=10,@Resutl=100--SELECT一次可以給多個變數賦值 ``` * 注意4:不能使用同一個`SELECT`即對某個變數使用某個欄位賦值,又同時從表中查詢另外欄位。 ```sql DECLARE @Age varchar(50) SELECT NAME,@AGE=Age FROM T_STUDENTS--這裡就是即用Age欄位對@Age賦值,又同時查詢Name欄位 ``` 上面的語句就會報錯: ```txt 向變數賦值的 SELECT 語句不能與資料檢索操作結合使用。 ``` 但是注意若是`SELECT`僅是通過查詢欄位賦值給某個變數,則是完全沒有問題的 ```sql DECLARE @Age VARCHAR(50),@Name VARCHAR(50) WITH Temp AS ( SELECT '張三' AS Name ,12 AS Age UNION ALL SELECT '李四' AS Name, 14 AS Age UNION ALL SELECT '王五' AS Name, null AS Age ) SELECT @Name=Name ,@Age=Age FROM Temp WHERE Name='張三' SELECT @Name, @Age 結果: ----- ------ 張三 12 ```

### 1. 批處理 批處理是作為一個單元而進行分析和執行的一組T-SQL語句。 批處理需要經歷的處理階段:分析(語法檢查)-->解析(檢查查詢的物件和列是否存在,是否具有訪問許可權)-->優化(作為一個執行單元) 批處理和事務是不一樣的:簡單的說一個批處理裡中可以有多個事務! 在SQL SERVER Management中,可以使用GO命令,表示一個批處理結束標誌。但是注意:GO命令是SQL SERVER Management工具的命令,而不是SQL SERVER伺服器的命令。 `GO`命令可以帶有引數,實現重複執行同一個批處理(SQL SERVER 2005),`GO n`,n為執行批處理的次數。 * 簡單例項——重複執行批處理 ```sql 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都不會執行 ```sql DECLARE @Name NVARCHAR(50) ='Tom' SELECT @Name GO--以上是第一個批處理 SELECT GETDATE() SELECT GETDAT()--有意製造一個錯誤 GO--以上是第二個批處理 執行結果: ------------ Tom (1 行受影響) 訊息 195,級別 15,狀態 10,第 6 行 'GETDAT' 不是可以識別的 內建函式名稱。 ``` 說明:第一批處理執行完畢,第二批處理中存在語法錯誤,故第二批處理中的所有SQL都沒有執行。 批處理與變數:定義在批處理中的變數是該批處理的區域性變數。 * 簡單例項——變數作用域為定義其的批處理中 ```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 ```sql DECLARE @i int =100 IF @i=100 PRINT 'i=100' ELSE PRINT 'i!=100' ``` * BEGIN……END 若是需要在IF或ELSE部分執行多條語句,則可以使用語句塊。語句塊使用`BEGIN……END`關鍵字識別,就相當於“{}” ```sql 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 ```sql 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表 ```sql USE Test GO IF EXISTS(SELECT * FROM SYSOBJECTS WHERE NAME='Employee') Begin PRINT '當前Test資料庫中存在Employee表' END ELSE BEGIN PRINT '當前Test資料庫中不存在Employee表' END ``` 另外一種查詢當前資料庫中是否存在指定的T-SQL程式設計物件的方法 ```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`是一個標量表達式,因此可以在任何允許使用標量表達式的地方使用它。例如:`SELECT`,`WHERE`,`HAVING`和`ORDER BY`子句中。 * 如果`CASE`表示式沒有`ELSE`子句,預設為`ELSE NULL` * 簡單示例1——在SELCET語句中使用--簡單格式表示式 常用的場景,將某個縮寫詞欄位中的值替換為完整描述性的值 ```sql 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語句中使用--搜尋格式 根據條件在查詢結果集中新增一個列(欄位) ```sql 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語句中使用 排序的時候,既不是升序也不是降序,而是按照自定義的順序排序 ```sql 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 ``` 結果: ```txt Name Age ----- ----- Jerry 16 Tom 14 Bob 15 ``` * 簡單示例4——在WHERE語句中使用 使用情形1:根據不同的值選擇不同的欄位作為篩選條件中使用的欄位。 當輸入引數@Flag為1的時候,取數學成績為100的學生,當輸入引數@Flag為2的時候,取語文成績為100的學生 當然這裡也可使用使用IF語句判斷不同的@Flag值執行不同的SELECT語句,這裡使用CASE WHEN語句演示: ```sql 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歲年齡的只取女性 ```sql 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——迴圈列印 ```sql DECLARE @i INT =0; WHILE @i<10 BEGIN PRINT @i; SET @i=@i+1; END; ``` * 簡單例項——打斷迴圈 ```sql DECLARE @i INT =0; WHILE @i<10 BEGIN IF @i=6 BREAK;--當@i=6的時候,就停止迴圈 PRINT @i; SET @i=@i+1; END; ``` * 簡單示例——跳出本次迴圈 ```sql 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。 ```sql DECLARE @Name VARCHAR SELECT ISNULL(@Name,'') ``` * `COALESCE()` :返回列表中第一個非null表達的值。如果所有表示式求值為null,則返回null ```sql DECLARE @Name VARCHAR DECLARE @Age INT SELECT Coalesce(@Name,@Age,2) 結果: Result ------- 2 ``` * `IFF()` :根據布林表示式計算為 true 還是 false,返回其中一個值。 語法:`IFF(boolean_expression, true_value, false_value) ` **其作用就是一個三元運算子** ```sql DECLARE @a INT = 45, @b INT = 40; SELECT IIF ( @a > @b, 'TRUE', 'FALSE' ) AS Result; 結果: Result ------ TRUE ``` 關於IFF()的使用,其實可以替代CASE兩個分支的情形,當前CASE分支是兩個相互物件的情形的時候,可以使用IFF()簡單的實現: ```sql 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開始的計數**的。 ```sql SELECT CHOOSE ( 3, '第一名', '第二名', '第三名', '第四名' ) AS Result; 結果: Result ------ 第三名 ``` 其作用和CASE的簡單表示式的作用一樣,將某一列縮寫類的值轉換為描述性的值 簡單示例:根據出生日期,確定出生季節 ```sql 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 ```

### 6. 參考 * [SQL文件](https://docs.microsoft.com/zh-cn/sql/t-sql/language-reference?view=sql-server-ver15) * [SQL SERVER 2012 T-SQL基礎教程](https://book.douban.com/subject/258