日本語並び順の考察

## 【序文】
日本語の並び順の問題に関する考察。

## 【環境】
| SQLServer | SQLCMD |
| ---- | ---- |
| 2017 | 14.0.1000.169 |
設定はデフォルト。
但しコマンドプロンプトのコードページは 65001。

## 【よくある問題】
以下のような部署名が格納されたテーブルがあったとする。

| 部署名 |
| ---- |
| 第一営業部 |
| 第二営業部 |
| 第三営業部 |

部署名でソートした結果が以下。

```SQL
1> SELECT [Value] FROM STRING_SPLIT(N'第一営業部,第二営業部,第三営業部', N',') ORDER BY [Value];
2> GO
Value
-----------------
第一営業部
第三営業部
第二営業部

(3 行処理されました)
```

これは期待した結果ではない。というかこれは文字コードの問題であり SQLServer、DB の問題ではない。
しかし、DB での実装でしばしば問題になるテーマなので取り上げてみた。

## 【解決策】
単純に表示順を持たせる方法が一般的だろう。

| 表示順 | 部署名 |
| ---- | ---- |
| 1 | 第一営業部 |
| 2 | 第二営業部 |
| 3 | 第三営業部 |

クエリでは、表示順列でソートすると。
もしクエリ側だけで無理やり何とかするなら以下。

```SQL
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 行処理されました)
```

酷い方法である。しかし開発の現場では、こんな付け焼刃的なコードがゴロゴロしているという……。

## 【余談】
そもそも漢数字の並び順ってどうなっているんだろう？　というのが最初のきっかけだった。

```SQL
1> SELECT [Value] FROM STRING_SPLIT(N'〇,一,二,三,四,五,六,七,八,九,十', N',') ORDER BY [Value];
2> GO
Value
---------------------
〇
一
九
五
三
四
七
十
二
八
六

(11 行処理されました)
```

滅茶苦茶。大字は？

```SQL
1> SELECT [Value] FROM STRING_SPLIT(N'零,壱,弐,参,肆,伍,陸,漆,捌,玖,拾', N',') ORDER BY [Value];
2> GO
Value
---------------------
壱
玖
伍
捌
参
漆
拾
弐
陸
零
肆

(11 行処理されました)
```

そもそも漢字って読み仮名順が基本だっけ？　簡単に言えば、あいうえお順。慣用的な並び順になる訳ない。
しかし、英語圏でも使われるであろうローマ数字や丸数字だとまともなんだよな。そういえばローマ数字ってゼロがないんだね。

```SQL
1> SELECT [Value] FROM STRING_SPLIT(N'Ⅰ,Ⅱ,Ⅲ,Ⅳ,Ⅴ,Ⅵ,Ⅶ,Ⅷ,Ⅸ,Ⅹ', N',') ORDER BY [Value];
2> GO
Value
-------------------
Ⅰ
Ⅱ
Ⅲ
Ⅳ
Ⅴ
Ⅵ
Ⅶ
Ⅷ
Ⅸ
Ⅹ

(10 行処理されました)
```

```SQL
1> SELECT [Value] FROM STRING_SPLIT(N'⓪,①,②,③,④,⑤,⑥,⑦,⑧,⑨,⑩,⑪,⑫,⑬,⑭,⑮,⑯,⑰,⑱,⑲,⑳', N',') ORDER BY [Value];
2> GO
Value
-----------------------------------------
⓪
①
②
③
④
⑤
⑥
⑦
⑧
⑨
⑩
⑪
⑫
⑬
⑭
⑮
⑯
⑰
⑱
⑲
⑳

(21 行処理されました)
```

同様の流れで。

```SQL
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 行処理されました)
```

これらの文字は以下を使わせていただいた。多謝。
[入力しづらい丸英数字のメモ](https://qiita.com/yoh-nak/items/fcea0b5ba51a6dd762ef "入力しづらい丸英数字のメモ")

再び漢字に戻る。
手当たり次第確認してみる。

```SQL
1> SELECT [Value] FROM STRING_SPLIT(N'一,万,億,兆,京,垓,?穣,溝,澗,正,載,極', N',') ORDER BY [Value];
2> GO
Value
-------------------------
�
一
億
澗
京
極
溝
載
穣
正
兆
万
垓

(13 行処理されました)
```

因みに本来入力したクエリは以下。
`𥝱` はサロゲートペア文字みたいでコマンドプロンプト上では扱えない。うーむ。[サロゲートペア入門：CodeZine（コードジン）](https://codezine.jp/article/detail/1592 "サロゲートペア入門：CodeZine（コードジン）") によれば `U+25771` らしい。だから何だって話だけど。

```SQL
SELECT [Value] FROM STRING_SPLIT(N'一,万,億,兆,京,垓,𥝱,穣,溝,澗,正,載,極', N',') ORDER BY [Value];
GO
```
引き続き思いつくままに。

```SQL
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 行処理されました)
```

```SQL
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 行処理されました)
```
惜しい。> 加減乗除

```SQL
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 行処理されました)
```

```SQL
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 行処理されました)
```

```SQL
1> SELECT [Value] FROM STRING_SPLIT(N'子,丑,寅,卯,辰,巳,午,未,申,酉,戌,亥', N',') ORDER BY [Value];
2> GO
Value
-----------------------
亥
卯
丑
午
子
申
辰
寅
酉
未
巳
戌

(12 行処理されました)
```
左右も逆なら前後も逆。

```SQL
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 行処理されました)
```
レディファーストでさえない。冠婚葬祭は惜しい。

```SQL
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 行処理されました)
```

```SQL
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 行処理されました)
```

大喜利と化してきたのでこの辺で。