【问题标题】:How do I fix the Code Page in SSIS Lookup Transformation to be 65001?如何将 SSIS 查找转换中的代码页修复为 65001?
【发布时间】:2021-06-03 23:15:33
【问题描述】:

我有一个 SQL Server 2019,数据库和表全部设置为 Latin1_General_100_CI_AS_SC_UTF8, 相关表有codedesc 列都有varchar

在 SSIS 项目中,单个数据流组件:

我有一个使用平面文件连接读取的 UTF-8 CSV 文件,要匹配的文本列 codeDT_STR, 65001

我有一个设置为“完整缓存”的查找并加载 Latin1_General_100_CI_AS_SC_UTF8 表,但 SSIS 认为 varchar 列是 DT_STR, 1252

最后,CSV 和查找中的 code 匹配,desc 被发送到目标表,该表位于相同的 Latin1_General_100_CI_AS_SC_UTF8 排序规则中。目标组件设置为AlwaysUseDefaultCodePage TrueDefaultCodePage 65001

我现在收到一条错误消息,指出该列有多个代码页并且无法运行包。

如果不是贴错标签的 1252,这个包应该运行。我相信它与ExternalMetadataXml 有关,它是只读的,并且说我所有的查找varchar 列都是CodePage="1252"

如果我用 npp 手动编辑包 .dtsx 并将 1252 的所有实例替换为 65001,只要我不再接触查找组件,该包就可以运行并且似乎符合我的预期。这似乎有点搞砸了解决方案,我希望还有其他人有更清洁的方法来解决这个问题。谢谢。

【问题讨论】:

  • 您是否更改了源对象中的代码页?

标签: sql-server ssis collation


【解决方案1】:

免责声明我是一个“愚蠢的美国人”,不处理非英语数据,但最近确实与朋友一起使用批量导入 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的交叉回答

【讨论】:

  • 感谢超级详细的回答,但它并没有真正帮助我的情况,因为我的服务器端列是 VARCHAR UTF8,所以如果我要在 DT_WSTR 中工作,我会在完成之前进行另一次转换将其存储到数据库中。我确实有第二种可能的解决方案,即使用另一个平面文件来查找而不是 OLE 查找,这与您推荐的类似
  • 做了更多的腿部工作。我能说的最好的,你被 UTF-8 数据的转换困住了,但 ADO.NET 连接至少可以让你保存到数据库,而 OLE DB 目标不会。
  • 我的回答试图提供的“帮助”是“工具并不真正支持你正在尝试做的事情”我会找出合适的用户语音频道我可以提出这个作为一个问题。
  • fwiw,OLE 目标小部件允许您在属性中指定 AlwaysUseDefaultCodePageDefaultCodePage。如果你设置 True 和 65001,你将能够保存到 db。我已经这样做了,问题是查找小部件没有这些道具
【解决方案2】:

听起来就像您没有更改平面文件连接管理器上的代码页面。打开你的连接管理器,那里有一个代码页的下拉菜单,在那里选择 65001 为 UTF-8。

然后您可能需要更改数据流任务,因为节点(在您必须转换为代码页的任何派生列转换之前)可能会将数据视为 1252,您会收到错误消息,因为 SSIS 不允许隐式转换。

【讨论】:

  • 您好,感谢您的回复,平面文件设置正确,列是平面文件中的 65001。问题是使用 OLE 从 sql 读取的查找,SSIS 以某种方式认为 varchar 是 1252 而它应该是 65001,因为 sql server 排序规则是 UTF8 并且表的代码页是 65001
猜你喜欢
  • 2018-07-05
  • 2017-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-05
  • 1970-01-01
相关资源
最近更新 更多