sql server編程之 T-SQL函數

 T-SQL函數

  • 學習系統函數、行集函數和Ranking函數;重點掌握字符串函數、日期時間函數和數學函數的使用參數以及使用技巧
  • 重點掌握用戶定義的標量函數以及自定義函數的執行方法
  • 掌握用戶定義的內嵌表值函數以及與用戶定義的標量函數的主要區別
在Transact-SQL語言中,函數被用來執行一些特殊的運算以支持SQL Server的標準命令。SQL Server包含多種不同的函數用以完成各種工作,每一個函數都有一個名稱,在名稱之後有一對小括號,如:gettime( )表示獲取系統當前的時間。大部分的函數在小括號中需要一個或者多個參數。Transact-SQL 編程語言提供了四種函數:行集函數、聚合函數、Ranking函數、標量函數。
由於聚集函數在上一章中已經介紹,因此本節首先重點討論標量函數及Ranking函數的具體名稱以及內容和使用方法。
2-3-1 標量函數
標量函數用於對傳遞給它的一個或者多個參數值進行處理和計算,並返回一個單一的值。標量函數可以應用在任何一個有效的表達式中。標量函數可分爲如表2-4所示的幾大類:
表2-4 標量函數的基本分類
函數分類
解釋
配置函數
返回當前的配置信息
遊標函數
返回有關遊標的信息
日期和時間函數
對日期和時間輸入值進行處理
數學函數
對作爲函數參數提供的輸入值執行計算
元數據函數
返回有關數據庫和數據庫對象的信息
安全函數
返回有關用戶和角色的信息
字符串函數
對字符串(char 或 varchar)輸入值執行操作
系統函數
執行操作並返回有關SQL Server中的值、對象和設置的信息
系統統計函數
返回系統的統計信息
文本和圖像函數
對文本或圖像輸入值或列執行操作,返回有關這些值的信息
1. 系統函數
系統函數用於返回有關SQL Server系統、用戶、數據庫和數據庫對象的信息。系統函數可以讓用戶在得到信息後,使用條件語句,根據返回的信息進行不同的操作。與其他函數一樣,可以在SELECT語句的SELECT和WHERE子句以及表達式中使用系統函數,下面我們通過案例對重要的系統函數進行注意的介紹。
實驗: 系統函數應用實驗
--該部分函數主要解決如何獲取SQL-sever的系統信息。
1、COL_LENGTH(expression):返回列的定義長度(以字節爲單位)。
2、DATALENGTH(expression):返回任何表達式所佔用的字節數。
--例1:col_length ()函數的使用
Use sample
Go
Select col_length(’員工數據表’, ’姓名’) as name_data_length ,
Datalength(’姓名’) as name_data_length from 員工數據表
--(註解: col_length ()函數可以返回列的長度)
3、ISNUMERIC(expression)/返回類型 int:確定表達式是否爲一個有效的數字類型。
--例2:ISNUMERIC ()函數的使用
USE school
SELECT ISNUMERIC(sno) FROM student
GO
4、USER_ID():返回用戶的數據庫標識號。
5、USER_NAME():返回給定標識號的用戶數據庫用戶名。
USER_NAME ( [ id ] )id:用來返回用戶名的標識號。id 的數據類型爲 int,注意當省略 id 時,則假定爲當前用戶。必須加上圓括號。
--例3:USER_ID()函數的使用
SELECT USER_ID('MY-TOMATO') , USER_NAME('MY-TOMATO')
2. 字符串函數
字符串函數可以對二進制數據、字符串和表達式執行不同的運算,大多數字符串函數只能用於char和varchar數據類型以及明確轉換成char和varchar的數據類型,少數幾個字符串函數也可以用於binary和varbinary數據類型,字符串函數可以分爲以下幾大類:
(1)    基本字符串函數:UPPER,LOWER,SPACE,REPLICATE,STUFF,REVERSE,LTRIM,RTRIM。
(2)    字符串查找函數:CHARINDEX,PATINDEX。
(3)    長度和分析函數:DATALENGTH,SUBSTRING,RIGHT。
(4)    轉換函數:ASCH,CHAR,STR,SOUNDEX,DIFFERENCE。
下面我們通過案例對重要的字符串函數進行重點的介紹。
實驗: 字符串函數應用實驗
--該部分函數主要解決各種字符串的處理問題
1、CHAR(數字變量)
功能:將ASC碼轉換成爲字符串;
--注意ASC碼是指0——255之間的整數
例子:select char(56)
2、LEFT(字符串表達式,整數)
功能:返回從字符串左邊開始多少個字符
例子:select left(sname,2) from student
3、LTRIM函數和RTRIM函數
功能:刪除字符串的前導空格與後導空格。
例子:insert into student(sno,sname) values(990,'    看看空格    ')
select sname from student where sname like '%看看空格%'
select LTRIM(sname) from student where sname like '%看看空格%'
select RTRIM(sname) from student where sname like '%看看空格%'
select RTRIM(LTRIM(sname)) from student where sname like '%看看空格%'
--注意:去除前後導空格一般通過RTRIM(LTRIM(查詢字符串))聯合使用完成。
4、REPLACE(’第一個字符串’,’第二個字符串’,’第三個字符串’)
功能:用第三個表達式替換第一個字符串表達式中出現的所有第二個給定字符串表達式
例如:SELECT REPLACE('我是玉樹臨風的高狗熊','高狗熊','周星馳')
5、SUBSTRING(表達式,開始點,結束點)
功能:返回字符、binary、text 或 image 表達式的一部分。
例如:SELECT SUBSTRING('我是玉樹臨風的高狗熊',3,4)
6、CAST與CONVERT函數
功能:實現數據的格式轉化;將某種數據類型的表達式顯式轉換爲另一種數據類型。
CAST 和 CONVERT 提供相似的功能
使用 CAST:CAST ( expression AS data_type )
使用 CONVERT:CONVERT (data_type[(length)], expression [, style])
例如:select CONVERT(varchar(10),123)+'100'
select Cast(‘123’ as int)+ 100
7、LEN(string_expression)
功能:返回給定字符串表達式的字符(而不是字節)個數,其中不包含尾隨空格
例如:select LEN('   我是玉樹臨風的高狗熊   ')
8、LOWER()
功能:將大寫字符數據轉換爲小寫字符數據後返回字符表達式
例如:select UPPER('dsfgdfghtyuj')
9、UPPER()
功能:返回將小寫字符數據轉換爲大寫的字符表達式。
例如:create table titles(title varchar(24),price money)
insert into titles values('PPd',3.63)
SELECT LOWER(SUBSTRING(title, 1, 20)) AS Lower, UPPER(SUBSTRING(title, 1, 20)) AS Upper,    LOWER(UPPER(SUBSTRING(title, 1, 20))) As LowerUpper FROM titles WHERE price between 1.00 and 200.00
10、CHARINDEX ( expression1 , expression2 [ , start_location ] )
功能:返回字符串中指定表達式的起始位置。
例如:SELECT CHARINDEX('不', sname) FROM student
select sname from student
11、REPLICATE ( character_expression , integer_expression )
功能:以指定的次數重複字符表達式。
例如:declare @c varchar(12)
set @c='我是誰'
SELECT REPLICATE(@c, 4)
12、REVERSE ( character_expression )
功能:返回字符表達式的反轉。
例如:declare @c varchar(62)
set @c='請問你誰是周星馳啊'
SELECT REVERSE(@c)
13、STUFF ( character_expression , start , length , character_expression )
功能:刪除指定長度的字符並在指定的起始點插入另一組字符。
--例如:SELECT STUFF('請問你誰是周星馳啊', 6, 3,'')
3. 日期時間函數
日期和時間函數用於對日期和時間數據進行各種不同的處理和運算,並返回一個字符串、數字值或日期和時間值。與其他函數一樣,可以在SELECT語句的SELECT和WHERE子句以及表達式中使用日期和時間函數,如表2-5所示爲日期時間函數的基本內容。
表2-5 標量函數的基本分類
函數
參數
功能
DATEADD
(datepart,number,date)
以datepart指定的方式,返回date加上number之和
DATEDIFF
(datepart,date1,date2)
以datepart指定的方式,返回date2與date1之差
DATENAME
(datepart,date)
返回日期date中datepart指定部分所對應的字符串
DATEPART
(datepart,date)
返回日期date中datepart指定部分所對應的整數值
DAY
(date)
返回指定日期的天數
GETDATE
()
返回當前的日期和時間
MONTH
(date)
返回指定日期的月份數
YEAR
(date)
返回指定日期的年份數
實驗:日期時間函數實驗
1、DATEADD ( datepart , number, date )
功能:在向指定日期加上一段時間的基礎上,返回新的 datetime 值。
例如:USE school
SELECT DATEADD(day, 21, birthday) AS stu_biradd FROM student
2、DATEDIFF ( datepart , startdate , enddate )
功能:返回跨兩個指定日期的日期和時間邊界數。
例如:SELECT DATEDIFF(year, birthday, getdate()) AS 年齡 FROM student
3、DATENAME( datepart , date )
功能:返回代表指定日期的指定日期部分的字符串。
例如:SELECT DATENAME(month, birthday) AS '出生月' from student
4、DATEPART( datepart , date )
功能:返回代表指定日期的指定日期部分的整數。
例如:SELECT DATEPART (year, birthday) AS '出生月' from student
5、year(),month(),day()
功能:返回年月日
6、GETDATE()函數
功能:返回今天的日期
例如:SELECT DATEPART(month, GETDATE()) AS 'Month Number'
SELECT DATEPART(day, GETDATE()) AS 'day Number'
SELECT DATEPART(year, GETDATE()) AS 'year Number'
4. 數學函數
數學函數用於對數字表達式進行數學運算並返回運算結果。數學函數可以對SQL Server提供的數字數據(decimal、integer、float、real、money、smallmoney、smallint 和 tinyint)進行處理,具體解釋見下面的實驗內容。
實驗:數學函數實驗
可以使用數學函數執行各種算術或函數運算
1、ABS()函數(絕對值)
功能:精確數字或近似數字數據類型類別的表達式(bit 數據類型除外)。
例如:SELECT ABS(-2147483648)
2、CEILING()(取整函數)
功能:返回大於或等於所給數字表達式的最小整數。
例如:SELECT CEILING($123.45), CEILING($-123.45), CEILING($0.0)
3、FLOOR() (取整函數)
功能:返回小於或等於所給數字表達式的最大整數。
例如:SELECT FLOOR(123.45), FLOOR(-123.45), FLOOR($123.45)
注意: CEILING 和 FLOOR函數的差別是:
CEILING 函數返回大於或等於所給數字表達式的最小整數。FLOOR 函數返回小於或等於所給數字表達式的最大整數。例如,對於數字表達式 12.9273,CEILING 將返回 13,FLOOR 將返回 12。FLOOR 和 CEILING 返回值的數據類型都與輸入的數字表達式的數據類型相同
4、ROUND()(四捨五入函數)
功能:返回數字表達式並四捨五入爲指定的長度或精度。
語法:ROUND ( numeric_expression , length [ , function ] )
例如:下例顯示兩個表達式,說明使用 ROUND 函數且最後一個數字始終是估計值。
SELECT ROUND(123.9994, 3),ROUND(123.9995, 3)
SELECT ROUND(123.4545, 2),ROUND(123.45, -2)
5、sign(n)
功能: 當n>0, 返回1,n=0,返回0,n<0, 返回-1
例如:DECLARE @value real
SET @value = -1
WHILE @value < 2
   BEGIN
      SELECT SIGN(@value)
      SELECT @value = @value + 1
   END
6、RAND ( [ seed ] )
功能:返回 0 到1 之間的隨機float 值。
例如:DECLARE @counter smallint
SET @counter = 1
WHILE @counter < 5
   BEGIN
      SELECT RAND(@counter) Random_Number
      SET @counter = @counter + 1
   END
2-3-2 行集函數
行集函數可以在Transact-SQL語句中當作表引用。下面的案例將通過行集函數OPENQUERY()執行一個分佈式查詢,以便從服務器local中提取表department中的記錄。
select * from openquery(local, ‘select * from department’)
2-3-3 Ranking函數
Ranking函數爲查詢結果數據集分區中的每一行返回一個序列值。依據此函數,一些行可能取得和其他行一樣的序列值。如果兩個或多個行與一個排名關聯,則每個關聯行將得到相同的排名。例如,如果兩位頂尖銷售員具有同樣的SalesYTD(銷售額)值,他們將並列第一。由於已有兩行排名在前,所以具有下一個最大SalesYTD 的銷售人員將排名第三。因此,RANK 函數並不總返回連續整數。Transact-SQL提供以下一些Ranking函數:RANK;DENSE_RANK;NTILE;ROW_NUMBER。
實驗:Ranking函數實驗
爲了便於說明排序函數的使用,我們選取了school數據庫中的teacher表中salary(薪水)字段作爲排序的測試數據。我們首先運行一段SQL查詢:select tno,name , salary From teacher,查詢後的基本結構如圖2-3所示。我們看見,分別有三位教師的薪水是一樣高的。
1、ROW_NUMBER ( ) OVER ( [ <partition_by_clause> ] <order_by_clause> )
該函數將返回結果集分區內行的序列號,每個分區的第一行從 1 開始。row_number函數的用途是非常廣泛,這個函數的功能是爲查詢出來的每一行記錄生成一個序號。row_number函數的用法如下面的SQL語句所示:
select row_number() over(order by salary) as row_number,tno,name, salary from teacher
其中row_number列是由row_number函數生成的序號列。在使用row_number函數是要使用over子句選擇對某一列進行排序,然後才能生成序號。實際上,row_number函數生成序號的基本原理是先使用over子句中的排序語句對記錄進行排序,然後按着這個順序生成序號。over子句中的order by子句與SQL語句中的order by子句沒有任何關係,這兩處的order by 可以完全不同,如下面的SQL語句所示:select row_number() over(order by salary asc) as row_number,tno,name, salary from teacher order by salary desc
結果比較圖如圖2-5所示,請讀者與圖2-4進行數據比較。

圖2-3 薪酬排序基本情況     圖2-4 row_number函數排序    圖2-5 row_number另一使用

我們可以使用Row_number函數來實現查詢表中指定範圍的記錄,一般將其應用到Web應用程序的分頁功能上。下面的SQL語句可以查詢teacher表中第2條和第3條記錄:
with teacher_rowtable
as
(select row_number() over(order by tno) as row_number,tno,name, salary from teacher)
select * from teacher_rowtable where row_number>1 and row_number < 4 order by tno
2、RANK( ) OVER ([< partition_by_clause>]<order_by_clause>)
該函數將返回結果集的分區內每行的排名。行的排名是相關行之前的排名數加一。一個相關的SQL語句案例如下:select rank() over(order by salary) as ranker,tno,name,salary from teacher order by salary,結果如圖2-6所示。
我們看到,如果使用rank函數來生成序號,其中有3條記錄的序號是相同的,而第6條記錄會根據當前的記錄數生成序號,後面的記錄依此類推,也就是說,在這個例子中,第6條記錄的序號是6,而不是4。rank函數的使用方法與row_number函數完全相同。
3、DENSE_RANK ( ) OVER([<partition_by_clause>]<order_by_clause>)
該函數的功能與rank函數類似,只是在生成序號時是連續的,而rank函數生成的序號有可能不連續。如上面的例子中如果使用dense_rank函數,第6條記錄的序號應該是4,而不是6。如下面的SQL語句所示:select dense_rank() over(order by salary)as ranker,tno,name,salary from teacher order by salary,結果如圖2-7所示,讀者可以比較圖2-6和圖2-7所示的查詢結果有什麼不同。
4、NTILE(integer_expression) OVER([<partition_by_clause>]<order_by_clause>)
ntile函數可以對序號進行分組處理。這就相當於將查詢出來的記錄集放到指定長度的數組中,每一個數組元素存放一定數量的記錄。ntile函數爲每條記錄生成的序號就是這條記錄所有的數組元素的索引(從1開始)。也可以將每一個分配記錄的數組元素稱爲“桶”。ntile函數有一個參數,用來指定桶數。下面的SQL語句使用ntile函數對teacher表進行了裝桶處理,本次共裝3個桶:select ntile(3) over(order by salary) as bucket,tno,name,salary from teacher order by salary,結果如圖2-8所示。
    

2-6 RANK()使用情況       圖2-7 DENSE_RANK()使用情況    圖2-8 NTILE()使用情況
2-3-4 用戶自定義函數
SQL SERVER創建了用戶自定義的函數,它同時具備了視圖和存儲過程的優點,但是卻犧牲了可移植性。
Create Function 函數名稱
(形式參數名稱 AS 數據類型)
Returns 返回數據類型
Begin
函數內容
Return 表達式
End
調用用戶自定義函數的基本語法爲:變量=用戶名.函數名稱(實際參數列表),注意:在調用返回數值的用戶自定義函數時,一定要在函數名稱的前面加上用戶名。
1. 用戶定義的標量函數
標量函數是返回單個值的函數,這類函數可以接收多個參數,但是返回的值只有一個值。在定義函數返回值時使用Returns定義返回值的類型,而在定義函數中將使用return最後返回一個值變量,因此在用戶定義的函數中,return命令應當是最後一條執行的命令,其基本的語法結構見下所示:
CREATE FUNCTION [ 用戶名.] 定義的函數名
    ( [ { @變量名 [AS] 變量類型 [ ,...n ] ] ) 
RETURNS 返回值的數據類型
[ AS ]
BEGIN
    declare @返回值變量    function_body
     RETURN @返回值變量
    END
2. 自定義函數的執行方法
用戶定義函數的執行方法有兩種:
(1)    第一種:通過Execute執行函數,並獲取返回值;
EXECUTE  @用戶自定義變量=dbo.用戶自定義函數 輸入參數
該執行方法使用過程中,dbo的概念是database owner,爲數據庫所有者,在執行該語句的時候,可以省略dbo。
例如:execute @ee=averc ‘3-105’或者execute @ee=dbo.averc ‘3-105’
(2)    第二種:通過Select語句執行函數,並獲取返回值;
SELECT @用戶自定義變量=dbo.用戶自定義函數(輸入參數)
與Execute執行函數不同的是,通過SELECT語句執行函數的時候,必須加上dbo用戶,否則會出現語法錯誤。
例如:select @ee=dbo.averc(‘3-105’),但是執行下列的語句系統將報錯:
q        錯誤!select @ee=averc(‘3-105’),原因是沒有加dbo用戶;
q        錯誤!select @ee=dbo.averc ‘3-105’,原因是沒有按照select格式錄入參數。
實驗:自定義標量函數實驗
--例1:建立自定義函數,輸入課程號,返回該課程的平均成績。
CREATE function averc(@cno varchar(12))
returns int
as
begin
declare @aver int
select @aver= ( select avg(degree) from score where cno=@cno group by cno )
return @aver
end
--下面是測試如何運行該函數部分。
declare @ee int, @ww varchar(12)
select @ee=dbo.averc('3-105‘)
print @ee
--例2:建立自定義函數,輸入學生學號和課程號,返回不同的信息
use school
Go
--查詢sysobjects系統表中是否有stufun_jg對象,如果有則將該函數對象刪除。
if exists(select name from sysobjects where name='stufun_jg')
drop function stu_jg
go
--下面開始建立自定義函數
create function stu_jg
(@stu_no varchar(12),@cnurse_no varchar(12))
returns varchar(100)
as
begin
declare @message varchar(100),
@sname varchar(12),@cname varchar(10)
if exists(select sname,cname from score,course,student where student.sno=@stu_no and course.cno=@cnurse_no and student.sno=score.sno and course.cno=score.cno)
begin
   select @sname=sname,@cname=cname from score,course,student
   where student.sno=@stu_no and course.cno=@cnurse_no
   and student.sno=score.sno and course.cno=score.cno
   set @message='您查詢的學生是:'+RTRIM(LTRIM(@sname))+',選擇的課程是:'+RTRIM(LTRIM(@cname))
end
else
    set @message='對不起查無此人,您輸入的學生號碼錯誤!'
    return @message
end
--下面開始測試函數,注意函數的執行測試方法
declare @mess varchar(500)
exec @mess=dbo.stu_jg '121','3-105'
Print @mess
3. 用戶定義的內嵌表值函數
用戶定義的內嵌表值函數沒有由begin—end標識的程序體,取而代之的是將select 語句作爲table數據類型加以返回,其基本的語法結構見下所示:
CREATE FUNCTION [ 用戶名.]用戶定義的函數名
     ( [ { @局部變量名 [AS]局部變量數據類型 } [ ,...n ] ] ) 
RETURNS TABLE
[ AS ]
RETURN
( select-stmt)
實驗:用戶定義的內嵌表值函數實驗
--例1:創建函數,查詢選修了某門課程的學生姓名
create function fn_view(@cname varchar(20)) returns table
as
return
(select sname from student where sno in(select sno from score where cno in
(select cno from course where cname=@cname) ))
--下面開始測試函數
declare @ee varchar(20)
set @ee='高等數學'
select * from fn_view(@ee)
--例2:建立函數,輸入一個學生的學號就可以知道他的姓名,選修課程名以及該門課程的成績
create function stu_avg_table(@sno varchar(20))
returns @stu_avg table
(sno varchar(12),sname varchar(20),cname varchar(20),degree int)
as
begin
insert @stu_avg
    select student.sno,sname,cname,degree from student,score,course
    where student.sno=score.sno and course.cno=score.cno and student.sno=@sno
return
end
--下面開始測試函數
declare @rr varchar(20)
set @rr='103'
select * from stu_avg_table(@rr)
--例3:查詢銷售數據庫,輸入一個貨幣參數,返回超過該銷售額數目的訂單數據表
Use sample
Go
/*開始定義變量@higher_money ,以保存檢索定單的總價限制*/
if exists(select name from sysobjects where name='large_order')
drop function large_order
go
--下面開始建立函數large_order,輸入一個貨幣參數,返回查詢訂單表
Create function large_order(@higher_than money)
Returns @order_table table/*定義返回數據表*/
(客戶名稱 char(255),產品名稱 varchar(10),定貨時間 datetime,總價 money)
AS
--下面開始定義查詢
Begin
insert @order_table
select 客戶數據表.公司名稱,產品數據表.產品名稱,訂單數據表.定貨日期,訂單數據表.定貨數量*產品數據表.單價
from 訂單數據表,客戶數據表,產品數據表
where 產品數據表.編號=訂單數據表.產品編號 and 訂單數據表.客戶編號=客戶數據表.編號
         and 訂單數據表.定貨數量*產品數據表.單價>@higher_than
Return
End
Go
--在查詢中調用該函數
select * from large_order(50000)
Go
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章