2013年8月30日 星期五

如何在無任何適當ORDER BY欄位情況下,使用ROW_NUMBER函數

ROW_NUMBER()函數將賦予各資料分割結果集中,每一筆資料一個1開始至N遞增的整數值Integer。常應用於產生逐筆序號,以供各項特殊需求使用,語法如下:
ROW_NUMBER()
           OVER ([PARTITION BY ] ORDER BY <order by clause>)
l  <patition by clause>:資料群組(選擇參數)
類似GROUP BY概念,將資料區分割成數個群組,相同群組將一同處理
l  <order by clause>:排序(必要參數
指定資料群組中資料的排序方式

<order by clause>ROW_NUMBER語法之必要參數,當使用此函數時必需提供才可執行,但許多情況下並無任何適當欄位資料可用(或產生非預期之序號),對MSSQL可使用系統時間GETDATE()函數,而ORACLE則可使用SYSDATENULL、常數等三種方法,即可克服此問題。將以四季為範例,即春天(1)、夏天(2)、秋天(3)及冬天(4)依季別產生其對應序號,語法及說明如下

SQL
說明
MSSQL
SELECT *
, ROW_NUMBER() OVER(ORDER BY GETDATE()) Seq--T1
--, ROW_NUMBER() OVER(ORDER BY NULL) Seq2  --T2
--, ROW_NUMBER() OVER(ORDER BY 1) Seq3     --T3
FROM   
  (VALUES ('Spring', '春天')
         , ('Summer', '夏天')
         , ('Autumn', '秋天')
         , ('Winter', '冬天')
   ) AS Seasons(Season, Disp)
ü  T1GETDATE()函數-可用
ü  T2: NULL-不可用
Windowed functions do not support constants as ORDER BY clause expressions.
ü  T31(常數)-不可用
Windowed functions do not support integer indices as ORDER BY clause expressions.
ORACLE
SELECT A.*
   , ROW_NUMBER() OVER(ORDER BY SYSDATE) Seq 
   , ROW_NUMBER() OVER(ORDER BY NULL)     Seq2
   , ROW_NUMBER() OVER(ORDER BY 1)        Seq3      
FROM
     (
      SELECT 'Spring' Season, '春天' Disp
      FROM DUAL
      UNION ALL
      SELECT 'Summer', '夏天'
      FROM DUAL
      UNION ALL
      SELECT 'Autumn', '秋天'
      FROM DUAL
      UNION ALL
      SELECT 'Winter', '冬天'
      FROM DUAL
     ) A
SYSDATE函數、NULL1(常數)均可使用。

執行結果:

[2008] VALUES增強功能(Table Value Constructor)

VALUES關鍵字常見應用於INSERT指令上,以指定(暫存)將存入資料表之資料,MSSQL 2008版本起增強VALUES之功能及應用範圍,先前版本僅支援一筆資料之操作,此版本起開始支援多筆模式,可INSERT字句中同時指定存入多筆資料,並擴大應用範圍於SELECTUPDATEDELETEMERGE INTO等語法中使用,資料庫VALUES關鍵字所列舉之資料列產生並暫存於虛擬資料表中,提供後續INSERTSELECT(或相關)等參照使用

下表整理出可能之應用情境,過去多筆資料上之應用常需搭配UNION ALL語法產生或組合所需,2008版本則可用VALUES功能達成所需。
功能
SQL2008以下版本
SQL2008版本
Insert 1
INSERT … VALUES
INSERT … VALUES
Insert 多筆
INSERT … SELECT [UNION ALL]
INSERT … VALUES
暫存資料
SELECT [COLUMN LIST]
UNION ALL
SELECT [COLUMN LIST]
VALUES

前後版本對應語法及說明,整理列於下表:
功能
SQL2008以下
SQL2008()以上
用途/說明
Insert All
INSERT INTO #Seasons
(Season, Disp)
SELECT 'Spring', '春天'
UNION ALL
SELECT 'Summer', '夏天'
UNION ALL
SELECT 'Autumn', '秋天'
UNION ALL
SELECT 'Winter', '冬天'
INSERT INTO #Seasons
VALUES ('Spring', '春天')
      , ('Summer', '夏天')
      , ('Autumn', '秋天')
      , ('Winter', '冬天');
DML指令中同時INSERT多筆資料。

測試前需建立#Seasons
CREATE TABLE #Seasons
(
Season   varchar(20),
Disp     varchar(20)
);
Temp Table
SELECT 'Spring' Season
, '春天' Disp
UNION ALL
SELECT 'Summer', '夏天'
UNION ALL
SELECT 'Autumn', '秋天'
UNION ALL
SELECT 'Winter', '冬天'
SELECT *
FROM    
  (VALUES ('Spring', '春天')
         , ('Summer', '夏天')
         , ('Autumn', '秋天')
         , ('Winter', '冬天')
   ) AS Seasons(Season, Disp)
ORDER BY Disp
VALUES產生暫存資料表。

2013年8月29日 星期四

日期函數

本文僅列出常用函數,將於其他文章中進行分析與比較。
#
功能
SQL SERVER
ORACLE
說明
1
系統時間
GETDATE()
SYSDATE
取得系統時間
2
日期加減運算
(日期提前延後)
DATEADD
+/-
ADD_MONTHS
S: DATEADD提供各種日期格式的加減運算。
O: ADD_MONTHS為月
3
兩日期的差距
(時間差)
DATEDIFF
DATEDIFF_BIG
-
MONTHS_BETWEEN
取得兩個日期的差距。
O: 通常可將日期直接相減(-)即可,月份差則可使用MONTHS_BETWEEN
4
部分日期資訊
(格式轉換)
DATENAME DATEPART
DAY
MONTH
YEAR
FORMAT (2012)
EXTRACT
取得日期型態中之年、月、日等部分日期資訊
MSSQL2012所提供FORMAT函數支援類似C#格式化功能。
5
日期截斷
(格式轉換)
CONVERT
CAST
ROUND
TRUNC
指定截斷格式將捨去所指定日期單位以下資訊
6
月底日期
EOMONTH (2012)
LAST_DAY
取得指定日期的月底日期
7
N/A
NEXT_DAY
取得下一個週幾』的日期
常用於期貨轉倉日計算或非標準週合計使用
8
日期比較
N/A
GREATEST
LEAST
可用於多個日期比較使用
LEAST(d1., d2, .. dn)取得最早(小)日期GREATEST最晚 ()日期

1.           格式轉換函數
資料庫
 函數
語法
ORACLE
TO_CHAR(date [, 'format' [, nls_language]])
MSSQL2012
FORMAT (date, 'format' [, culture ] )
MSSQL
CONVERT

MSSQL2012提供相當簡便/彈性的FORMAT函數,可藉由指定格式化字串及CULTURE幾乎可滿足大部份需求,強建議採用,可參考[2012] 格式化函數FORMAT介紹》所述。ORACLE則可使用TO_CHAR函數,一樣藉由指定格式化字串及nls_language即可,可參考格式轉換函數(日期/文字)

2.         下一個週幾
常應用於期貨轉倉日計算(台指期為每月第三個週三:三週三),或者半導體因四二輪作業及撰寫檢討週報所需以切週五早上0700為切點,以上兩種需求可參考取得下一個週五的日期