如果我尝试插入没有 N 前缀的 unicode,sql 服务器可以给我警告吗

Can sql server give me a warning if I try and insert unicode without the N prefix

好的,所以支持团队再次更新了数据库中的值并忘记了 N 前缀,因此将其替换为 ???s。

是否可以在数据库 (sqlserver 2012) 或 sqlserver management studio 2012 上做一些可以阻止或警告人们的事情?

为什么数据库会自动将更新更改为 ?s,如果它是一个 nvarchar 列并且我在没有 N 的情况下传入 Unicode,为什么它不会出错?

Is there something that can be done on either the database (sqlserver 2012) or sqlserver management studio 2012 that can stop or warn people?

据我所知不是。我唯一能想到的是:

ALTER TABLE some_table ADD CONSTRAINT stop_messing_it_up CHECK (NOT column1 LIKE '%?%');

但是您无法区分来自先前内容处理的问号和真正的问号,因此只有在将问号放入数据库也是无效的情况下,这才可行。

why does the database automagically change the update to ?s, if it's a nvarchar column

列是什么并不重要,重要的是查询表达式中字符串文字的类型。在 SQL 服务器(仅)中,非国家字符串文字只能包含特定于语言环境(“ANSI”)代码页中的字符,因此数据丢失发生在内容到达您的 table 附近之前:

SELECT '随机字符中国';
??????

SELECT N'随机字符中国';
随机字符中国

这不是用于连接 SQL 服务器的驱动程序的问题。这只是由于在字符串文字中使用了错误的数据类型而发生的隐式转换。一切都有类型。默认情况下,数字 2 本身就是 INT,而不是 DECIMALFLOAT 或其他任何东西。默认情况下,数字 2.0NUMERIC(与 DECIMAL 相同),而不是 FLOAT,等等。字符串也不例外。表示为 'something' 的字符串是 8 位 ASCII,使用查询所在数据库的代码页 运行。如果您在数据库中使用 '随机字符中国' 设置为以下之一如果排序规则支持 8 位编码中的这些字符(它将是双字节字符集 (DBCS)),则它不会转换为 ?,因为它的代码页中会有该字符。

CREATE DATABASE [ChineseSimplifiedPinyin] COLLATE Chinese_Simplified_Pinyin_100_CI_AS;

然后,运行这个:

USE [ChineseSimplifiedPinyin];
SELECT '随机字符中国';

它会 return 那些字符 不会 ??????.

And why does the database automagically change the update to ?s, if it's a nvarchar column and I'm passing in Unicode without N why not have it error?

UPDATE 未更改。发生隐式转换是因为您在未使用 N 前缀时对字符串文字使用了错误的数据类型。这与执行以下操作没有什么不同:

DECLARE @Test INT;
SET @Test = 2.123;
SELECT @Test;

其中 return 只是一个 2

现在,可能 可以设置一个策略来捕获隐式转换,但这会影响太大并且可能会破坏很多东西。即使您可以将其缩小到从 VARCHARNVARCHAR 的隐式转换,这仍然会破坏在当前情况下可以正常工作的代码:将 'bob' 插入 NVARCHAR字段将是隐式转换,但不会丢失数据。而且您不能在触发器中捕获任何这些,因为这是在接收隐式转换数据之后发生的。

确保没有人忘记在没有 N 前缀的情况下插入或更新的最佳方法是创建一个网络应用程序或控制台应用程序作为此接口(无论如何这可能是个好主意,因为那还将防止某人使用错误的 WHERE 子句或完全忘记使用一个子句,这两种情况都会发生)。创建小型 .NET Web 或控制台应用程序非常简单,.NET 字符串都是 Unicode (UTF-16 Little Endian)。然后应用程序获取数据并提交 INSERT 或 UPDATE 语句。请务必使用参数而不是动态 SQL.


鉴于 ? 字符在此字段中有效,如果可以确定多个 ? 永远不会自然发生,那么您可能可以在涉及超过通过创建 INSERT、UPDATE 触发器来转换单个字符,如果一行中存在多个 ?,则取消操作。使用触发器而不是检查约束允许更多的控制,尤其是在错误消息上:

CREATE TRIGGER tr_PreventLosingUnicodeCharacters
ON SchemaName.TableName
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;

  IF (EXISTS (SELECT *
             FROM   INSERTED ins
             WHERE  ins.column1 LIKE N'%??%')
     )
  BEGIN
    ROLLBACK; -- cancel the INSERT or UPDATE operation

    DECLARE @Message NVARCHAR(1000);
    SET @Message =
               N'INSERT or UPDATE of [column1] without "N" prefix results in data loss. '
                 + NCHAR(13) + NCHAR(10)
                 + N'Please try again using N''string'' instead of just ''string''.';

    RAISERROR(@Message, 16, 1);
    RETURN;
  END;
END;

如果 2 ? 自然发生,则搜索 ???,然后只有 1 或 2 个字符的项目可能会被忽略。在任何一种情况下,这都应该捕获足够多的错误条目,以便您只需要在极少数情况下修复问题(希望 :)。