【序文】
日本語の並び順の問題に関する考察。
【環境】
SQLServer | SQLCMD |
---|---|
2017 | 14.0.1000.169 |
設定はデフォルト。 | |
但しコマンドプロンプトのコードページは 65001。 |
【よくある問題】
以下のような部署名が格納されたテーブルがあったとする。
部署名 |
---|
第一営業部 |
第二営業部 |
第三営業部 |
部署名でソートした結果が以下。
1> SELECT [Value] FROM STRING_SPLIT(N'第一営業部,第二営業部,第三営業部', N',') ORDER BY [Value];
2> GO
Value
-----------------
第一営業部
第三営業部
第二営業部
(3 行処理されました)
これは期待した結果ではない。というかこれは文字コードの問題であり SQLServer、DB の問題ではない。
しかし、DB での実装でしばしば問題になるテーマなので取り上げてみた。
【解決策】
単純に表示順を持たせる方法が一般的だろう。
表示順 | 部署名 |
---|---|
1 | 第一営業部 |
2 | 第二営業部 |
3 | 第三営業部 |
クエリでは、表示順列でソートすると。
もしクエリ側だけで無理やり何とかするなら以下。
1> SELECT [Value] [部署名] FROM STRING_SPLIT(N'第一営業部,第二営業部,第三営業部', N',')
2> ORDER BY REPLACE(REPLACE(REPLACE([Value], N'一', N'1'), N'二', N'2'), N'三', N'3')
3> ;
4> GO
部署名
-----------------
第一営業部
第二営業部
第三営業部
(3 行処理されました)
酷い方法である。しかし開発の現場では、こんな付け焼刃的なコードがゴロゴロしているという……。
【余談】
そもそも漢数字の並び順ってどうなっているんだろう? というのが最初のきっかけだった。
1> SELECT [Value] FROM STRING_SPLIT(N'〇,一,二,三,四,五,六,七,八,九,十', N',') ORDER BY [Value];
2> GO
Value
---------------------
〇
一
九
五
三
四
七
十
二
八
六
(11 行処理されました)
滅茶苦茶。大字は?
1> SELECT [Value] FROM STRING_SPLIT(N'零,壱,弐,参,肆,伍,陸,漆,捌,玖,拾', N',') ORDER BY [Value];
2> GO
Value
---------------------
壱
玖
伍
捌
参
漆
拾
弐
陸
零
肆
(11 行処理されました)
そもそも漢字って読み仮名順が基本だっけ? 簡単に言えば、あいうえお順。慣用的な並び順になる訳ない。
しかし、英語圏でも使われるであろうローマ数字や丸数字だとまともなんだよな。そういえばローマ数字ってゼロがないんだね。
1> SELECT [Value] FROM STRING_SPLIT(N'Ⅰ,Ⅱ,Ⅲ,Ⅳ,Ⅴ,Ⅵ,Ⅶ,Ⅷ,Ⅸ,Ⅹ', N',') ORDER BY [Value];
2> GO
Value
-------------------
Ⅰ
Ⅱ
Ⅲ
Ⅳ
Ⅴ
Ⅵ
Ⅶ
Ⅷ
Ⅸ
Ⅹ
(10 行処理されました)
1> SELECT [Value] FROM STRING_SPLIT(N'⓪,①,②,③,④,⑤,⑥,⑦,⑧,⑨,⑩,⑪,⑫,⑬,⑭,⑮,⑯,⑰,⑱,⑲,⑳', N',') ORDER BY [Value];
2> GO
Value
-----------------------------------------
⓪
①
②
③
④
⑤
⑥
⑦
⑧
⑨
⑩
⑪
⑫
⑬
⑭
⑮
⑯
⑰
⑱
⑲
⑳
(21 行処理されました)
同様の流れで。
1> SELECT [Value] FROM STRING_SPLIT(N'❶,❷,❸,❹,❺,❻,❼,❽,❾,❿', N',') ORDER BY [Value];
2> SELECT [Value] FROM STRING_SPLIT(N'Ⓐ,Ⓑ,Ⓒ,Ⓓ,Ⓔ,Ⓕ,Ⓖ,Ⓗ,Ⓘ,Ⓙ,Ⓚ,Ⓛ,Ⓜ,Ⓝ,Ⓞ,Ⓟ,Ⓠ,Ⓡ,Ⓢ,Ⓣ,Ⓤ,Ⓥ,Ⓦ,Ⓧ,Ⓨ,Ⓩ', N',') ORDER BY [Value];
3> SELECT [Value] FROM STRING_SPLIT(N'ⓐ,ⓑ,ⓒ,ⓓ,ⓔ,ⓕ,ⓖ,ⓗ,ⓘ,ⓙ,ⓚ,ⓛ,ⓜ,ⓝ,ⓞ,ⓟ,ⓠ,ⓡ,ⓢ,ⓣ,ⓤ,ⓥ,ⓦ,ⓧ,ⓨ,ⓩ', N',') ORDER BY [Value];
4> SELECT [Value] FROM STRING_SPLIT(N'⑴,⑵,⑶,⑷,⑸,⑹,⑺,⑻,⑼,⑽,⑾,⑿,⒀,⒁,⒂,⒃,⒄,⒅,⒆,⒇', N',') ORDER BY [Value];
5> SELECT [Value] FROM STRING_SPLIT(N'⒜,⒝,⒞,⒟,⒠,⒡,⒢,⒣,⒤,⒥,⒦,⒧,⒨,⒩,⒪,⒫,⒬,⒭,⒮,⒯,⒰,⒱,⒲,⒳,⒴,⒵', N',') ORDER BY [Value];
6> SELECT [Value] FROM STRING_SPLIT(N'⒈,⒉,⒊,⒋,⒌,⒍,⒎,⒏,⒐,⒑,⒒,⒓,⒔,⒕,⒖,⒗,⒘,⒙,⒚,⒛', N',') ORDER BY [Value];
7> GO
Value
-------------------
❶
❷
❸
❹
❺
❻
❼
❽
❾
❿
(10 行処理されました)
Value
---------------------------------------------------
Ⓐ
Ⓑ
Ⓒ
Ⓓ
Ⓔ
Ⓕ
Ⓖ
Ⓗ
Ⓘ
Ⓙ
Ⓚ
Ⓛ
Ⓜ
Ⓝ
Ⓞ
Ⓟ
Ⓠ
Ⓡ
Ⓢ
Ⓣ
Ⓤ
Ⓥ
Ⓦ
Ⓧ
Ⓨ
Ⓩ
(26 行処理されました)
Value
---------------------------------------------------
ⓐ
ⓑ
ⓒ
ⓓ
ⓔ
ⓕ
ⓖ
ⓗ
ⓘ
ⓙ
ⓚ
ⓛ
ⓜ
ⓝ
ⓞ
ⓟ
ⓠ
ⓡ
ⓢ
ⓣ
ⓤ
ⓥ
ⓦ
ⓧ
ⓨ
ⓩ
(26 行処理されました)
Value
---------------------------------------
⑴
⑵
⑶
⑷
⑸
⑹
⑺
⑻
⑼
⑽
⑾
⑿
⒀
⒁
⒂
⒃
⒄
⒅
⒆
⒇
(20 行処理されました)
Value
---------------------------------------------------
⒜
⒝
⒞
⒟
⒠
⒡
⒢
⒣
⒤
⒥
⒦
⒧
⒨
⒩
⒪
⒫
⒬
⒭
⒮
⒯
⒰
⒱
⒲
⒳
⒴
⒵
(26 行処理されました)
Value
---------------------------------------
⒈
⒉
⒊
⒋
⒌
⒍
⒎
⒏
⒐
⒑
⒒
⒓
⒔
⒕
⒖
⒗
⒘
⒙
⒚
⒛
(20 行処理されました)
これらの文字は以下を使わせていただいた。多謝。
入力しづらい丸英数字のメモ
再び漢字に戻る。
手当たり次第確認してみる。
1> SELECT [Value] FROM STRING_SPLIT(N'一,万,億,兆,京,垓,?穣,溝,澗,正,載,極', N',') ORDER BY [Value];
2> GO
Value
-------------------------
�
一
億
澗
京
極
溝
載
穣
正
兆
万
垓
(13 行処理されました)
因みに本来入力したクエリは以下。
𥝱
はサロゲートペア文字みたいでコマンドプロンプト上では扱えない。うーむ。サロゲートペア入門:CodeZine(コードジン) によれば U+25771
らしい。だから何だって話だけど。
SELECT [Value] FROM STRING_SPLIT(N'一,万,億,兆,京,垓,𥝱,穣,溝,澗,正,載,極', N',') ORDER BY [Value];
GO
引き続き思いつくままに。
1> SELECT [Value] FROM STRING_SPLIT(N'小,中,高,大', N',') ORDER BY [Value];
2> SELECT [Value] FROM STRING_SPLIT(N'起,承,転,結', N',') ORDER BY [Value];
3> GO
Value
-------
高
小
大
中
(4 行処理されました)
Value
-------
起
結
承
転
(4 行処理されました)
1> SELECT [Value] FROM STRING_SPLIT(N'春,夏,秋,冬', N',') ORDER BY [Value];
2> SELECT [Value] FROM STRING_SPLIT(N'都,道,府,県', N',') ORDER BY [Value];
3> GO
Value
-------
夏
秋
春
冬
(4 行処理されました)
Value
-------
県
都
道
府
(4 行処理されました)
惜しい。> 加減乗除
1> SELECT [Value] FROM STRING_SPLIT(N'市,区,町,村', N',') ORDER BY [Value];
2> SELECT [Value] FROM STRING_SPLIT(N'加,減,乗,除', N',') ORDER BY [Value];
3> GO
Value
-------
区
市
村
町
(4 行処理されました)
Value
-------
加
減
除
乗
(4 行処理されました)
1> SELECT [Value] FROM STRING_SPLIT(N'甲,乙,丙,丁', N',') ORDER BY [Value];
2> SELECT [Value] FROM STRING_SPLIT(N'士,農,工,商', N',') ORDER BY [Value];
3> GO
Value
-------
乙
甲
丁
丙
(4 行処理されました)
Value
-------
工
士
商
農
(4 行処理されました)
1> SELECT [Value] FROM STRING_SPLIT(N'子,丑,寅,卯,辰,巳,午,未,申,酉,戌,亥', N',') ORDER BY [Value];
2> GO
Value
-----------------------
亥
卯
丑
午
子
申
辰
寅
酉
未
巳
戌
(12 行処理されました)
左右も逆なら前後も逆。
1> SELECT [Value] FROM STRING_SPLIT(N'前,後,左,右', N',') ORDER BY [Value];
2> SELECT [Value] FROM STRING_SPLIT(N'古,今,東,西', N',') ORDER BY [Value];
3> GO
Value
-------
右
後
左
前
(4 行処理されました)
Value
-------
古
今
西
東
(4 行処理されました)
レディファーストでさえない。冠婚葬祭は惜しい。
1> SELECT [Value] FROM STRING_SPLIT(N'老,若,男,女', N',') ORDER BY [Value];
2> SELECT [Value] FROM STRING_SPLIT(N'冠,婚,葬,祭', N',') ORDER BY [Value];
3> GO
Value
-------
若
女
男
老
(4 行処理されました)
Value
-------
冠
婚
祭
葬
(4 行処理されました)
1> SELECT [Value] FROM STRING_SPLIT(N'喜,怒,哀,楽', N',') ORDER BY [Value];
2> SELECT [Value] FROM STRING_SPLIT(N'風,林,火,山', N',') ORDER BY [Value];
3> GO
Value
-------
哀
楽
喜
怒
(4 行処理されました)
Value
-------
火
山
風
林
(4 行処理されました)
大喜利と化してきたのでこの辺で。