如何确保 SQL 脚本以 ANSI 编码运行?

Rac*_*SQL 3 sql-server sql-server-2008-r2 encoding unicode

也许这是一个愚蠢的问题,或者我问错了。

我如何确定脚本(包含数千行)正在使用 ANSI 编码运行?

假设我们使用 Notepad++ 创建了一个脚本(程序员同时为 SQL 和 ORACLE 编写代码),并使用ANSI 编码保存它:

在此处输入图片说明

好的。然后,我们的脚本中有一个Â字符。如果我们的客户只是将此脚本复制到使用不同编码的某个工具中(真的,我不知道为什么,但有些用户这样做,我确定这不是为了发现错误),这Â 将被转换为:在此处输入图片说明,但是由于我们的脚本有数千行,所以在客户端没有人会注意到这一点。

我们知道用户不会看到这一点,他们不会阅读整个脚本以确保一切正常。即使是付费的 DBA 也不会这样做(我是 DBA,我肯定会一直阅读所有脚本)。

那么,我怎么能确定,当用户按下 时F5,所有脚本都是用 ANSI 编码的,就像我们发送它的方式一样,没有这些奇怪的字符?我们只能通过正确的数据库整理来实现这一点吗?

我试图在脚本的第一行用 a case when asci character = the ascii(character) then ok else ERROR( using ascii to test )思考这样的事情:

Select CHAR(ASCII('ã')) As Teste_CHAR, CHAR(227) as Teste_CHAR_ASCII
Run Code Online (Sandbox Code Playgroud)

所罗门,这是查询:

Select *,
Case
        When Teste_CHAR=Teste_CHAR_ASCII
        Then 'OK'
        Else 'Erro'
END as STATUS_TESTE,
Case
       When Teste_CHAR=Teste_CHAR_ASCII
       Then 'Everything is OK'
       Else 'Script will not run. your encode is different from ours'
END as Mensagem_TESTE
 from (
Select CHAR(ASCII('ã')) As Teste_CHAR, CHAR(227) as Teste_CHAR_ASCII
) A
Run Code Online (Sandbox Code Playgroud)

Sol*_*zky 6

那么,我怎么能确定,当用户按下 F5 时,所有脚本都是用 ANSI 编码的,就像我们发送它的方式一样,没有这些奇怪的字符?

你不能确定。不幸的是,这只是文本编码的复杂性质,尤其是非 Unicode 编码。一切都只是字节。我们在屏幕上看到的只是对这些字节的解释。对于同一字节或字节序列(取决于编码),一种编码肯定会显示与另一种编码不同的“字符”,但从技术上讲,字节就是字节,所有字节都是有效的。

在 的情况下Â,您无法检测到差异,因为没有差异。您只能xC2在 Notepad++ 中看到 ,因为这是该字符的字节值,但它本身不是有效的 UTF-8 或 UTF-16 / UCS-2 字节序列,因此 Notepad++ 仅显示字节本身。

现在,通过查找不在任何 8 位代码页中的字符并将其与?/ CHAR(63),如果它们匹配,那么您不再使用 Unicode 编码。

这里的缺陷是 8 位编码无法表明它们是什么编码/代码页。你只需要知道。但是,Unicode 编码可以选择在文件开头放置几个字节以指示所使用的编码类型。此字节序列称为字节顺序标记 (BOM),如果采用正确的编码,则不可见。

因此,您最好的选择是使用其中一种 Unicode 编码,并确保使用字节顺序标记 (BOM) 保存文件,因为您通常可以选择使用或不使用 BOM 以 Unicode 编码保存。在 Notepad++(我使用的)中,两个 UCS-2 选项都是仅 BOM,但 UTF-8 可以选择。如果您的脚本当前使用 ANSI,则在Notepad++的编码菜单中,选择转换为 UTF-8-BOM,然后保存文件。然后,当复制并粘贴到 SSMS 中时,一切都应该没问题。并且在大多数编辑器中打开该文件会自动检测到它被编码为 UTF-8,因为 BOM 就在那里。

我们只能通过正确的数据库整理来实现这一点吗?

这与 SQL Server 无关。这与客户端工具及其使用的编码有关。SSMS 几乎肯定使用 UTF-16 LE(Little Endian),因为这是 Windows/SQL Server/.NET 使用的。


关于最近添加到问题末尾的查询:

ã具有值0xE3在ANSI编码,这是不以UTF-8或UTF-16有效。在 Notepad++ 中,将编码更改为 UTF-8(使用“编码输入”,而不是“转换为”)会导致它只显示xE3. 将该版本的查询复制并粘贴到 SSMS 中需要该字节加上下一个字节(用于结束的字节')并将其转换为?由于没有结束引号而中断查询的内容。您可以通过在 之后添加 2 个空格来解决这个问题ã,使其看起来像:

CHAR(ASCII('ã  '))
Run Code Online (Sandbox Code Playgroud)

当编码未更改时,这仍将按预期工作,因为该ASCII函数仅返回第一个字符的值,而忽略其他字符(2 个空格)。

如果该脚本被导入或更改为 UTF-8,它将在 Notepad++ 中显示如下:

CHAR(ASCII('xE3  '))
Run Code Online (Sandbox Code Playgroud)

xE3将是一个单一的“字符”。将该版本的查询复制并粘贴到 SSMS 中将显示如下:

CHAR(ASCII('?'))
Run Code Online (Sandbox Code Playgroud)

并运行将产生所需的“错误”结果。

但是,请注意,这不是万无一失/有保证的测试。它主要只是表明脚本被错误地打开为 UTF-8、UTF-16 或不包含该ã字符的 8 位代码页。

这种方法并不能表明一个错误,如果脚本被打开为8位编码,是不是ANSI但仍包含ã字符,并且可以曲解(即改变)其他字符。

保证 ANSI 编码的唯一方法是找到 a) 在任何其他 8 位代码页中不可用的字符,以及b) 在 UTF-8 或 UTF-16 中不相同的字符。我不知道任何这样的字符,尽管我也没有根据所有可用的代码页检查它们。

但是,如果您只处理以 UTF-8 格式打开文件的人,那么进行上面显示的调整应该适用于这种情况。