【问题标题】:sql connect different rowssql连接不同的行
【发布时间】:2013-10-21 19:43:12
【问题描述】:

最近在oracle sql中遇到一个问题。花了很多时间试图弄清楚,但似乎很难实现。因此,如果有人可以提供帮助,那就太好了!

问题很简单,我想连接不同行中的重复项,以便找到“真正的开始”和“真正的结束”,例如,

ID  Start date  End date    Line
1   8/25/2013   8/27/2013   1
1   8/27/2013   8/30/2013   2
2   8/20/2013   8/27/2013   1
2   9/1/2013    9/4/2013    2
2   9/4/2013    9/5/2013    3
2   9/5/2013    9/7/2013    4

如您所见,对于同一个ID,它有多个“开始”和“结束”,但其中一些是一致的(结束日期与其下一个开始日期相同)。我想做的是对数据进行排序并删除一些重复项。例如,结果应该是,

ID  Start date  End date
1   8/25/2013   8/30/2013
2   8/20/2013   8/27/2013
2   9/1/2013    9/7/2013

如果有人可以提供一些提示,我真的很感激。我尝试了“引导”功能,但似乎解决这个问题还需要更多。另外,我尝试将此查询复制到 Access,您知道它没有太多花哨的功能,所以第二个问题是这是否可以在 Access 中实现。谢谢...

【问题讨论】:

    标签: sql oracle compare rows


    【解决方案1】:

    有趣的问题。请问你在哪里找到的?下面是我的提议。我还没有彻底测试它,但我会的,因为我也有兴趣找到一个合适的解决方案来解决这个问题。困难的部分是找到START WITH 子句的所有记录,但对于我用于测试的数据,它返回了正确的结果集。我希望有人会发布一个更简单的解决方案,也许使用分析函数(我自己没有成功)。

    好的,代码如下:

    CREATE TABLE my_data (
      id NUMBER,
      start_date DATE,
      end_date DATE,
      line NUMBER
    );
    
    INSERT INTO my_data VALUES (1, DATE '2013-08-25', DATE '2013-08-27', 1);
    INSERT INTO my_data VALUES (1, DATE '2013-08-27', DATE '2013-08-30', 2);
    INSERT INTO my_data VALUES (2, DATE '2013-08-20', DATE '2013-08-27', 1);
    INSERT INTO my_data VALUES (2, DATE '2013-09-01', DATE '2013-09-04', 2);
    INSERT INTO my_data VALUES (2, DATE '2013-09-04', DATE '2013-09-05', 3);
    INSERT INTO my_data VALUES (2, DATE '2013-09-05', DATE '2013-09-07', 4);
    
    COMMIT;
    
    SELECT
        id,
        root_start_date AS start_date,
        MAX(end_date) AS end_date
      FROM (
        SELECT
            id,
            start_date,
            end_date,
            CONNECT_BY_ROOT start_date AS root_start_date
          FROM my_data
        START WITH (id, start_date) IN (
                                SELECT id, start_date
                                  FROM my_data md
                                WHERE
                                  NOT EXISTS (
                                    SELECT 1
                                      FROM my_data
                                    WHERE id = md.id
                                      AND md.start_date BETWEEN start_date AND end_date
                                      AND end_date < md.end_date
                                    )
        )
        CONNECT BY start_date >= PRIOR start_date
                AND start_date <= PRIOR end_date
                AND end_date > PRIOR end_date
                AND id = PRIOR id
      )
    GROUP BY id, root_start_date
    ORDER BY id, start_date
    ;
    

    结果:

     ID START_DATE END_DATE
    ---------- ---------- --------
             1 13/08/25 13/08/30
             2 20 年 8 月 13 日 27 年 8 月 13 日
             2 13/09/01 13/09/07 

    【讨论】:

    • 非常感谢@PrzemyslawK!它确实对我的 Oracle 蟾蜍有帮助和工作。这是我工作中的一个案例。当我处理数据时,我总是尝试对它们进行排序并使其更易于使用。了解“start with”和“connect”的功能真的很有帮助。非常感谢您的帮助!
    • 对了,@PrzemyslawK,你用的是什么解析函数,能不能多解释一下……谢谢分享!
    • @user2679074 没问题,我很高兴我能提供帮助并且我找到了解决方案,因为我前段时间遇到过类似的问题并且当时没有找到解决方案。您的后一条评论是指您希望我解释我提出的查询中发生了什么吗?
    • 谢谢,我明白了你的意思。我想说的是,既然你谈到了也许其他分析函数可以提供更简单的解决方案,我想知道它们是什么,所以我也可以尝试一下。
    • @user2679074 不幸的是,我不知道如何使用分析函数来解决这个问题,或者是否有可能。
    【解决方案2】:

    这是我想出的,我很想用更多的数据来尝试一下,但本质上,我所做的只是确保 (id, start_date) 的组合不作为 (id , end_date)。

    我想当一个特定的 id 具有相同的开始日期和结束日期时,错误可能会出现——你应该测试一下。

    希望这能让你达到 80%(不过,它可以工作并返回你想要的输出):

    SELECT id, start_date
      FROM table1 mst
     WHERE (id, start_date) NOT IN (SELECT id, end_date FROM table1)
    

    验证(sqlfiddle):http://sqlfiddle.com/#!4/6116f/20/0

    【讨论】:

    • 感谢@RobertoN 的帮助,我认为这是正确的逻辑开始。
    • 如果对您有用,请随时接受我的解决方案 :)
    猜你喜欢
    • 1970-01-01
    • 2015-10-05
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 2017-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多