如何在存储过程参数中不丢失 unicode 字符

How to not lose unicode characters in Stored Procedure parameter

提问人:Venkataraman R 提问时间:4/13/2022 最后编辑:Dale KVenkataraman R 更新时间:4/18/2022 访问量:676

问:

问题陈述
我们有一个后端为 SQL Server 的旧应用程序。到目前为止,我们在传递非 unicode 值时没有遇到任何问题。现在,我们正在从用户界面中获取 unicode 字符。

unicode 字符在 UI 中如下所示传递。这些数据正在插入到表中。

目前,我们传递如下所示的 unicode 字符,并且我们正在丢失非英语字符。

EXEC dbo.ProcedureName @IN_DELIM_VALS = '삼성~AX~Aland Islands~ALLTest1~Aland Islands~~~~'

我们尝试过什么:
如果我们传递带有 N 前缀的 unicode,则非英语字符将被正确插入到表格中。

EXEC dbo.ProcedureName @IN_DELIM_VALS = N'삼성~AX~Aland Islands~ALLTest1~Aland Islands~~~~'

但是,添加 N 前缀需要更改 UI 代码。由于它是遗留应用程序,我们希望避免 UI 更改。我们想在 sql server 端进行处理。

当我读到传递没有 N 前缀的参数时,数据被隐式转换为默认代码页,韩文字符丢失了。参考

在 Unicode 字符串常量前面加上字母 N 的 信号 UCS-2 或 UTF-16 输入,具体取决于 SC 归类是否为 使用与否。如果没有 N 前缀,字符串将转换为 数据库的默认代码页可能无法识别某些 字符。从 SQL Server 2019 (15.x)SQL Server 2019 (15.x)SQL Server 2019 (15.x)SQL Server 2019 (15.x)SQL Server 2019 (15.x)SQL Server 2019 使用归类,默认代码页能够存储 UNICODE UTF-8 字符集。

我们的问:
有没有办法在分配给存储过程参数之前向存储过程参数添加 N 前缀,这样我们就不会丢失 unicode 字符。

SQL SQL Server 存储过程 Unicode 参数传递

评论

2赞 Thom A 4/13/2022
“但是,添加 N 前缀需要更改 UI 代码。由于它是遗留应用程序,我们希望避免 UI 更改。我们希望在 sql server 端进行处理。它不需要更改用户界面,它应该需要更改应用程序代码才能使用正确的参数类型;显然,您的应用程序正在传递一个参数,或者更糟糕的是,您正在注入一个文本。两者都需要修复。没有 SQL 修复,因为一旦你使用了一个值,就已经太晚了;数据丢失。修复您的应用程序。varcharvarcharvarchar
0赞 Venkataraman R 4/13/2022
@Larnu,同意你的看法。我们必须在应用程序级别修复它。只是想看看是否有任何其他棘手的解决方法可以在存储过程端实现。
1赞 Dan Guzman 4/13/2022
大多数编程中的字符串都是 Unicode,因此,如果您使用参数对象而不是字符串文字来指定值,则无需指定前缀。N
1赞 Charlieface 4/13/2022
无论Unicode问题如何,您都必须解决此问题。不得将数据注入 SQL 批处理,请始终使用参数。无论如何,在程序方面你无能为力:它首先被错误地传递了
1赞 Jeroen Mostert 4/13/2022
确实有一个棘手的解决方法:将数据库的默认排序规则更改为天生支持韩语字符的排序规则,以便参数可以保存它们。但是,当下一个字符串与日语字符一起出现时,这无济于事,因为没有能够保存每个字符的非 Unicode 排序规则。在不更改列排序规则的情况下更改默认排序规则也很容易破坏其他查询,并且更改排序规则更为复杂,因此总而言之,这不是您想要采用的策略,而不是修复不安全的应用程序。VARCHAR

答:

0赞 Venkataraman R 4/18/2022 #1

由于无法添加前缀,因此在将参数传递给 SQL Server 后,我们将进行以下应用程序代码更改。理想情况下,应用程序应传递具有正确数据类型的参数,以便它具有前缀。NnvarcharN

SqlCommand cmd  = new SqlCommand("EXEC dbo.ProcedureName @IN_DELIM_VALS", myConnection);
cmd.Parameters.Add(new SqlParameter("@IN_DELIM_VALS", SqlDbType.NVarChar,400)).Value 
  = "삼성~AX~Aland Islands~ALLTest1~Aland Islands~~~~";
cmd.ExecuteNonQuery();