WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

SQL Server の Order By での濁音の扱い

by WebSurfer 2017年12月15日 16:10

SQL Server のデフォルトでの照合順序 Japanese_CI_AS で、Order By 句による濁音の並び順がどうなるかについて書きます。元の話は teratail のスレッド半角の「濁音なし」「濁音あり」カナのソート順についてです。

照合順序 Japanese_CI_AS

照合順序 Japanese_CI_AS の場合の結果は上の画像の通りです。濁音はアクセントとして扱われ、'キ' と 'ギ' および 'キ' と 'ギ' は Order By 句では同じ順序となり、「クロギアイコ」は「クロキマユ」より前に、「クロギアイコ」は「クロキマユ」より前になっているのが分かるでしょうか。

半角カナの 'ギ' は、実際は 2 つの文字 'キ' (U+FF77) と '゙' (U+FF8D) を合わせたものなのですが、にもかかわらず「クロギアイコ」は「クロキマユ」より前になるのが不思議でした。

その理由は、MSDN Blogs の記事「日本語照合順序での 濁音、半濁音 の取り扱いについて」に書いてありますが、日本語照合順序を使用している場合 '半角文字' + '濁音' または '半濁音' が 1 文字として認識されるからだそうです。

つまり、Order By では濁点がないのと同じ扱いになり、照合順序に _WS の指定がないので全角・半角の区別をせず、上の画像の様な結果となるということのようです。

ちなみに、照合順序を Japanese_BIN2 にして Order By 句を適用すると以下の画像の順序になります。

照合順序 Japanese_BIN2

BIN2 というのは "すべての文字をコードポイントによる比較を行います" とのことです。詳しくは、MSDN Blogs の記事「照合順序 – 文字の比較と並び順 (その 1)」を見てください。

--------------------------------------------

以下にオマケで、Linq で OrderBy を使った時どうなるかという話を書いておきます。これも元は teratail の別スレッドでの話です。

単純に words.OrderBy(s => s); としたときは SQL Server で照合順序を Japanese_CI_AS とした時と同じになります。

カスタム Comparer を定義し、それを OrderBy の第 2 引数に使えば何とでもできるはずです。SQL Server の照合順序 Japanese_BIN2 と同じ結果になるようにするには、String.CompareOrdinal メソッド(それぞれの文字列の対応する Char オブジェクトの数値を評価することで、2 つの String を比較)が使えそうです。

以下のコードで検証した限りですが、望む結果が得られました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication3
{
    public class StringCompareOrdinal : IComparer<string>
    {
        public int Compare(string x, string y)
        {
            return string.CompareOrdinal(x, y);
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            string[] words = { "the", "quick", "brown", 
                "fox", "jumps","クロキマユ", "クロギアイコ", 
                "クロギトミオ", "テスト 項目", "クロキマユ", 
                "クロギアイコ", "クロギトミオ" };

            var query = words.OrderBy(s => s);

            foreach (string s in query)
                Console.WriteLine(s);
            Console.WriteLine("-------------------");

            var query2 = words.OrderBy(s => s, 
                               new StringCompareOrdinal());

            foreach (string s in query2)
                Console.WriteLine(s);

            /*
            結果は:
            brown
            fox
            jumps
            quick
            the
            クロギアイコ
            クロギアイコ
            クロギトミオ
            クロギトミオ
            クロキマユ
            クロキマユ
            テスト 項目
            -------------------
            brown
            fox
            jumps
            quick
            the
            クロキマユ
            クロギアイコ
            クロギトミオ
            テスト 項目
            クロキマユ
            クロギアイコ
            クロギトミオ
            */
        }
    }
}

Tags: , ,

SQL Server

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  2018年7月  >>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

View posts in large calendar