提问人:Vincent Vega 提问时间:2/20/2023 最后编辑:Thom AVincent Vega 更新时间:2/22/2023 访问量:244
当平面文件是 ANSI 而不是 UTF8 时,变音符/代码页的 Openrowset 问题
Openrowset problems with Umlauts/Codepage when flatfile is ANSI and not UTF8
问:
我在使用 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 如何选择正确的字符。
答:
我们的临时解决方案是保留我们的旧脚本
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% 保存设计的。因此,得到错误总比没有获取任何数据要好。
评论
BULK INSERT
根本不是 Polybase。这是一个普通的旧 BULK INSERT 命令,自 1990 年代以来一直可用。似乎真正的问题是尝试使用 Access 驱动程序从 CSV 中读取,就好像它们是表一样。Access 驱动程序从来都不是为此而设计的。由于您从未在 Access 驱动程序中指定代码页,因此在数据到达 SQL Server 之前很久就使用错误的代码页加载了数据