2013-03-04 92 views
2

我有象以下行数据:用相同的密钥删除行

Name1 Name2 Name3 Col 
aaa bbb ccc ... 
abc ddd ddd 1 
abc ddd ddd 2 
abc ddd ddd 3 
fff fff fff ... 
ggg ggg hhh 4 
ggg ggg hhh 5 

Name1Name2Name3是主键)

如何从该组数据中移除所述第一行使用相同的3个主键? (离开只有该组的最后一行)

I.e.从上面的结果将是:

Name1 Name2 Name3 Col 
aaa bbb ccc ... 
abc ddd ddd 3 
fff fff fff ... 
ggg ggg hhh 5 

回答

2

假设你的源数据以正确的顺序,你想在每一组中的最后记录,没有任何失可以处理这种情况的机箱转换。但是,脚本转换可以很容易地处理它。

这里的一个样本数据流:

enter image description here

我使用FF_SRC_AllRowsFF_DST_SelectedRows作为平面文件源和目的地(分别)为简单起见,使用您提供的样品的数据;您的具体需求会有所不同。脚本转换SCR_SelectLastRow被配置为转换(输入和输出):

enter image description here

选择的所有输入的字段(使用类型ReadOnly):

enter image description here

创建一个输出(我将它命名为OutgoingRows,但您可以随意命名它),并将SynchronousInputID属性设置为None。这会让你的脚本过滤出你不想要的行。

enter image description here

添加对应的输入列输出列:

enter image description here

而且沿着这些线路使用代码:

/* Microsoft SQL Server Integration Services Script Component 
* Write scripts using Microsoft Visual C# 2008. 
* ScriptMain is the entry point class of the script.*/ 

using System; 
using Microsoft.SqlServer.Dts.Pipeline.Wrapper; 
using Microsoft.SqlServer.Dts.Runtime.Wrapper; 

[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute] 
public class ScriptMain : UserComponent 
{ 
    class IncomingRowData 
    { 
     public string Name1; 
     public string Name2; 
     public string Name3; 
     public string Col; 
     public IncomingRowData(IncomingRowsBuffer Row) 
     { 
      Name1 = Row.Name1; 
      Name2 = Row.Name2; 
      Name3 = Row.Name3; 
      Col = Row.Col; 
     } 
     public bool KeysDiffer(IncomingRowData other) 
     { 
      return (Name1 != other.Name1 
       || Name2 != other.Name2 
       || Name3 != other.Name3); 
     } 
     public void WriteToOutputBuffer(OutgoingRowsBuffer Row) 
     { 
      Row.AddRow(); 
      Row.Name1 = Name1; 
      Row.Name2 = Name2; 
      Row.Name3 = Name3; 
      Row.Col = Col; 
     } 
    } 

    private IncomingRowData _previousRow; 

    public override void IncomingRows_ProcessInputRow(IncomingRowsBuffer Row) 
    { 
     if (_previousRow == null) 
     { 
      _previousRow = new IncomingRowData(Row); 
     } 
     IncomingRowData currentRow = new IncomingRowData(Row); 
     if (currentRow.KeysDiffer(_previousRow)) 
     { 
      _previousRow.WriteToOutputBuffer(this.OutgoingRowsBuffer); 
     } 
     _previousRow = currentRow; 
    } 

    public override void FinishOutputs() 
    { 
     if (_previousRow != null) 
     { 
      _previousRow.WriteToOutputBuffer(this.OutgoingRowsBuffer); 
     } 
     base.FinishOutputs(); 
    } 
} 

关于这项技术的一个好处是,它允许您一次处理数据,不需要使用临时表和ke将整个源数据集设置在内存中。根据您的数据集有多大,这些可能会导致重大的性能问题。

+0

谢谢你的回应!我用埃德蒙施韦普的答案,我的程序工作!再次感谢。 – Albert 2013-04-16 00:57:20

1

建议#1:如果可能的话在源查询中执行此操作。

假设这是不可能的,假设您始终希望选择Col的最大值,那么可以在数据流中使用Aggregate组件。

只是对所有列添加到总投入,并为操作选择“分组依据”为1,名称和NAME3“最大”为上校

不幸的是,总的成分是异步组件 - 意味着您的整个流程将在数据流入时暂停,因为它不会知道每个组的“最大”值,直到它在每一行中读取为止。

+0

真;然而,OP期望获得* last *行,而不是具有最大值的行。 – 2013-03-04 19:43:19

1
SELECT name1, 
     name2, 
     name3, 
     col 
FROM (SELECT name1, 
       name2, 
       name3, 
       col, 
       Max(rn) 
       over ( 
        PARTITION BY name1, name2, name3) AS max_rn, 
       rn 
     FROM (SELECT name1, 
         name2, 
         name3, 
         col, 
         Row_number() 
         over ( 
          PARTITION BY name1, name2, name3 
          ORDER BY col) AS rn 
       FROM test1)) 
WHERE max_rn = rn; 

你可以试试这个地方test1的是表名

+0

我喜欢使用'PARTITION BY'。然而,OP要求* last *行,而不是'col'的*最大*值。此外,尽管在OP环境中有一个SQL Server数据库的可能性相当好,但最初的问题根本没有提到数据库,更不用说支持“PARTITION BY”的数据库了。 – 2013-03-04 19:47:04

0

您需要对您的数据进行分组并选择最大Col值。

FLOW:

enter image description here

数据:

enter image description here

骨料元件:

enter image description here

结果: enter image description here

如果您使用的是SQL表,能写查询:

SQLFIDDLEExample

SELECT Name1, Name2, Name3, MAX(Col) Col 
FROM Table1 
GROUP BY Name1, Name2, Name3 

结果:

| NAME1 | NAME2 | NAME3 | COL | 
------------------------------- 
| aaa | bbb | ccc | ... | 
| abc | ddd | ddd | 3 | 
| fff | fff | fff | ... | 
| ggg | ggg | hhh | 5 |