2013年5月8日 星期三

使用內建函式查詢

IsNull and Coalesce

  • ISNULL :以指定的取代值來取代 NULL。
  • COALESCE :傳回其引數中第一個非 Null 的運算式。

ISNULL 是用來判斷欄位的值,若為 NULL 的時候,可以回傳自己所要的值。 COALESCE 就像是 CASE WHEN 陳述式,會回傳引數中第一個非 Null 的運算式,如果所有引數都是 NULL, COALESCE 便會傳回 NULL。

ISNULL

declare @T table (id char(2), age decimal(3,1));
insert @T values ('01', 10.0);
insert @T values ('02', null);
insert @T values ('03', 15.0);

--總計函式會忽略Null欄位
select AVG(age) from @T             -- return 12.5

--若為 NULL 回傳 11
select AVG(isnull(age,11)) from @T  -- return 12

COALESCE

Coalesce :回傳引數中第一個非 Null 的運算式

declare @T table ( productid varchar(2), price1 int, price2 int, price3 int);

insert @T values ('01',10,11,12);
insert @T values ('02',null,11,12);
insert @T values ('03',null,null,12);
insert @T values ('04',10,null,12);
insert @T values ('05',null,null,null);

select productid , Coalesce(price1, price2, price3) from @T
select productid , Coalesce(price1, price2, price3, 15) from @T

日期時間函式

取得系統和日期時間

SELECT GetDate()			--datetime 
SELECT SysDateTime()		--datetime2
SELECT SysUtcDateTime()		--datetime2
SELECT SysDateTimeOFFSET()	--datetimeoffset
SELECT ToDateTimeOffset(SysDateTimeOFFSET(), '+02:00') 

較高精確度的日期時間

函式名稱說明備註
SYSDATETIME 取得主機上的時間傳回 datetime2(7) 型別
SYSDATETIMEOFFSET 取得主機上的時間傳回 datetimeoffset(7) 型別
SYSUTCDATETIME 取得即時的 UTC 時間傳回 datetime2(7) 型別
SELECT 'SysDateTime()', SysDateTime()

SELECT 'SysDateTimeOFFSET()', SysDateTimeOFFSET()

SELECT 'SysUtcDateTime()', SysUtcDateTime()

較低精確度的日期時間

函式名稱說明備註
GETDATE 取得主機上的時間傳回 datetime 型別
GETUTCDATE 取得即時的 UTC 時間傳回 datetime 型別
CURRENT_TIMESTAMP 取得主機上的時間同 GetDate() ,但這個不是參數型函式
SELECT 'GetDate()', GetDate()

SELECT 'GetUTCDate()', GetUTCDate()

SELECT 'CURRENT_TimeSTAMP', CURRENT_TimeSTAMP  -- 同 GetDate() ,但這個不是參數型函式

分解日期時間中的各個部份

  • DATEPART :取得日期時間欄位指定部份的值,回傳整數型別
  • DATENAME : 取得日期時間欄位指定部份的值,回傳字串型別
  • DAY
  • MONTH
  • YEAR

DATEPART 和 DateName 用法相同,只是回傳型態不同。它們都帶有一個 datepart 參數,這個參數可使用的值如下例:

SELECT DateName(YY,@Now) YY,    -- year
	   DateName(MM,@Now) MM,    -- month
	   DateName(DD,@Now) DD,    -- day
	   DateName(HH,@Now) HH,    -- hour
	   DateName(MI,@Now) MI,    -- minute
	   DateName(SS,@Now) SS,    -- second
	   DateName(MS,@Now) MS     -- millisecond
	   
SELECT DatePart(QQ,@Now) QQ,    -- quarter 本年度第幾季
	   DatePart(WK,@Now) WK,    -- week 本年度第幾週
	   DatePart(DY,@Now) DY,    -- dayofyear 本年度第幾天
	   DatePart(mcs,@Now) mcs,  -- microsecond
	   DatePart(ns,@Now) ns     -- nanosecond
	   
SELECT Year(@Now) YEAR, 
       Month(@Now) MONTH, 
       Day(@Now) DAY

日期時間的運算

常用的時間運算函式有:

  • DATEDIFF :Returns the count (signed integer) of the specified datepart boundaries crossed between the specified startdate and enddate.
  • DATEADD :Returns a specified date with the specified number interval (signed integer) added to a specified datepart of that date.
DATEADD (datepart , number , date )
    DATEDIFF ( datepart , startdate , enddate )

PS. 雖然在 DATENAME 函式中,若 datepart=dy ,是表示今年的天數,但是在 DATEDIFF 函式中是表示二個日期相差的天數, quarter和 week 也是如此。

DECLARE @Time1 DateTime = '2012-05-10 11:35:41';
DECLARE @Time2 DateTime = GetDate();
SELECT DateDiff(YY, @Time1, @Time2) Diff_YY, 
       DateDiff(MM, @Time1, @Time2) Diff_MM, 
	   DateDiff(DD, @Time1, @Time2) Diff_DD,
	   DateDiff(HH, @Time1, @Time2) Diff_DD,
	   DateDiff(MI, @Time1, @Time2) Diff_MI,
	   DateDiff(SS, @Time1, @Time2) Diff_SS,
	   DateDiff(MS, @Time1, @Time2) Diff_MS

SELECT DATEADD(YY, 1, @Time1),
	   DATEADD(QQ, 1, @Time1),
	   DATEADD(MM, 1, @Time1)
	   DATEADD(HH, 1, @Time1)

新版的 SQL 還增加了底下幾個函式:

  • EOMONTH :傳回指定日期的當月最後一天,回傳型別為 date。(SQL2012)
  • SWITCHOFFSET :依指定時間變換時間。(SQL2008)
  • TODATETIMEOFFSET :變更某個時間的時區值。(SQL2008)
--取得當月最後一天的日期
DECLARE @date DateTime = '2012-03-10 06:05:003'; 
SELECT EOMONTH ( @date, -1 )  AS 'Last Date in Previous Month';		-- 2012-02-29
SELECT EOMONTH ( @date )	  AS 'Last Date in This Month'			-- 2012-03-31
SELECT EOMONTH ( @date, 1 )   AS 'Last Date in Next Month';			-- 2012-04-30

DECLARE @Time2 datetimeoffset = '2012-05-10 06:05:03.00000 +8:00';

--將 Time2 由 +8:00 時區的時間轉換成 -04:00 時區的時間
SELECT SWITCHOFFSET(@Time2, '-04:00')	
-- Return: 2012-05-09 18:05:03.0000000 -04:00

--將 Time2 的時區值變更成 -04:00 時區值
SELECT ToDateTimeOffset(@Time2, '-04:00')	
-- Return: 2012-05-10 06:05:03.0000000 -04:00

建立 DateTime、Date、Time

以下6個函式都是 SQL2012 才有的支援:

函式名稱說明備註
TIMEFROMPARTS 建立時間傳回 time 型別
DATEFROMPARTS 建立日期傳回 date 型別
SMALLDATETIMEFROMPARTS 建立日期時間傳回 smalldatetime 型別
DATETIMEFROMPARTS 建立日期時間傳回 datetime 型別
DATETIME2FROMPARTS 建立日期時間傳回 datetime2 型別
DATETIMEOFFSETFROMPARTS 建立日期時間傳回 datetimeoffset 型別
TIMEFROMPARTS           ( hour, minute, seconds, fractions, precision )
DATEFROMPARTS           ( year, month, day )
SMALLDATETIMEFROMPARTS  ( year, month, day, hour, minute )
DATETIMEFROMPARTS       ( year, month, day, hour, minute, seconds, milliseconds )
DATETIME2FROMPARTS      ( year, month, day, hour, minute, seconds, fractions, precision )
DATETIMEOFFSETFROMPARTS ( year, month, day, hour, minute, seconds, fractions, hour_offset, minute_offset, precision )

其他與日期時間相關的函式

SET DATEFIRST

SELECT @@DATEFIRST

SET DATEFIRST 1

SET DATEFORMAT

設定系統如何解讀日期字串之年月日的順序。

格式有效的參數為: mdy、dmy、ymd、ydm、myd 和 dym 。

SET DATEFORMAT dmy;
DECLARE @date1 datetime = '31/12/2012 09:01:01';
SELECT @date1

SET DATEFORMAT ymd;
DECLARE @date2 datetime = '2012/12/31 09:01:01';
SELECT @date2

SET LANGUAGE

設定工作階段和系統訊息的語言環境

select @@LANGUAGE 

SET LANGUAGE 繁體中文
SET LANGUAGE us_english

sp_helplanguage 

字串函式

SQL2012 新功能

  • FORMAT :將數值或日期資料,轉換成指定格式的字串。(SQL2012)
  • CONCAT :傳回串連兩個以上之字串值的結果字串。

FORMAT

FORMAT 是用來將 date/time 或 number 型別的資料,轉換成具有文化特性格式的字串值。

日期類型的Format

傳回不同文化特性的日期格式

DECLARE @d DATETIME = '2011/12/31';

SELECT FORMAT ( @d, 'D', 'en-US' ) AS '美式'
      ,FORMAT ( @d, 'D', 'en-gb' ) AS '英式'
      ,FORMAT ( @d, 'D', 'de-de' ) AS '德式'
      ,FORMAT ( @d, 'D', 'zh-tw' ) AS '台式'; 

SELECT FORMAT ( @d, 'd', 'en-US' ) AS '美式(簡)'
      ,FORMAT ( @d, 'd', 'en-gb' ) AS '英式(簡)'
      ,FORMAT ( @d, 'd', 'de-de' ) AS '德式(簡)'
      ,FORMAT ( @d, 'd', 'zh-tw' ) AS '台式(簡)'; 

數值類型的Format

傳回不同格式的數值

declare @i money = 1.5491

SELECT @i as 'Original Format'
    ,FORMAT(@i, 'N', 'en-us') AS 'Number Format'
    ,FORMAT(@i, 'G', 'en-us') AS 'General Format'
    ,FORMAT(@i, 'C', 'en-us') AS 'Currency Format'

傳回自訂格式

SELECT 
	FORMAT(223939889,'(0#)-####-####') AS 'Phone Format',
	FORMAT(952123456,'0###-######') AS 'Mobil Format';

子字串和位置

declare @tmp varchar(50) = ' abcd bc d32ef ';

SELECT 
	SUBSTRING(@tmp, 1,3),	--abc
	LEFT(@tmp, 3),			--ab
	RIGHT(@tmp, 3),			--ef
	RTRIM(LTRIM(@tmp))		--abcd bc d32ef
	
SELECT 
	CHARINDEX('bc', @tmp),		--2
	CHARINDEX('g', @tmp),		--0
	PATINDEX('%bc%', @tmp),		--2
	PATINDEX('%[0-9]%', @tmp)	--10

SELECT 
    REPLICATE('abc',3),					--abcabcabc
    'a' + SPACE(2) + 'b',				--a  b
    REPLACE('abc123abc','123','xyz')	--abcxyzabc
DECLARE @d DATETIME = GETDATE();
SELECT 
	FORMAT( @d, 'dd/MM/yyyy', 'en-US' ) AS 'DateTime Result',   --27/09/2012       
	FORMAT(123456789,'###-##-####') AS 'Custom Number Result';  --123-45-6789

字串變換

-- 將 123.45 轉成六個位數的字元字串
-- 數字的小數點後部份會捨入到一個小數位數。
SELECT STR(123.45, 6, 1);	-- 123.5

字串長度

  • LEN :回傳字數 (number of characters)
  • DATALENGTH :回傳字元數 (number of bytes)
SELECT 
LEN('ABC'),LEN('ABC'),				--3,3
DATALENGTH('ABC'),DATALENGTH('ABC')	--3,6

如何在字串中反向找到特定字元的位置

使用 CharIndex 可以找到特定字元在字串中首次出現的位置,如果要由後面開始算呢?目前 SQL 內建函式好像沒有直接這樣的功能,不過可以利用以上的方法來取得。 假設有個字串「abc.def.xyz」,你要取得最後一個「.」的位置,你可以這麼做:

declare @temp varchar(100) = 'abc.def.xyz'

select LEN(@temp) - CHARINDEX('.', REVERSE(@temp))

數學函式

算術函式

  • ROUND :捨入到指定的長度或有效位數。 (指定有效位數,以下四捨五入)
  • FLOOR :傳回小於或等於指定數值運算式的最大整數。 (取整數,無條件捨去小數)
  • CEILING :傳回大於或等於指定數值運算式的最小整數。 (取整數,小數無條件進位)
  • ABS :絕對值
  • SQRT :求平方根
  • SQUARE :求平方數
  • SIGN :判斷正或負,負數值回傳-1,零值回傳0,正數值回傳1。
  • POWER :傳回指定乘冪之指定運算式的值,例 Power(2,3) = 23
  • PI :傳回 PI 的常數值

若要求除法後的整數和餘數,沒有函式,可以直接使用 / 和 % 運算

select 11/3     -return 3
select 11 % 3   -return 2

ROUND

對數值欄位指定有效位數,以進行四捨五入計算

ROUND ( numeric_expression , length [ ,function ] )   //length : 取到小數第幾位,若為負值,表示取到整數第幾位

範例1:

select ROUND(123.9994, 3)	--123.9990 
select ROUND(123.9995, 3)	--124.0000 
select ROUND(123.4545, 2)	--123.4500 
select ROUND(123.4545, -2)	--100.0000
select ROUND(748.58, -1)	--750.00 
select ROUND(748.58, -2)	--700.00 
select ROUND(748.58, -3)	--1000.00 執行批次時發生錯誤。錯誤訊息為: 算術溢位。
select ROUND(748.58, -4)	--0 

範例2:

假設資料庫中以下數字 {10.5, 12, 3.7, 1, 3, 9, 13.5},型別為NUMBER(5,2),要如何找出帶小數的值 {10.5, 3.7, 13.5}?
1.轉字串後,再判斷字串含不含 dot
2.執行 mod 1 後,判斷含不含餘數
3.使用 ROUND => (VALUE - ROUND(VALUE,0)) <> 0

三角或指數函式

  • SIN :三角正弦函式 (Sine)
  • COS :三角餘弦函式 (CoSine)
  • TAN :三角正切函式 (Tangent)
  • COT :三角餘切函式 (CoTangent)
  • ASIN :反正弦函式 (ArcSine)
  • ACOS :反餘弦函式 (ArcCosine)
  • ATAN :反正切函式 (ArcTangent)。
  • DEGREES :以弧度換算對應的角度(θ)
  • RADIANS :以角度換算對應的弧度(rad)
  • LOG10 :以 10 為基底的對數。
  • LOG :自然對數,以 e 為基底的對數,其中 e 是大約等於 2.718281828 的無理常數。Log(10) ≒ 2.3
  • EXP :自然指數,以 e 為基底的指數。Exp(3) = e3 ≒ 20.0855

角度與弧度

亂數函式

  • RAND :傳回 0 到 1 (不含) 的虛擬隨機(pseudo-random) float 值。

邏輯函數

IsNull

ISNULL ( para1 , para2 )

若 para1 為 NULL,則回傳 para2

DECLARE @x int = 10, @y int = null
SELECT ISNULL ( @x , 0 )        --10
SELECT ISNULL ( @y , 0 )        --0

NullIf

NULLIF ( expression1 , expression2 )

NULLIF 接受二個表示式,若 exp1=exp2 則回傳 NULL,否則回傳 exp1 。

declare @a int;
declare @b int;
set @a=2; 
set @b=2;
select NULLIF(@a, @b)	--NULL

set @a=2; 
set @b=3;
select NULLIF(@a, @b)	--2

IIF

IIF 函式為 SQL2010 新功能,判斷運算式的真偽。

IIF ( boolean_expression, true_value, false_value )
  • true_value 及 false_value 可以是任何類型。
  • true_value 及 false_value 也可以是 null ,但是不能同時都為 null 。
  • 若 boolean_expression 錯誤,則函式會中斷。
DECLARE @a int = 45, @b int = 30;
SELECT IIF ( @a > @b, 'TRUE', 'FALSE' ) AS Result;              -- return TRUE
SELECT IIF ( @a > @b, 1, 0 ) AS Result;                         -- return 1

DECLARE @x int = 45, @y varchar(2) = '0';
SELECT IIF ( @x > @y, 'TRUE', 'FALSE' ) AS Result;              -- return TRUE
SELECT IIF ( @x / @y > 0 , 'TRUE', 'FALSE' ) AS Result;         -- error 

CHOOSE

CHOOSE 函式為 SQL2010 新功能,從數值清單傳回指定之索引的項目。

CHOOSE ( index, val_1, val_2 [, val_n ] )
SELECT CHOOSE ( 3, 'Manager', 'Director', 'Developer', 'Tester' ) AS Result;
--return: Developer

SELECT Gender, CHOOSE ( Gender, '男', '女') as Expression1 FROM Employees
Gender   Expression1
-------- ----
  1      男
  2      女

CASE ... WHEN

CASE ... WHEN有二種使用方式

simple form

這個格式比較簡單,指定固定欄位當做比較式的來源。

SELECT ProductID, ProductName,
	CASE Discontinued
		WHEN 0 THEN 'No'
		WHEN 1 THEN 'Yes'
		ELSE 'Unknow'
	END as Discontinued
FROM Products

searched form

這個格式比較彈性,因為比較式不限定同一個欄位。

SELECT ProductID, ProductName,
	CASE 
		WHEN Discontinued=0 THEN 'No'
		WHEN Discontinued=1 THEN 'Yes'
		ELSE 'Unknow'
	END as Discontinued
FROM Products

系統函式

以下幾個也是常用的內建函式或是系統變數:

型別轉換函式

  • CAST :轉換運算式的資料類型。
  • CONVERT :轉換運算式的資料類型。
CAST ( expression as data_type )
CONVERT ( data_type , expression [ , style ] )

底下為幾個較常用的 style :

style輸出格式說明
2碼4碼
0或100mon dd yyyy hh:miAM(PM)預設
1 101mm/dd/yyyy美式
2 102yyyy.mm.ddANSI
3 103dd/mm/yyyy 英式
8 108hh:mi:ss
11111yyyy/mm/dd日式
12112yyyymmdd ISO
DECLARE @Time1 DateTime = '2012-05-10 06:05:003';

SELECT 
CAST( @Time1 as varchar(10) ),	--05 10 2012
CAST( @Time1 as varchar(15) ),	--05 10 2012  6:0
CAST( @Time1 as varchar(18) )	--05 10 2012  6:05AM

SELECT 
CONVERT( varchar(18), @Time1, 0 ),		--05 10 2012  6:05AM
CONVERT( varchar(18), @Time1, 101 ),	--05/10/2012
CONVERT( varchar(18), @Time1, 102 ),	--2012.05.10
CONVERT( varchar(18), @Time1, 103 ),	--10/05/2012
CONVERT( varchar(18), @Time1, 108 ),	--06:05:03
CONVERT( varchar(18), @Time1, 111 ),	--2012/05/10
CONVERT( varchar(18), @Time1, 112 )		--20120510

執行結果回應函式

  • @@ERROR :傳回最後執行之 Transact-SQL 陳述式的錯誤號碼。
  • @@TRANCOUNT :Returns the number of BEGIN TRANSACTION statements that have occurred on the current connection.
  • @@ROWCOUNT :傳回受到前一個陳述式所影響的資料列數。

中繼資料函式(Metadata Functions)

SELECT DB_ID('test')		--19
SELECT DB_NAME(19)			--test

SELECT OBJECT_ID('tblUser')		--713821655
SELECT OBJECT_NAME(713821655)	--tblUser

--取得tblUser的所有欄位名稱
SELECT * FROM sys.columns  where OBJECT_ID = 713821655

--由 tableid+columnid 取得欄位名稱
SELECT COL_NAME (713821655,1)	--UserID

目錄檢視(Catalog Views )

下列內建的檢視(View)可以用來查詢各類別的物件資訊。

沒有留言:

張貼留言