免责声明我是一个“愚蠢的美国人”,不处理非英语数据,但最近确实与朋友一起使用批量导入 UTF-8 数据,这就是我所看到的。
我有一个像这样的管道分隔值文件
level|name
7|"Ovasino Poste de Santé"
Notepad++ 表示我已将其保存为 UTF-8。
我在 SSIS 中创建了两个平面文件连接管理器:Codepage65001STR 和 Codepage65001WSTR。它们都使用 65001 (UTF-8) 的代码页
在 STR 变体的高级选项卡中,我将数据类型保留为 DT_STR
在 WSTR 变体的高级选项卡中,我将数据类型更改为 DT_WSTR
我还创建了一个表并用相同的数据加载它
DROP TABLE IF EXISTS dbo.dba_286478;
CREATE TABLE dbo.dba_286478
(
level int NOT NULL
, name varchar(75) COLLATE Latin1_General_100_CI_AS_SC_UTF8
)
INSERT INTO dbo.dba_286478
(
level
, name
)
VALUES
(
7 -- level - int
, 'Ovasino Poste de Santé' -- name - varchar(75)
);
DROP TABLE IF EXISTS dbo.dba_286478;
CREATE TABLE dbo.dba_286478
(
level int NOT NULL
, name varchar(75) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);
然后,我使用不同的平面文件连接管理器创建了一个带有平面文件源的数据流任务,并在它们之间添加了数据查看器和一个空的派生列(因此我有一个数据查看器的锚点)。
我对指向我的表的 OLE DB 源以及自定义查询做了同样的事情
SELECT
T.level
, CAST(T.name AS varchar(75)) AS name
FROM
dbo.dba_286478 AS T;
以及明确定义排序规则,因为它在 SSIS 中没有什么不同
, CAST(T.name COLLATE Latin1_General_100_CI_AS_SC_UTF8 AS varchar(75)) AS name
结果都显示相同,最后一个单词是带重音的 Sante。如果 UTF-8 没有发生,它会显示为 Santé
此时,无论我们在平面文件源列定义中是 DT_STR 还是 DT_WSTR,组件都理解 UTF-8 和 UTF-16。
属性,每个的元数据。代码页 65001 STR 看起来与预期的一样。代码页 65001 和数据类型 DT_STR
Unicode,DT_WSTR 看起来不错
但是,OLE 组件是不同的动物。无论我们是对 DT_STR 进行显式转换、可选地指定排序规则,还是让自然元数据流过,组件都会返回 DT_WSTR(完整的 Unicode/UTF-16)的元数据。
无论哪种方式,它都不会检测到代码页/排序规则的东西,只会说不,你是 Unicode
因此,当我们尝试将查找任务与 OLE DB 连接管理器一起使用时,我们可以预期并收到相同的无法在 UTF-8 字符串/varchar 和 UTF-16/nvarchar 之间进行描述
错误表明这是真的,DT_STR 不能匹配 DT_WSTR
无法将输入列“名称”映射到查找列“名称”,因为数据类型不匹配。
那我该怎么办?
您必须进行类型对齐才能使查找组件正常工作,这意味着源数据的类型必须为 DT_WSTR。您可以将平面文件中的数据以 Unicode 格式导入,也可以将其保留为带有代码页 65001 的字符串。如果您采用后者,则需要复制该列并使用派生列或数据转换工作它在 Lookup 组件中。
如果您从查找组件中提取文本,那么它现在作为 Unicode 在您的管道中,因此您可能希望随后将其转换为带有代码页的字符串类型。同样,将使用派生列或数据转换。
SSIS OLE 组件不理解 UTF8
我们通过源和查找组件看到 SSIS 会将 UTF-8 字符串视为 UTF-16,但我认为它可以很好地处理存储到表中。没那么多。
我的服务器排序规则是 Latin1_General_100_CI_AI_SC_UTF8,虽然我在服务器和 dbo.dba_286478 的表定义之间切换了重音敏感度,但在这种情况下并不重要,因为它一直是 UTF-8。
对于我的平面文件源,我使用基于 STR 的文件,该文件具有上面显示的元数据并以黄色突出显示。数据类型 DT_STR 的代码页 65001 是我们想要的。
我添加了一个 OLE DB 目标并将其指向我的表,该表再次将“名称”列定义为 UTF-8
name varchar(75) COLLATE Latin1_General_100_CI_AS_SC_UTF8
检查这个错误!
验证错误。数据流任务 OLE DB 目标 [138]:无法处理列“名称”,因为为其指定了多个代码页(65001 和 1252)。
我们仅在此数据流中使用代码页 65001,然而,SSIS 空间中的某些东西在验证期间推断/默认为 1252 代码页。 p>
让它发挥作用
数据流任务中的组件在构建时考虑了 OLE DB 连接。这就是查找任务支持 2005、2008 和 2008R2 的 OLE DB 连接的原因?很久以前,我知道,但后来的迭代中添加了缓存连接管理器(也称为其他任何东西)选项,因为除了 OLE 连接管理器之外还需要使用其他东西,特别是考虑到当时的推送是弃用 OLE 驱动程序。
在这种情况下,ADO.NET 连接管理器的性能略好于 OLE,这很可能是您在处理 SSIS 包中的 UTF8 数据时必须使用的。当它呈现给表时,它将隐式转换为 UTF-16,然后 SQL Server 会将其捕捉回 UTF-8 空间(我能说的最好)。
作为参考,使用 ADO Source 将 UTF-8 数据引入管道仍将标记为 DT_WSTR/UTF-16/unicode。
但是您可以将 DT_STR 代码页 65001 放入 ADO.NET 目标,而不会出现我在 OLE DB 目标中看到的代码页不匹配错误。
无论您如何将其引入管道,数据库中的数据都将显示为 DT_WSTR。这意味着您可以定义 OLE 和 ADO 连接管理器以按原样使用 Lookup 组件。
或者您可以添加一个前置数据流步骤来填充缓存连接管理器,并且只有一个 ADO.NET 连接管理器。如果您走那条路,请将 DT_WSTR 数据转换为代码页 65001 的 DT_STR 并将该数据存储到缓存中。
DFT - Populate Cache -> DFT - Load data
DFT - 填充缓存
ADO.NET Source -> Data Conversion -> Cache Connection Manager
DFT - 加载数据
Flat File Source -> Lookup Component -> ADO.NET Destination
来自https://dba.stackexchange.com/questions/286478/how-do-i-fix-the-code-page-in-ssis-lookup-transformation-to-be-65001/286520#286520的交叉回答