如何使用SSIS从平面文件中删除重复的行?
首先我要说的是,能够从一个平面文件中提取1700万条记录,将其推送到远程设备上的数据库中,并花费7分钟,这真是令人惊讶。 SSIS确实很棒。但是现在我已经有了这些数据,如何删除重复项?
更好的是,我要获取平面文件,从平面文件中删除重复项,然后将其放回另一个平面文件中。
我在考虑一个:
数据流任务
- 文件源(具有关联的文件连接)
- 一个for循环容器
- 一个脚本容器,其中包含一些逻辑来判断是否存在另一行
谢谢我们,这个网站上的每个人都知识渊博。
更新:
我已经找到此链接,可能有助于回答这个问题
解决方案
我建议使用SSIS将记录复制到临时表中,然后创建一个根据情况使用Select Distinct或者Rank的任务来选择重复项,这些重复项将它们集中到平面文件中,然后从临时表中删除。最后一步是将记录从临时表复制到目标表。
确定重复项是SQL擅长的事情,但是不太适合使用平面文件。在我们提议的情况下,脚本容器将加载一行,然后必须将其与1700万条记录进行比较,然后加载下一行并重复执行……性能可能不是那么好。
该策略通常将取决于登台表具有多少列。列越多,解决方案越复杂。我们链接的文章有一些很好的建议。
到目前为止,我要补充的是,其他人唯一要说的是,带有日期和日期时间值的列将提供此处介绍的一些解决方案。
我想到的一种解决方案是:
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语句中。这对我来说真的很好。
要在平面文件上执行此操作,请使用unix命令行工具进行排序:
sort -u inputfile > outputfile
不幸的是,windows sort命令没有唯一的选项,但是我们可以尝试从以下其中一个下载sort实用程序:
- 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
有点肮脏的解决方案是使用覆盖所有列的组合键来设置目标表。这将确保具有唯一性。然后在"数据目标"形状上,配置任务以忽略错误。所有重复的插入都将被遗忘。
使用排序组件。
只需选择要对加载的行进行排序的字段,然后在左下角看到一个复选框即可删除重复项。此框将删除仅基于排序条件重复的所有行
因此,在下面的示例中,如果我们仅对第一个字段进行排序,则这些行将被视为重复行:
1 | sample A | 1 | sample B |
平面文件源->聚合(我们要唯一的分组依据列)->平面文件目标
我建议在目标服务器上加载暂存表,然后将结果合并到目标服务器上的目标表中。如果我们需要运行任何卫生规则,则可以通过存储过程来执行此操作,因为与SSIS数据流转换任务相比,我们一定会获得更好的性能。此外,重复数据删除通常是一个多步骤过程。我们可能要在以下项上进行重复数据删除:
- 分明的线条。
- 不同的列组,例如名字,姓氏,电子邮件地址等。
- 我们可能想对现有目标表进行重复数据删除。如果真是这样,那么我们可能需要包括NOT EXISTS或者NOT IN语句。或者,我们可能想用新值更新原始行。通常最好与MERGE语句和源子查询一起使用。
- 采取特定图案的第一行或者最后一行。例如,我们可能希望每次出现电子邮件地址或者电话号码时在文件中输入最后一行。我通常依靠带有ROW_NUMBER()的CTE来生成顺序列和逆序列,如以下示例所示:
。
WITH sample_records ( email_address , entry_date , row_identifier ) AS ( SELECT '[email protected]' , '2009-10-08 10:00:00' , 1 UNION ALL SELECT '[email protected]' , '2009-10-08 10:00:01' , 2 UNION ALL SELECT '[email protected]' , '2009-10-08 10:00:02' , 3 UNION ALL SELECT '[email protected]' , '2009-10-08 10:00:00' , 4 UNION ALL SELECT '[email protected]' , '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;
对于重复数据删除,有很多选项供我们选择,但是最终,我建议我们在目标服务器上加载临时表后,在存储过程中进行处理。清除数据后,可以合并或者插入到最终目标位置。
发现此页面的链接文本可能值得一看,尽管有1,700万条记录可能需要一些时间