SQL nchar から char への .NET キャスト/変換が必要です。
より具体的には、nchar UNICODE を char ASCII にキャストします。
これが複雑なのは、SQL char が完全なバイトを使用することです。
128 の純粋な ASCII ではありません
。TSQL 関数 ASCII は 0 ~ 255 を返します。
FormByte の NormalizationForm が存在することが理想的です。
正確なテキスト値ではなく、近い論理値または ? になります。
また、SQL は FormByte を使用して nchar から char にキャストします。
正規化フォーム
エンコード デコードがうまくいかず、すべてのフレーバーを試しました。
SQL では、多くの char (バイト) が 63 にマップされます。63 は ? です。
63 にマップされる 255 を超える char だけではありません
。130 から 140 はすべて 63 にマップされます。
文字 160 ~ 255 はすべて 160 ~ 255 を返します
255 を超えるすべてが 63 にマップされるわけではありません。
たとえば、多くの分音記号は ASCII にマップされます。
TSQL には、UNICODE および ACSII 関数があります。
したがって、すべての Unicode 文字を char 列と nchar 列の両方にロードしました。
SQL によって返される char は、29 文字に対して間違っています。
また、不正な文字に対して返される ASCII() は意味がありません。すべての制御文字は 130 ~ 160 の範囲です。
バイナリで不正な 29 をチェックしたところ、格納されているのは ASCII() によって返されたものです。
27 の場合、char から返されるのは nchar であり、2 の場合は正しい nchar ではありません。それらはすべて ? にマップする必要があります。または同等の ACSII。
“ と ” は"
にマッピングされますが、
?
私はあなたが私を信じていないことを知っています。
「Œ」を char 列に挿入して選択すると、「Œ」が返されます。
また、それを検索することもできます - char = 'Œ' は true を返します。
Select ASCII('Œ') は 140 を返し、それが実際に格納されているものです (バイナリを確認してください)。
140 / 8C の UNICODE 定義は、Partial Line Backward です。
その文字のバイナリ値を確認したところ、8C (140) でした。
返されるのは Unicode 'Œ' Int16 338
です。SQL が何らかの入出力マッピングを行っていて、それが間違っているようです。
ASCII 関数は、? にマップされていない 575 個の Unicode 文字に対して正しいです。
char 値は ACSII と一致し、すべて意味があります。
EG 12 の異なる形式の u はすべて u にマップされます。
? 以外の 32163 文字 にマッピングされていますか? (63)。
以下は、間違った値を返す 29 文字です。
列の順序:
char
nchar
ASCII(char)
UNICODE(nchar)
sqlCharASCIIbackToString did not match Œ Œ 140 338
sqlCharASCIIbackToString did not match œ œ 156 339
sqlCharASCIIbackToString did not match Š Š 138 352
sqlCharASCIIbackToString did not match š š 154 353
sqlCharASCIIbackToString did not match Ÿ Ÿ 159 376
sqlCharASCIIbackToString did not match Ž Ž 142 381
sqlCharASCIIbackToString did not match ž ž 158 382
sqlCharASCIIbackToString did not match ƒ Ƒ 131 401
sqlCharASCIIbackToString did not match ƒ ƒ 131 402
sqlCharASCIIbackToString did not match ˆ ˆ 136 710
sqlCharASCIIbackToString did not match ˜ ˜ 152 732
sqlCharASCIIbackToString did not match – – 150 8211
sqlCharASCIIbackToString did not match — — 151 8212
sqlCharASCIIbackToString did not match ‘ ‘ 145 8216
sqlCharASCIIbackToString did not match ’ ’ 146 8217
sqlCharASCIIbackToString did not match ‚ ‚ 130 8218
sqlCharASCIIbackToString did not match “ “ 147 8220
sqlCharASCIIbackToString did not match ” ” 148 8221
sqlCharASCIIbackToString did not match „ „ 132 8222
sqlCharASCIIbackToString did not match † † 134 8224
sqlCharASCIIbackToString did not match ‡ ‡ 135 8225
sqlCharASCIIbackToString did not match • • 149 8226
sqlCharASCIIbackToString did not match
… … 133 8230
sqlCharASCIIbackToString did not match ‰ ‰ 137 8240
sqlCharASCIIbackToString did not match ‹ ‹ 139 8249
sqlCharASCIIbackToString did not match › › 155 8250
sqlCharASCIIbackToString did not match € € 128 8364
sqlCharASCIIbackToString did not match ™ ™ 153 8482
sqlCharASCIIbackToString did not match ˜ ≈ 152 8776
count63 = 32163 countMis = 29 countCorrect = 575
次の .NET を実行して、SQL によって返された場合にどの「Œ」が返されるかを確認しました
char char338 = (char)338;
System.Diagnostics.Debug.WriteLine(char338);
sqlCmd.CommandText = "select [char] from [charNchar] where [char] = @char;";
sqlCmd.Parameters.Add("@char", SqlDbType.Char).Value = char338;
string string338= sqlCmd.ExecuteScalar().ToString();
char338 = string338.ToCharArray()[0];
System.Diagnostics.Debug.WriteLine(char338 + " " + ((Int16)char338).ToString());
上記のコードは Œ 338 を返し
ます。SQL は、byte として格納されているはずのデータ型に byte より大きい値を返しています。
(char)140 で検索すると、? 63 が返されます。
興味深いのは、'ā' と char の N'ā' で検索すると、異なる結果が得られることです。
それは左側の検索です (140) Œ。
右側を検索 (338) Œ char 検索では何も見つかりません。
Nchar は、どちらかの入力で両方の結果を見つけます。
SELECT [int16],RTRIM([char]) as [char], ASCII([char]) as 'ASCII'
,RTRIM([nchar]) as [nchar], UNICODE([nchar]) as 'UNICODE'
FROM [test].[dbo].[charNchar]
where [char] = 'Œ'
SELECT [int16],RTRIM([char]) as [char], ASCII([char]) as 'ASCII'
,RTRIM([nchar]) as [nchar], UNICODE([nchar]) as 'UNICODE'
FROM [test].[dbo].[charNchar]
where [char] = N'Œ'
SELECT [int16],RTRIM([char]) as [char], ASCII([char]) as 'ASCII'
,RTRIM([nchar]) as [nchar], UNICODE([nchar]) as 'UNICODE'
FROM [test].[dbo].[charNchar]
where [nchar] = 'Œ'
SELECT [int16],RTRIM([char]) as [char], ASCII([char]) as 'ASCII'
,RTRIM([nchar]) as [nchar], UNICODE([nchar]) as 'UNICODE'
FROM [test].[dbo].[charNchar]
where [nchar] = N'Œ'
int16 char ASCII nchar UNICODE
------ -------------------------------------------------- ----------- -------------------------------------------------- -----------
338 Œ 140 Œ 338
int16 char ASCII nchar UNICODE
------ -------------------------------------------------- ----------- -------------------------------------------------- -----------
338 Œ 140 Œ 338
339 œ 156 œ 339
int16 char ASCII nchar UNICODE
------ -------------------------------------------------- ----------- -------------------------------------------------- -----------
338 Œ 140 Œ 338
339 œ 156 œ 339
int16 char ASCII nchar UNICODE
------ -------------------------------------------------- ----------- -------------------------------------------------- -----------
338 Œ 140 Œ 338
339 œ 156 œ 339
≈ search は、4 つのクエリのいずれでも何も見つかりません。チャートを確認したところ、これは 8776 の正しい文字であり、数学的にはほぼ同じです。
〜はSSMSに貼り付けられたゼロ幅ですが、FROMに貼り付けられたかのように、青が黒に変わります。
私は何かが足りないのですか - これは私にはバグのようです。
値が間違っているだけでなく、無効な値です。
Int16 が返されます。
スペースを節約するために文字を格納するためにバイトを使用したいとしましょう.29文字がバイトとして返されないため、SQL文字で壊れます。
使用したコードは次のとおりです。
public void SQLchar()
{
SqlConnection sqlCon = new SqlConnection(connString);
try
{
sqlCon.Open();
SqlCommand sqlCmd = sqlCon.CreateCommand();
SqlDataReader rdr;
sqlCmd.CommandText = "delete charNchar";
sqlCmd.ExecuteNonQuery();
for(Int16 i = 0; i < Int16.MaxValue; i ++)
{
sqlCmd.CommandText = "insert into charNchar (int16,char,nchar) values (@int16, @char, @nchar);";
sqlCmd.CommandType = System.Data.CommandType.Text;
sqlCmd.Parameters.Clear();
sqlCmd.Parameters.Add("@int16", SqlDbType.Int).Value = i;
sqlCmd.Parameters.Add("@char", SqlDbType.Char).Value = (char)i;
sqlCmd.Parameters.Add("@nchar", SqlDbType.NChar).Value = (char)i;
sqlCmd.ExecuteNonQuery();
}
string sqlChar;
string sqlNChar;
Int16 sqlCharASCII;
Int16 sqlNCharUnicode;
string sqlCharASCIIbackToString;
sqlCmd.CommandText = "select char,nchar,ASCII(char),UNICODE(nchar) from charNchar order by int16;";
rdr = sqlCmd.ExecuteReader();
Int16 count63 = 0;
Int16 countMis = 0;
Int16 countCorrect = 0;
while (rdr.Read())
{
sqlChar = rdr.IsDBNull(0) ? "dbNull" : rdr.GetString(0);
sqlNChar = rdr.IsDBNull(1) ? "dbNull" : rdr.GetString(1);
sqlCharASCII = rdr.IsDBNull(2) ? Int16.Parse("-1") : (Int16)rdr.GetInt32(2);
sqlNCharUnicode = rdr.IsDBNull(3) ? Int16.Parse("-1") : (Int16)rdr.GetInt32(3);
if(sqlCharASCII == 63 && sqlNCharUnicode != 63)
{
count63 ++;
continue; // ?
}
if (sqlCharASCII < 0)
{
System.Diagnostics.Debug.WriteLine("ASCII(char) null for " + sqlChar + " " + sqlNChar);
}
else
{
sqlCharASCIIbackToString = ((char)sqlCharASCII).ToString();
if (string.CompareOrdinal(sqlChar, sqlCharASCIIbackToString) != 0)
{
countMis++;
System.Diagnostics.Debug.WriteLine(" sqlCharASCIIbackToString did not match " + sqlCharASCIIbackToString + " " + sqlChar + " " + sqlNChar + " " + sqlCharASCII + " " + sqlNCharUnicode);
}
else
{
countCorrect++;
}
}
}
rdr.Close();
System.Diagnostics.Debug.WriteLine("count63 = " + count63.ToString() + " countMis = " + countMis.ToString() + " countCorrect = " + countCorrect.ToString());
}
catch (Exception Ex)
{
System.Diagnostics.Debug.WriteLine(Ex.Message);
}
finally
{
sqlCon.Close();
}
}
理由は。
.NET で文字列データを解析し、そのデータは FK です。
FK の ID を取得するために SQL に往復するのではなく、速度のために .NET ディクショナリを使用します。
Dictionary は、値からキーを取得するための逆引きです。
パーサーは、既にパーサーによって使用されているため、char の Int16 を持っています。
そのため、char の ASCII が間違っている場合、逆引きは失敗します。
誤った ASCII 結果の修正をハードコーディングできると思います。
しかし、パッチから始まる道をたどる前に、ここで何が起こっているのかを理解したい.
char には根本的な欠陥がありますか?
nchar を使用することもできますが、char を使用することをお勧めします。
アプリケーションの性質は、一致が必要です。
u の 6 つの分音符号がすべて ascii u に一致するのは良いことです。