WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

LocalDB の照合順序

by WebSurfer 24. September 2020 11:28

Microsoft LocalDB の照合順序はデフォルトで SQL_Latin1_General_CP1_CI_AS になるそうです。今更ながらですが調べてみたらそうなってました。

LocalDB の照合順序

Microsoft の Blog の記事「[SQL Azure] Unicode型列(NCHAR/NVARCHAR) に格納されるデータが “?” になる」によると、SQL Azure も同じだそうです。

なので、その記事にも書いてありますが、以下のような N プレフィックスを使わない SQL では文字化けします。

INSERT INTO [Table] ([Name]) VALUES ('あいうえお')

知ってました? 何をいまさらと言われそうですけど。(汗)

SQL 文をパラメータ化し ADO.NET + SqlClient を利用して INSERT, UPDATE 操作を行えば、内部的に N プレフィックスが付与された SQL 文に変換されて実行され、文字化けの問題は起こらないので、気が付かないかもしれません。(詳しくは先の記事「パラメータ化の副次的な効用」参照)

Visual Studio を使って ASP.NET プロジェクトを作る際[個別のユーザーアカウント]を選ぶと、ASP.NET Identity のユーザー情報のストアはデフォルトで LocalDB を使う設定となり、EF Code First で生成されるデータベースの照合順序も同じく SQL_Latin1_General_CP1_CI_AS になります。

自分でモデルを定義してそれをベースに EF Code First でデータベースを生成する場合も、接続文字列で LocalDB に接続する設定がされていると当然 LocalDB にデータベースが生成されますが、同様に照合順序は SQL_Latin1_General_CP1_CI_AS になります。

ASP.NET MVC アプリでは Linq to Entities を使って DbContext クラスを継承したコンテキストクラスを操作してデータベースとのやり取りを行うケースが多いですが、そういう場合も内部的に N プレフィックスが付与された SQL 文に変換されて実行されるようで、文字化けの問題は起こらなかったです。

Tags: ,

SQL Server

SQL Server 列の照合順序

by WebSurfer 26. April 2018 19:27

自分の持っている本「一目でわかる Microsoft SQL Server 2008」によると、SQL Server の照合順序はサーバー、データベース、列、式に対して指定することができるそうです。(テーブルレベルでは指定できないようです)

そして、照合順序は変更できるのですが、既存のデータベースの照合順序を変更しても、そのテーブルの中の列の照合順序は元のままで、変更されないということは知ってました?

実は、自分は知らなかったです。おかげで 1 ~ 2 時間ハマってしまいました。(汗) また時間を無駄にすることがないように備忘録を残しておきます。

(1) データベースの照合順序

データベースの照合順序

データベースの照合順序は SQL Server Management Studio (SSMS) を使って表示・変更することができます。Transact-SQL を使っても可能です。詳しくは Microsoft の文書「照合順序情報の表示」を見てください。

上の画像は、SSMS で既存のデータベース TestDatabase を右クリックして[データベースのプロパティ]ダイアログを開き、[ページの選択]で[オプション]を選択したものです。[照合順序(C)]ボックスに現在の照合順序が表示されています。

この画面で、[照合順序(C)]ボックスのドロップダウンリストから他の照合順序を選んで、変更することができます。

現在はサーバーレベルでのデフォルトの照合順序を継承して Japanese_CI_AS になっていますが、試しにそれを Japanese_BIN2 に変更してみます。

(2) 列の照合順序

列の照合順序

上の画像は、上記 (1) で既存のデータベース TestDatabase の照合順序を Japanese_CI_AS から Japanese_BIN2 に変更した後の、テーブル dbo.T_TRADE の 列 USER_ID (varchar(10), NOT NULL) のプロパティを SSMS で見たものです。

列 USER_ID の照合順序は Japanese_CI_AS のまま変わってないのが分かるでしょうか。

(3) 列の照合順序の変更

列の照合順序の変更

列の照合順序の変更は Transact-SQL を使って可能です。詳しい方法は Microsoft の文書「列の照合順序の設定または変更」を見てください。

上の画像は、SSMS 上で Transact-SQL を使って、テーブル dbo.T_TRADE の 列 USER_ID の照合順序を Japanese_BIN2 に変更したところです。

(4) 変更後の列の照合順序

変更後の列の照合順序

上の画像の通り、上記 (3) の手順を実行した結果、テーブル dbo.T_TRADE の 列 USER_ID の照合順序が Japanese_BIN2 に変更されています。


以上、既存のデーターベースの照合順序を変更しても意味はなくて、上記の操作をして列の照合順序を変えないとダメという話でした。

先の記事「SQL Server の Order By での濁音の扱い」は order by 句による並び順の話でしたが、主キーの場合は Japanese_CI_AS では濁音有り無しを区別しないことにより制約違反になることがあるということで、注意が必要です。

Tags:

SQL Server

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

by WebSurfer 15. December 2017 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

<<  November 2020  >>
MoTuWeThFrSaSu
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

View posts in large calendar