如何使用 SSIS 从平面文件中删除重复的行?
Posted
技术标签:
【中文标题】如何使用 SSIS 从平面文件中删除重复的行?【英文标题】:How to remove duplicate rows from flat file using SSIS? 【发布时间】:2010-09-14 03:01:24 【问题描述】:首先我要说的是,能够从一个平面文件中获取 1700 万条记录,然后将其推送到远程机器上的数据库并花费 7 分钟,这真是太棒了。 SSIS 真的很棒。但是现在我已经有了这些数据,我该如何删除重复项?
更好的是,我想获取平面文件,从平面文件中删除重复项并将它们放回另一个平面文件中。
我正在考虑一个:
Data Flow Task
谢谢,这个网站上的每个人都知识渊博。
Update:
I have found this link, might help in answering this question
【问题讨论】:
当您说“重复”时,您是指相同的记录,还是主键相同的记录? 【参考方案1】:使用排序组件。
只需选择您希望对加载的行进行排序的字段,在左下角您会看到一个用于删除重复项的复选框。此框仅根据排序标准删除任何重复的行 所以在下面的例子中,如果我们只对第一个字段进行排序,这些行将被认为是重复的:
1 | sample A |
1 | sample B |
【讨论】:
【参考方案2】:我建议使用 SSIS 将记录复制到临时表中,然后根据您的情况创建一个使用 Select Distinct 或 Rank 的任务,以选择将它们汇集到平面文件中的重复项并从临时表中删除它们.最后一步是将临时表中的记录复制到目标表中。
确定重复是 SQL 擅长的,但平面文件不太适合。在您建议的情况下,脚本容器将加载一行,然后必须将其与 1700 万条记录进行比较,然后加载下一行并重复......性能可能不是那么好。
【讨论】:
【参考方案3】:平面文件源 --> 聚合(您想要唯一的按列分组) --> 平面文件目标
【讨论】:
【参考方案4】:策略通常取决于临时表有多少列。列越多,解越复杂。您链接的文章有一些非常好的建议。
到目前为止,我要补充到其他人所说的唯一内容是,具有日期和日期时间值的列将提供适合此处介绍的一些解决方案。
我想出的一个解决方案是:
SET NOCOUNT ON
DECLARE @email varchar(100)
SET @email = ''
SET @emailid = (SELECT min(email) from StagingTable WITH (NOLOCK) WHERE email > @email)
WHILE @emailid IS NOT NULL
BEGIN
-- Do INSERT statement based on the email
INSERT StagingTable2 (Email)
FROM StagingTable WITH (NOLOCK)
WHERE email = @email
SET @emailid = (SELECT min(email) from StagingTable WITH (NOLOCK) WHERE email > @email)
END
在进行重复数据删除时,这比 CURSOR 快很多,并且不会与服务器的 CPU 挂钩。要使用它,请将来自文本文件的每一列分隔到它们自己的变量中。在循环之前和内部使用单独的 SELECT 语句,然后将它们包含在 INSERT 语句中。这对我来说非常有效。
【讨论】:
Hector,在这次 SSIS 工作中,你将成为我的救星!非常感谢! 很高兴为您服务。 ;)【参考方案5】:为了对平面文件执行此操作,我使用了 unix 命令行工具,排序:
sort -u inputfile > outputfile
不幸的是,windows 排序命令没有唯一选项,但您可以尝试从以下之一下载排序实用程序:
http://unxutils.sourceforge.net/ http://www.highend3d.com/downloads/tools/os_utils/76.html。(我还没有尝试过,所以恐怕不能保证)。
另一方面,要在记录加载到数据库时执行此操作,您可以使用 ignore_dup_key 在数据库表的键上创建唯一索引。这将使记录在加载时非常有效地唯一。
CREATE UNIQUE INDEX idx1 ON TABLE (col1, col2, ...) WITH IGNORE_DUP_KEY
【讨论】:
【参考方案6】:我们可以为此使用查找表。就像 SSIS 提供了两种 DFS(数据流转换),即模糊分组和模糊查找。
【讨论】:
【参考方案7】:有点肮脏的解决方案是使用跨越所有列的复合键设置目标表。这将保证明显的唯一性。然后在数据目标形状上,将任务配置为忽略错误。所有重复的插入都会被遗忘。
【讨论】:
【参考方案8】:发现此页面link text 可能值得一看,虽然有 1700 万条记录可能需要一点时间
【讨论】:
【参考方案9】:我建议在目标服务器上加载临时表,然后将结果合并到目标服务器上的目标表中。如果您需要运行任何卫生规则,那么您可以通过存储过程来执行此操作,因为您一定会获得比通过 SSIS 数据流转换任务更好的性能。此外,重复数据删除通常是一个多步骤的过程。您可能希望对以下内容进行重复数据删除:
-
清晰的线条。
不同的列组,例如名字、姓氏、电子邮件地址等。
您可能希望对现有目标表进行重复数据删除。如果是这种情况,那么您可能需要包含 NOT EXISTS 或 NOT IN 语句。或者您可能希望使用新值更新原始行。这通常最好使用 MERGE 语句和源子查询。
获取特定模式的第一行或最后一行。例如,您可能希望在文件中为每次出现的电子邮件地址或电话号码输入最后一行。我通常依靠带有 ROW_NUMBER() 的 CTE 来生成顺序列和逆序列,如下例所示:
.
WITH
sample_records
( email_address
, entry_date
, row_identifier
)
AS
(
SELECT 'tester@test.com'
, '2009-10-08 10:00:00'
, 1
UNION ALL
SELECT 'tester@test.com'
, '2009-10-08 10:00:01'
, 2
UNION ALL
SELECT 'tester@test.com'
, '2009-10-08 10:00:02'
, 3
UNION ALL
SELECT 'the_other_test@test.com'
, '2009-10-08 10:00:00'
, 4
UNION ALL
SELECT 'the_other_test@test.com'
, '2009-10-08 10:00:00'
, 5
)
, filter_records
( email_address
, entry_date
, row_identifier
, sequential_order
, reverse_order
)
AS
(
SELECT email_address
, entry_date
, row_identifier
, 'sequential_order' = ROW_NUMBER() OVER (
PARTITION BY email_address
ORDER BY row_identifier ASC)
, 'reverse_order' = ROW_NUMBER() OVER (
PARTITION BY email_address
ORDER BY row_identifier DESC)
FROM sample_records
)
SELECT email_address
, entry_date
, row_identifier
FROM filter_records
WHERE reverse_order = 1
ORDER BY email_address;
在重复文件删除方面有很多选项可供您选择,但最终我建议您在目标服务器上加载临时表后在存储过程中处理此问题。清理数据后,您可以 MERGE 或 INSERT 到最终目的地。
【讨论】:
以上是关于如何使用 SSIS 从平面文件中删除重复的行?的主要内容,如果未能解决你的问题,请参考以下文章
SSIS - 如何从平面文件插入到具有日期范围的OLE DB?
如何在 SSIS 中使用空格作为分隔符从平面文件中插入数据?