SQL Server 2008のデータ変換の問題を修正する必要があります。データの保存に関する要件の変更がありました。あまり注意せずに、CONVERT(NVARCHAR(max), @bytearraydata, 1)
を使用して既存のvarbinary
データをvarchar
に変換しました。
C#での同じ変換は、_Encoding.Default.GetString
_および_Encoding.Default.GetBytes
_メソッドを使用して行われます。 Encoding.Default.GetBytes(string)
は、以前のようにバイト配列を取得します。しかし、CONVERT()
を使用して変換した文字列のバイト配列を取得しようとすると、間違った結果が返されます。
私の仕事は、データベースとして文字列として格納されているバイト配列をフェッチしてバイト配列に変換し、最後にコンテンツをPDFとしてレンダリングすることです。 (保存中およびフェッチ中に)エンコーディングメカニズムを通過するデータは、私にとってはうまく機能します。しかし、CONVERT
を使用して変換されたデータをフェッチしようとすると、PDFの生成に失敗します。
この問題を解決するにはどうすればよいですか?
バイト配列の列が文字列に変更されました。
この関数を使用して行われる既存のデータ変換:
_Convert(NVARCHAR(MAX), @bytearraydata, 1)
_
アプリケーションでは、バイト配列変換はEncoding.Default.GetString(bytearraydata)
を使用して行われます
Encoding
とCONVERT
は互換性がありませんか?
Encoding.Default
を使用すると、結果はローカル設定に依存します。
オペレーティングシステムの現在のANSIコードページのエンコーディング。
仕様は、デフォルトのエンコーディングを使用することの危険性についてかなり直接的であり、非常に具体的には、それを使用するための推奨notを呼び出します。
異なるコンピューターは異なるエンコーディングをデフォルトとして使用でき、デフォルトのエンコーディングは単一のコンピューターでも変更できます。そのため、あるコンピューターから別のコンピューターにストリーミングされたデータ、または同じコンピューターで異なる時間に取得されたデータも、正しく変換されない場合があります。さらに、Defaultプロパティによって返されるエンコーディングは、最適なフォールバックを使用して、サポートされていない文字をコードページでサポートされている文字にマップします。これら2つの理由により、通常はデフォルトのエンコーディングを使用することはお勧めしません
ここで、何らかの理由で、現在のランダムなローカルエンコーディングがサーバーのエンコーディングと一致することを期待します。 CONVERT
関数があなたが信じていることをするとしても、結果はランダムで予測不可能です:
さらに、CONVERT
は期待どおりのことを行いません。 CONVERT
は、UCS-2エンコーディングを使用してVARBINARY
をNVARCHAR
にキャストします。これは、SQL ServerがNVARCHARデータに使用するエンコーディングであるためです。
最初にこの記事を読んで、緊急の問題に取り組むことをお勧めします すべてのソフトウェア開発者の絶対的な最小値絶対に、確実にUnicodeと文字セットについて知っておく必要があります(言い訳なし!) 。 SQL Serverの国際的な考慮事項 でフォローアップします。
質問にはいくつかの混乱があり、予期しない結果につながります。
VARCHAR
とNVARCHAR
という用語は同じ意味で使用されています(またはそう思われます)が、まったく異なります。 NVARCHAR
は16ビットエンコーディング–正確にはUTF-16 LE(リトルエンディアン)–であり、これは変更されません。 VARCHAR
は8ビットエンコーディングであり、使用される特定の8ビットエンコーディングは、列の照合に関連付けられたコードページによって決定されます(文字列リテラルのVARCHAR
データは無視します)この質問はテーブルに保存されたデータに関するものなので、今のところ変数)。特定の照合順序に関連付けられているコードページを知りたい場合は、COLLATIONPROPERTY
組み込み関数を使用できます。
_SELECT COLLATIONPROPERTY(N'Latin1_General_100_CI_AS_SC', 'CodePage') AS [CodePage];
-- 1252
_
VARBINARY
とVARCHAR
またはNVARCHAR
の間で変換するときは、その文字列データ型と一致するように注意する必要があります。 VARCHAR
からVARBINARY
に変換してから同じVARBINARY
を使用してNVARCHAR
に変換することはできません。
.NETのEncoding
クラスは、7ビット、8ビット、16ビット、32ビット、または変数(UTF-8など)のいずれであっても、テキストの特定のエンコーディングを表します。 「期待どおりの」結果を得るには、_byte[]
_表現に関して、変換先または変換元と一致するエンコードを作成する必要があります。 .NETの文字列は常にUTF-16 LE(NVARCHAR
と同じ)であり、これが.NETのUnicode
エンコーディングと呼ばれています。エンコーディングの_byte[]
_表現は、作成された任意のエンコーディングになりますが、文字列表現は常にUTF-16 LEになります。したがって、どのエンコーディングを作成するかは、処理するデータのタイプによって異なります。
Encoding.Unicode
_を使用COLLATIONPROPERTY(N'collation_name', 'CodePage')
を使用して照合順序のコードページを決定し、int
値をEncoding.GetEncoding(CodePageIntValue)
で使用します。CONVERT
組み込み関数を使用するときは、使用している「スタイル」番号に注意してください。例えば:
_SELECT CONVERT(VARBINARY(50), N'bob');
-- 0x62006F006200
_
次に、返されたVARBINARY
値を取得し、「スタイル」の値0(デフォルト)と1(NVARCHAR
関数で使用している値)を使用してCONVERT
に戻します。質問):
_SELECT CONVERT(NVARCHAR(MAX), 0x62006F006200, 0) AS [Style_0],
CONVERT(NVARCHAR(MAX), 0x62006F006200, 1) AS [Style_1];
_
戻り値:
_Style_0 Style_1
bob 0x62006F006200
_
したがって、質問の次のステートメントが真である場合:
アプリケーションでは、バイト配列変換は
Encoding.Default.GetString(bytearraydata)
を使用して行われます
次に、VARCHAR
の代わりにNVARCHAR
を使用し、_0
_の代わりに_1
_(または何もない)の「スタイル」値を使用することと同じになります。
_CONVERT(VARCHAR(MAX), 0x62006F006200)
_
その問題を再現することはできません。余分な手順はありましたか?私はテキストをバイナリに変換し、再び、またはその逆に、損失なしに変換できます。
DECLARE @OrigText VARCHAR (100) = 'There once was a bear'
DECLARE @Binary VARBINARY(100) = CONVERT(VARBINARY(100), @OrigText)
DECLARE @RoundTripText VARCHAR (100) = CONVERT(VARCHAR (100), @Binary)
DECLARE @RoundTripBin VARBINARY(100) = CONVERT(VARBINARY(100), @RoundTripText)
SELECT @OrigText, @Binary, @RoundTripText, @RoundTripBin
結果:
これはNVARCHAR
でも機能し、CAST
ではなくCONVERT
を使用します。 CONVERT
のスタイルを指定していないことに注意してください。 1つ指定した場合、私の理解は、テキストは16進数の文字列である必要があるということです。それはあなたが保存しているものですか、それとも従来のテキストですか?