顯示具有 [(19).特殊排序]特殊排序 標籤的文章。 顯示所有文章
顯示具有 [(19).特殊排序]特殊排序 標籤的文章。 顯示所有文章

2013年9月25日 星期三

中文排序 (筆劃、部首、拼音)


全球眾多語系,對於排序順序可能因習慣、文化等因素而有所差異,中文常用之排序方法有筆劃、部首、拼音(或注音)等,以下範例列出兩種資料庫中文排序方法。

1.  環境
MSSQL可於伺服器(Server)、資料庫(Database)、資料行(Column)及運算式(Expression)等四個層級進行定序(Collation)設定,ORDEER BY子句是針對特定欄位(群)進行排序,因此須確知排序欄位之定序;ORACLE則支援資料庫及運算式兩種定序設定模式,因此確知資料庫層級之定序設定。MSSQLORACLE查詢指定及結果如下表所示:
#
MSSQL
執行結果
MSSQL
SELECT T.name   Tbl_Name
     , C.name    Col_Name
     , C.collation_name
FROM sys.columns C, sys.tables T
WHERE 1=1
AND T.OBJECT_ID= C.OBJECT_ID
AND T.name = 'CHNTest' --Tbl Name
AND C.name = 'CHN'   --Col Name


ORACLE
SELECT *
FROM v$nls_parameters




2.  中文排序方法
先以中文常用筆劃(Stroke)排序為範例,說明兩種資料庫排序語法,後續再針對兩種資料庫特有排序方法進行說明,SQL及執行結果如下: 
資料庫
SQL
說明
MSSQL
SELECT CHN
FROM CHNTest
ORDER BY CHN COLLATE chinese_taiwan_stroke_cs_as_ks_ws
指定欄位定序為chinese_taiwan_stroke_cs_as_ks_ws
ORACLE
SELECT CHN    
FROM CHNTest
ORDER BY nlssort(CHN,'NLS_SORT=TCHINESE_STROKE_M')
nlssort函數進行轉換

執行結果:(相同)










ORACLE
9i起,針對中文語言方式(Simplified ChineseTraditional Chinese)提供了5種排序方式。如下:
Sort Name
Description
SCHINESE_RADICAL_M
Simplified Chinese sort based on radical as primary order and number of strokes order as secondary order
簡體中文,按照部首(第1順序)、筆劃(第2順序)排序
SCHINESE_STROKE_M
Simplified Chinese sort uses number of strokes as primary order and radical as secondary order
簡體中文,按照筆劃(第1順序)、部首(第二2序)排序
SCHINESE_PINYIN_M
Simplified Chinese PinYin sorting order
簡體中文,按照拼音排序
TCHINESE_RADICAL_M
Traditional Chinese sort based on radical as primary order and number of strokes order as secondary order
正體中文,按照部首(第1順序)、筆劃(第2順序)排序
TCHINESE_STROKE_M
Traditional Chinese sort uses number of strokes as primary order and radical as secondary order. It supports supplementary characters.
正體中文,按照筆劃(第1順序)、部首(第2順序)排序

將先前之測試資料,以本測試環預設之BINARY、筆劃(Stroke)、部首(Radical)及簡中-拼音(Pinyin)共四種方法排序,將進行ROW TO COLUMN轉置以清楚呈現排序結果,後續再探討ROW TO COLUMN概念及作法,無法理解者,可執行中間局部SQLSQL及結果如下。
SELECT SEQ
, MAX(CASE  WHEN SEQ = DFT     THEN CHN END) BINARY
     , MAX(CASE  WHEN SEQ = STROKE  THEN CHN END) STROKE
     , MAX(CASE  WHEN SEQ = RADICAL THEN CHN END) RADICAL
     , MAX(CASE  WHEN SEQ = PINYIN  THEN CHN END) PINYIN       
FROM
  (
   SELECT CHN, DFT, STROKE, RADICAL, PINYIN, SEQ
   FROM
     (
SELECT CHN
  , ROW_NUMBER() OVER (ORDER BY CHN) DFT
  , ROW_NUMBER() OVER (ORDER BY nlssort(CHN,'NLS_SORT=TCHINESE_STROKE_M'))  STROKE
  , ROW_NUMBER() OVER (ORDER BY nlssort(CHN,'NLS_SORT=TCHINESE_RADICAL_M')) RADICAL
  , ROW_NUMBER() OVER (ORDER BY nlssort(CHN,'NLS_SORT=SCHINESE_PINYIN_M'))  PINYIN
FROM CHNTest
     ) A ,
     (
     SELECT LEVEL SEQ
     FROM DUAL
     CONNECT BY LEVEL <=6
     ) N
 )
GROUP BY SEQ










上面測試結果中,BINARY及筆劃排序恰巧相同,此為特例不代表兩者相同,測試時曾發現兩者不同之組合,針對三種方法整理如下:
l   筆劃(Stroke
按照筆劃(第1順序)、部首(第2順序)排序,其中『何』、『杜』筆劃相同,則按部首排序,分別為『人』及『木』。
l   部首(Radical
按照部首(第1順序)、筆劃(第2順序)排序。
l   拼音(Pinyin
按照簡中-拼音(非注音)進行排序,簡中版本僅供參考。

MSSQL
選項
說明
Case sensitivity (CS)
區分大小寫,如Aa視為不同。Case Insensitive(CI)不區分大小寫。
Accent sensitivity (AS)
區分腔調字,如 'a' 不等於 'ấ'Accent Insensitive(AI)則否。
Kana Sensitivity (KS)
區分兩種日文的假名字元Kana Insensitive(KI)則否。
Width sensitivity (WS)
區分全半形 ,如A、A視為不同。Width Insensitive(WI)則視為相同。

以下將列出筆劃(Stroke)及注音(bopomofo)兩種排序方法,SQL及結果如下:
SELECT CHN
     , ROW_NUMBER() OVER (ORDER BY CHN) DFT
     , ROW_NUMBER() OVER (ORDER BY CHN COLLATE Chinese_Taiwan_bopomofo_CS_AS)     bopomofo
     , ROW_NUMBER() OVER (ORDER BY CHN COLLATE chinese_taiwan_stroke_cs_as_ks_ws) Stroke
FROM  CHNTest

結果











MSSQL為支援不同語系而提供為數眾多定序定義,定序可直接由『::fn_helpcollations()』得知定義及說明,SQL如下:
SELECT *
FROM ::fn_helpcollations()
WHERE 1=1
AND name like 'chinese_taiwan%'
AND CHARINDEX('90', name) =0

2013年9月22日 星期日

集合(SET)運算中使用排序注意事項

集合(SET)指令的目的是將兩個(含以上)SQL指令所產生的結果合併起來,由於是將兩個(含以上)的資料集進行合併,因此操作上些許限制,如在資料欄位數量上必需相等型態上則需必需相容,在排序上也與單一查詢資料集有些許不同。

一般查詢情況下,排序在除可依據資料表之欄位名稱外,尚有SELECT清單位置(Postition)、運算式(expression : expr)及欄位/運算式別名(Alias)等方法,ORDER BY所參照之欄位並非限定存在於SELECT 清單中,但SELECT DISTINCT則除外。而集合運算(SET)如需使用運算式(expression: expr)進行排序時,則此運算式必須存在於SELECT清單中,後續將進行數項測試以說明此限制條件。

以下針對單一及集合運算進行測試,單一查詢可順利執行,如預期A30排於第1位,而集合運算MSSQLORACLE兩者均發生錯誤,SQL及執行結果如下所示:
#
SQL/結果
執行結果
一般SQL
(可執行)
SELECT VAL
FROM Test
WHERE 1=1
      AND VAL LIKE 'A%'     
ORDER BY CASE WHEN VAL ='A30' THEN '000' ELSE VAL END
--ORDER BY VAL -- Column Name / Alias
--ORDER BY 1   -- Column Position

集合運算
(錯誤)
SELECT VAL
  --, CASE WHEN VAL ='A38' THEN '000' ELSE VAL END
FROM Test
WHERE 1=1
      AND VAL LIKE 'A%'
UNION ALL
SELECT VAL
  --, CASE WHEN VAL ='A38' THEN '000' ELSE VAL END
FROM Test
WHERE 1=1
      AND VAL LIKE 'B%'
ORDER BY CASE WHEN VAL ='A30' THEN '000' ELSE VAL END
ü  MSSQL
Msg 104, Level 16, State 1, Line 12
ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.

ü  ORACLE
ORA-01785: ORDER BY item must be the number of a SELECT-list expression
MSSQL
訊息104,層級16,狀態1,行14
如果陳述式中包含UNIONINTERSECT EXCEPT 運算子,則選取清單中必須有ORDER BY 項目。
ORACLE
ORA-01785: ORDER BY 項目必須是 SELECT-list 表示式中的數字

MSSQL錯誤訊息,可清楚得知在集合運算中採用排序指令ORDER BY 時,其中必須存在(出現)於SELECT清單中,但由ORACLE的錯誤訊息則較以理解其原由。

以下進行3種測試,分析說明兩種資料庫之差異:
#
SQL/結果
執行結果
1
運算式(expression: expr
SELECT VAL
  , CASE WHEN VAL ='A38' THEN '000' ELSE VAL END
FROM Test
WHERE 1=1
      AND VAL LIKE 'A%'
UNION ALL
SELECT VAL
  , CASE WHEN VAL ='A38' THEN '000' ELSE VAL END
FROM Test
WHERE 1=1
      AND VAL LIKE 'B%'
ORDER BY CASE WHEN VAL ='A38' THEN '000' ELSE VAL END --測試1
ü  MSSQL(可執行)

ü  ORACLE錯誤
ORA-01785: ORDER BY item must be the number of a SELECT-list
2
運算/欄位別名(Alias
SELECT VAL
       , CASE WHEN VAL ='A38' THEN '000' ELSE VAL END Col
FROM Test
WHERE 1=1
      AND VAL LIKE 'A%'
UNION ALL
SELECT VAL
     , CASE WHEN VAL ='A38' THEN '000' ELSE VAL END
FROM Test
WHERE 1=1
      AND VAL LIKE 'B%'
ORDER BY Col --測試2
MSSQL/ORACLE(可執行)

3
SELECT清單位置Position
SELECT VAL --位置1
     , CASE WHEN VAL ='A38' THEN '000' ELSE VAL END Col --位置2
FROM Test
WHERE 1=1
      AND VAL LIKE 'A%'
UNION ALL
SELECT VAL
       , CASE WHEN VAL ='A38' THEN '000' ELSE VAL END
FROM Test
WHERE 1=1
      AND VAL LIKE 'B%'
ORDER BY 2 --測試3
MSSQL/ORACLE(可執行)

由測試23可得知,集合運算(SET)中排序以運算/欄位別名(Alias)或SELECT清單位置(Position)兩種資料庫均可順利執行;但對於由測試1中的排序直接使用運算式(expression: expr)則兩者不同,MSSQL仍支援,但ORACLE發生如同先前之ORA-01785: ORDER BY item must be the number of a SELECT-list expression錯誤。

集合運算(SET)如需使用運算式(expression: expr)排序時,則此運算式必須存在於SELECT清單中,MSSQL可如同一般查詢之排序,可於ORDER BY子句中使用運算式、運算欄位別名及運算欄位位置等3種方法,而ORACLE只可使用運算欄位別名及運算欄位位置等2種方法。

資料產生(ORALCE為例,MSSQL改以INTO Test)
CREATE TABLE Test
AS
SELECT 'A42' VAL
FROM DUAL
UNION ALL
SELECT 'A30'
FROM DUAL
UNION ALL
SELECT 'A28'
FROM DUAL
UNION ALL
SELECT 'B26'
FROM DUAL
UNION ALL
SELECT 'B90'
FROM DUAL