【问题标题】:Remove rows with same keys删除具有相同键的行
【发布时间】:2013-03-05 20:21:51
【问题描述】:

我有如下行的数据:

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 个主键的数据集中删除第一行? (只留下集合的最后一行)

即上面的结果是:

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

【问题讨论】:

    标签: ssis rows


    【解决方案1】:

    假设您的源数据顺序正确,并且您希望每个集合中都有最后一个记录,那么没有任何开箱即用的转换可以处理这种情况。但是,脚本转换可以相当容易地处理它。

    这是一个示例数据流:

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

    选择所有输入列(使用类型为ReadOnly):

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

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

    并使用以下代码:

    /* 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();
        }
    }
    

    这种技术的一个好处是它允许您一次处理数据,并且不需要使用临时表,也不需要将整个源数据集保存在内存中。根据您的数据集有多大,其中任何一个都可能导致严重的性能问题。

    【讨论】:

    • 感谢您的所有回复!我使用了 Edmund Schweppe 的答案,我的程序成功了!再次感谢。
    【解决方案2】:

    建议 #1:尽可能在源查询中执行此操作。

    假设这是不可能的,并且假设您总是希望选择 Col 的最大值,您可以在数据流中使用聚合组件。

    只需将所有列添加到聚合输入中,然后为操作选择 Name1、Name2 和 Name3 的“分组依据”,为 Col 选择“最大值”。

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

    【讨论】:

    • 真;但是,OP 正在寻找 last 行,而不是具有最大值的行。
    【解决方案3】:
    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 是表名的地方

    【讨论】:

    • 我喜欢使用PARTITION BY。但是,OP 要求的是 last 行,而不是 最大 值为col 的行。此外,虽然 OP 环境中某处存在 SQL Server 数据库的可能性非常大,但最初的问题根本没有提到数据库,更不用说支持 PARTITION BY 的数据库了。
    【解决方案4】:

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

    流程:

    数据:

    聚合元素:

    结果:

    如果你使用SQL Table并且可以写查询:

    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 |
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-12
      • 2017-03-02
      • 1970-01-01
      • 2021-04-10
      • 2015-08-07
      • 1970-01-01
      相关资源
      最近更新 更多