需要将 SQL nchar 转换为 .NET 转换为 char。
更具体地说,将 nchar UNICODE 转换为 char ASCII。
复杂之处在于 SQL char 使用完整字节。
不是 128 的纯
ASCII。TSQL 函数 ASCII 返回 0-255。
理想情况下,会有一个 FormByte 的 NormalizationForm。
它不会是一个精确的文本值 - 而是一个接近的逻辑值或?。
SQL 将使用 FormByte 从 nchar 转换为 char。
规范化表格
编码解码对我不起作用,我尝试了所有口味。
在 SQL 中,许多 char(字节)映射到 63。63 是 ?。
不仅仅是超过 255 的字符映射到 63。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。
选择 ASCII('Œ') 返回 140,这就是实际存储的内容(检查二进制文件)。
140 / 8C 的 UNICODE 定义是部分行向后。
我检查了该字符的二进制值,它是 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 找不到任何四个查询。检查图表,这是 8776 的正确字符,数学几乎等于。
〜是粘贴到SSMS中的零宽度,但它好像粘贴到从蓝色变为黑色的FROM中。
我错过了什么吗 - 这对我来说似乎是一个错误。
这不仅仅是他错误的价值,而是一个无效的价值。
返回一个 Int16。
假设我想使用字节来存储字符以节省空间 - 它会在 SQL char 上中断,因为 29 个字符不会作为字节返回。
这是我使用的代码:
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。
与其往返 SQL 来获取 FK 的 ID,不如使用 .NET 字典来提高速度。
Dictionary 是从值中获取键的反向查找。
解析器具有 char 的 Int16,因为它已被解析器使用。
因此,如果 char 的 ASCII 错误,则反向查找将失败。
我想我可以对不正确的 ASCII 结果进行硬编码修复。
但我想了解这里发生了什么,然后再走一条以补丁开始的道路。
char 有一些基本缺陷吗?
可以只使用 nchar,但我们更喜欢 char。
应用程序的性质是我们想要匹配。
u 的 6 个变音符号都匹配 ascii u 是一件好事。