このシナリオはSQL Serverインスタンスであり、主にBULK INSERT操作を使用してデータをフィードするデータベースです。スペイン語環境で作業しているため、挿入されたテキストの一部にñ
などの特殊文字が含まれています。
したがって、最初の小さなテストの後、単純なselect
を実行すると、これらの特殊文字が正しく表示されないことがわかりました。そのため、考えられるすべてのことを確認し始めます。
select collation_name from sys.databases where name='DBNAME';
結果はSQL_Latin1_General_CP1_CI_AS
になります。これらのテストで、データ正しく保存されていないであると結論付けました。これが、データが正しく表示およびエクスポートされない理由です。インターネットで見つけたほとんどすべての解決策は、文字列データ型フィールドにnvarchar
ではなくvarchar
を使用することを提案していますが、それでもこのシナリオは解決されません。私の挿入を妨害しているのは何ですか?
文字が正しくインポートされていない場合、これは実際には2段階のプロセスであるため、次の領域の1つ(または両方)に問題があります。
BCP/BULK INSERTはファイルがどのようにエンコードされているかを認識しておらず、誤って解釈しています
宛先列はVARCHAR
(またはCHAR
{or TEXT
、ただしTEXT
}は使用しないでください)およびその宛先の照合column(データベースではない)は、誤ってインポートされた文字のマッピングがないコードページを使用します。
ここで、インポートテーブルが存在するデータベースのデフォルトの照合順序は関係がないことに注意してください。ここで重要な唯一の照合順序は、インポートされる特定の各文字列列の照合順序です。また、すべての文字列列の照合順序は異なる場合があり、それらのいずれもデータベースのデフォルトの照合順序と同じである必要はありません。データベース内のほとんどの列の照合順序をデータベースのデフォルトと一致させるのは一般的です。これは、新しいテーブルと列を作成するときに使用され、COLLATE
キーワードを介して照合順序を指定しないためです。
ステップ1:ファイルのエンコード
BCP/BULK INSERT(またはファイルを読み取る他のほとんどのコード)は、ファイルがいくつかのエンコーディングの1つを使用して Byte Order Mark(BOM ) 。ただし、拡張ASCIIエンコーディングはバイトオーダーマークを使用しないため、少なくとも確実にプログラムで決定することはできません。拡張ASCIIエンコーディングを使用すると、コードページを指定する必要があるか、デフォルトが想定されます。
bcp Utility のMSDNページに従って、-Cオプションの下:
OEM->クライアントが使用するデフォルトのコードページ。これは、-Cが指定されていない場合に使用されるデフォルトのコードページです。
コマンドプロンプトを開いてmode
またはchcp
を実行すると、デフォルトのコードページを確認できます(chcp
を使用すると、コードページを変更することもできます。価値)。
デフォルトのコードページが850で、ファイルがWindows-1252 Latin1(ANSI)のエンコーディングで保存されている場合、2つのコードページ間で文字マッピングが同じではないため、ファイルの解釈に問題が発生する可能性があります。これは、SQL Serverとはまったく関係ありません。
コードページ1252では、ñ
文字の値は241です。ただし、コードページ850では、同じ文字の値は164です。ファイルは、他のものに関係なく、一連のバイトであり、それらの1つです。 bytesの10進数値は241です(保存時に、ñ
を241として格納する必要があると判断したコードページ1252を使用するように指示されたため)。これで、BCPがファイルを読み取るときに、デフォルトのMS-DOSコードページ850を使用している場合、同じバイト値241が文字±
にマップされます。 1252
スイッチを介してACP
または-C
(同じもの)のコードページを指定すると、BCPは値241のバイトが実際にはñ
。または、1255(Windowsヘブライ語)のコードページを指定すると、BCP/BULK INSERTは241の同じバイト値を文字ס
として解釈します。
ステップ2:宛先列のデータ型と照合順序
BCP/BULK INSERT(または任意のクライアントアプリ)がデータを読み込むと、ベースバイト値だけでなく、それらのマッピングとして存在します。 BCP/BULK INSERTに読み込まれた文字は、宛先のデータ型と照合順序でマップできる限り、宛先列その文字としてに格納されます。宛先データ型NVARCHAR
、NCHAR
、およびNTEXT
(ただしNTEXT
は使用しない)は、すべての文字を保持できるため、何でもかまいません照合はです。ただし、コピー先のデータ型がVARCHAR
、CHAR
、またはTEXT
の場合、照合はコードページを決定し、次にコードページが文字マッピングを決定します。宛先データ型が最後に言及した3つのうちの1つである場合andは、ファイルに使用されたのと同じコードページに関連付けられた照合を使用し、すべてが正常に機能するはずです。または、照合が別のコードページに関連付けられている場合、バイト値ではなく文字をマップしようとします。
つまり、BCP/BULK INSERTがコードページ1252および文字ñ
(コードページ1252の値241)で機能している場合、照合でVARCHAR
列にインポートするとof SQL_Latin1_General_CP850_CI_AS
-これはコードページ850を使用します-次に、ñ
の代わりに±
(同じ文字ですが、コードページ850の値は164)の文字が表示されます。コードページ850の同じ241値。ただし、Hebrew_CI_AS
の照合順序を持つVARCHAR
列にインポートすると、コードページ1255を使用しますが、代わりに?
が表示されます。コードページ1255のס
のマッピングがないため、ñ
(コードページ1255の値241)。
私と同じような問題が発生する可能性のある人にとって、私のために働いたのはコードページシステムに関連したものでした。さらに詳しく説明します。
データベースの照合では、データベースがコードページ1252を使用し、コンピューターのアクティブなコードページをチェックした後(cmd
を実行し、次にcmd内でmode
)、850であることがわかりました。紛争が起こっていたに違いありません!
コンピューターが私の特殊文字を正しく印刷できない場合、データベースは私のコンピューターがそれに出力する愚かな文字列を保存します。
オプションCODEPAGE=ACP
を追加しました。これにより、一括挿入がSQLサーバーのコードページを使用するように強制され、すべてがうまくいきました:)