如果我尝试插入不带N前缀的unicode,sql server可以给我一个警告

时间:2016-02-23 12:42:27

标签: sql-server unicode sql-server-2012 collation

好的,所以支持团队再次更新了数据库中的一个值并忘记了N前缀,所以用??? s替换它。

是否可以在数据库(sqlserver 2012)或sqlserver管理工作室2012上完成某些事情,可以阻止或警告人们?

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

2 个答案:

答案 0 :(得分:0)

  

是否可以在数据库(sqlserver 2012)或sqlserver管理工作室2012上完成某些事情,可以阻止或警告人们?

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

$xmlfile.InnerXml

但是你无法区分来自先前内容修改的问号与真实问号之间的区别,因此只有在数据库中放置问号也无效时才能使用。

  

为什么数据库会自动将更新更改为?s,如果它是nvarchar列

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

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

答案 1 :(得分:0)

这不是用于连接到SQL Server的驱动程序的问题。它只是由于在字符串文字中使用了错误的数据类型而发生的隐式转换。一切都有类型。默认情况下,数字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 '随机字符中国';

它将返回这些字符而 ??????

  

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

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

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

只返回2

现在,可能可以设置一个策略来捕获隐式转换,但这样做太过深远,很可能会破坏很多东西。即使您可以将其缩小到从VARCHARNVARCHAR的隐式转换,但仍然会破坏在当前情况下可能有效的代码:将'bob'插入NVARCHAR字段将是隐式转换,但不会有数据丢失。并且您不能在触发器中捕获任何此类因素,因为这是在接收隐式转换的数据之后的事实。

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

鉴于?字符在此字段中有效,如果可以确定多个? s永远不会自然发生,那么您可以在涉及多个单个的情况下防止此问题通过创建INSERT,UPDATE触发来转换字符,如果存在多行?,则取消操作。使用Trigger而不是Check Constraint可以进行更多控制,尤其是错误消息:

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 ? s自然会发生,那么搜索???然后只有1或2个字符项可能会漏掉。在任何一种情况下,这应该捕获足够的错误条目,这样你只需要在极少数情况下解决问题(希望如此:)。