当平面文件是 ANSI 而不是 UTF8 时,变音符/代码页的 Openrowset 问题

Openrowset problems with Umlauts/Codepage when flatfile is ANSI and not UTF8

提问人:Vincent Vega 提问时间:2/20/2023 最后编辑:Thom AVincent Vega 更新时间:2/22/2023 访问量:244

问:

我在使用 OPENROWSET 时遇到了变音符号问题(例如:Empänger)。在 Windows Server 2012、SQL-Server 2012 和不带 UTF-8 (Latin1_General_CI_AS) 的 COLLATION 的旧环境中,一切都可以正常运行。在大多数情况下,我们的平面文件是 ANSI 格式(我认为是 cp1252)。
现在我们更改为 Windows Server 2016、SQL-Server 2019 和 UTF-8 排序规则 (Latin1_General_100_CI_AS_SC_UTF8),并且德语变音符(像 Übung 一样的变音符)出现了问题。

我们有许多用户使用上传文件并将其用作 SSRS 中的扩展版本的功能。因此,如果它只是一种更改选项,那就太好了。

我们的原始脚本在 UTF-8 上工作正常,但它在 ANSI 中返回了错误的字符:

SELECT * FROM OPENROWSET('MSDASQL','Driver={Microsoft Access Text Driver (*.txt, *.csv)}','select * from \\localhost\_RepUploader\FlatFileTest_ANSI.csv')

这是我得到的:“Emfpfänger”>>“Empf nger” 当我从 ANSI tu UTF-8 更改编码时,我得到了正确的拼写。

以下是该文件的内容:

FirstWord;SecondWord
Empfänger;Üben

在“Schema.ini”中,我尝试了不同的字符集选项:“1252,65001,OEM,ANSI,1250”以及已知代码页之间的其他选项。没有运气。

我让它与 Polybase External_Table 连接一起使用。我还让它与 BULK INSERT 和代码页 1252 一起使用。

drop table if exists #tmp
create table #tmp (FirstWord varchar(100), SecondWord nvarchar(100))
bulk insert #tmp
from '\\localhost\_RepUploader\FlatFileTest_ANSI.csv'
with
(
    fieldterminator = ';',
    codepage = 1252,
    FIRSTROW = 2    
)
select 'ANSI File', * from #tmp

在我看来,Polybase 连接使用 Schema.ini,因为当我尝试 CharacterSet=65001 时,我得到了错误的字符。当我取消注释或使用 CharacterSet=1252 时,一切都很好。那么 Polybase 如何选择正确的字符。

sql-server utf-8 ansi sql-server-2019 平面文件

评论

0赞 Panagiotis Kanavos 2/20/2023
那是 Latin1,而不是 ANSI。确保文件为 UTF8 或指定实际代码页。最好的选择是使用 UTF8,因为它消除了猜测
0赞 Panagiotis Kanavos 2/20/2023
BULK INSERT根本不是 Polybase。这是一个普通的旧 BULK INSERT 命令,自 1990 年代以来一直可用。似乎真正的问题是尝试使用 Access 驱动程序从 CSV 中读取,就好像它们是表一样。Access 驱动程序从来都不是为此而设计的。由于您从未在 Access 驱动程序中指定代码页,因此在数据到达 SQL Server 之前很久就使用错误的代码页加载了数据
0赞 Panagiotis Kanavos 2/20/2023
你首先想做什么?
0赞 Vincent Vega 2/20/2023
我没有发布用于 Polybase 测试的脚本。这是一个简单的创建数据源和创建外部表。所以我真的用 PolyBase 尝试了一下。但是,当我更改此文件的架构.ini中的字符集时,我得到了相同的错误字符。如何在访问驱动程序中设置正确的代码页。
0赞 Vincent Vega 2/20/2023
我有大约 50+ 个用户。用户拥有来自不同来源的列表。在大多数情况下,我无法更改列表,因为它们来自外部应用程序。有时必须扩展列表以帮助同事完成工作。因此,他们将列表上载到 Reporting Services 服务器并打开其报表。

答:

0赞 Vincent Vega 2/22/2023 #1

我们的临时解决方案是保留我们的旧脚本

SELECT * FROM OPENROWSET('MSDASQL','Driver={Microsoft Access Text Driver (*.txt, *.csv)}','select * from \\localhost\_RepUploader\FlatFileTest_ANSI.csv')

我们的用户使用 c# 上传工具上传文件。此工具现在将所有 cp1252 文件转换为 cp65001(无 BOM)。 现在,我们不需要在 Schema.INI 中设置任何 CharakterSet。

有了这个转换后的 UTF-8 文件,我们可以使用旧的语法来完成服务器切换,而无需进行太多更改。

Panagiotis 的解决方案也可以在没有此转换步骤的情况下工作,但我们决定这样做,因为 UTF-8 对我们来说是更好的编码。 OPENROWSET 中的任何 CharakterSet 设置似乎都被忽略了!

SELECT * FROM OPENROWSET('Microsoft.Ace.OLEDB.12.0', 'Text;Database=\\localhost\_RepUploader\', 'Select * from [FlatFileTest_ANSI.csv]')

将来,我们将专注于 BULK Insert。但是在我的测试中,我遇到了许多问题,没有结果,更重要的是,即使有数据,也没有错误。因为我们得到的文件“经过了许多人的手”,所以它们不是 100% 保存设计的。因此,得到错误总比没有获取任何数据要好。