【问题标题】:How to get start/end date from single date column -oracle如何从单个日期列-oracle 获取开始/结束日期
【发布时间】:2013-07-25 20:22:46
【问题描述】:

我在这里看到了一些出色的答案,我需要修复。我还不想创建表或 ETL,我希望创建一个简单的数据库视图,用户可以先访问以进行测试。

一个表有一个 item#、item_ticket_color#、maint_date 和其他列 tick_col 有时会更新 但表中的其他列也是如此。如果其他列被更新或更改 tick_col 迭代。 我需要过滤这些数据以获得以下预期结果并需要一些帮助 试图弄清楚我该怎么做。 如果可能的话,我正在寻找直接的 SQL

ITEM......................TICK_COL................. MAINT_DATE

21524804....................RIBG...................1/1/0001  
21524804....................RIBG...................6/15/2008 6:52:57 AM
21524804....................RIBG...................6/25/2008 11:31:03 AM
21524804....................RIBG...................6/28/2008 4:12:21 AM
21524804....................RIWH...................9/20/2008 6:36:24 AM
21524804....................RIGR...................9/23/2008 6:36:44 AM
21524804....................RIGR...................9/30/2008 6:37:42 AM
21524804....................RIWH...................10/31/2008 6:37:27 AM
21524804....................RIWH...................11/1/2008 6:36:41 AM
21524804....................RIGR...................3/11/2009 6:01:43 PM
21524804....................RIGR...................7/28/2009 6:37:11 AM
21524804....................RIGR...................10/8/2009 6:37:00 AM
21524804....................RIBS...................11/20/2009 6:37:58 AM
21524804....................RIBS...................5/18/2010 6:37:07 AM
21524804....................RIBS...................9/16/2010 6:38:11 AM
21524804....................RIBS...................8/13/2012 10:39:44 AM
21524804....................RIBS...................3/12/2013 6:46:08 AM
21524804....................RIBS...................3/17/2013 9:25:31 AM
21524804....................RIBS...................3/27/2013 6:52:57 AM
21524804....................RIBS...................7/25/2013 6:41:51 AM

我期待在下面看到这个,它显示了开始 以及票证颜色发生变化的每个场景的结束日期。:

21524804.....RIBG.....10101........20080919

21524804.....RIWH.....20080920.....20080922

21524804.....RIGR.....20080923.....20081030

21524804.....RIWH.....20081031.....20090310

21524804.....RIGR.....20090311.....20091119

21524804.....RIBS.....20091120.....20130725

SQLFiddle here.

这是新代码,基于 Jasti 的贡献,我做了一些额外的更改,但这正是我想要的

 SELECT item,
       tick_col,
       from_dt,
       CASE
          WHEN LEAD (from_dt) OVER (PARTITION BY item ORDER BY from_dt) - 1
                  IS NULL
          THEN
             SYSDATE
          ELSE
             LEAD (from_dt) OVER (PARTITION BY item ORDER BY from_dt) - 1
       END
          TO_DATE
  FROM (  SELECT ITEM,
                 TICK_COL,
                 MIN (MAINT_DATE) AS from_dt,
                 MAX (MAINT_DATE) AS to_dt
            FROM (SELECT SUM (start_of_group) OVER (ORDER BY maint_date) AS sm,
                         ITEM,
                         TICK_COL,
                         maint_date
                    FROM (SELECT ITEM,
                                 TICK_COL,
                                 maint_date,
                                 CASE
                                    WHEN LAG (TICK_COL, 1, TICK_COL)
                                            OVER (ORDER BY maint_date) =
                                            TICK_COL
                                    THEN
                                       0
                                    ELSE
                                       1
                                 END
                                    start_of_group
                            FROM mytable))
        GROUP BY ITEM, TICK_COL, sm
        ORDER BY sm)

【问题讨论】:

  • 我添加了解决方案并更新了 SQL Fiddle 链接。如果这对您不起作用,请发表评论。
  • 感谢 Jasti,绝对精彩,我必须在其中添加一些东西才能得到我想要的东西,但它确实有效
  • 将解决方案发布为答案并以这种方式标记。不要用解决方案更新问题,因为它应该是 问题
  • @CM 您的解决方案返回最后日期的July, 26,而不是July, 25,如来自问题的示例数据集。 (SQLFiddle)
  • 我的解决方案,可能不是最好的解决方案,我只是做了一些小的调整,但实际上并没有满足我的需求,因为它在数据库视图的上下文中不起作用。

标签: sql oracle lag analytic-functions lead


【解决方案1】:

我也为您的第一部分添加了查询。以下查询应该解决这两个要求。此查询对项目进行分组,直到 TICK_COL 更改并计算该特定组的最大和最小日期

select ITEM, TICK_COL, MIN(MAINT_DATE) AS from_dt, MAX(MAINT_DATE) AS to_dt from
(
  select sum(start_of_group) over (order by maint_date) as sm, ITEM, TICK_COL, maint_date from 
  (
    select  ITEM, TICK_COL,maint_date,
      case
        when 
          lag(TICK_COL,1,TICK_COL) over (order by maint_date)  = TICK_COL then 0
          else 1
         end start_of_group
    from  mytable 
  )
) group by ITEM, TICK_COL,sm order by sm

更新SQL Fiddle here

【讨论】:

  • 我对我的数据进行了 SQL Fiddle,并且我使用了您的查询,开始和结束日期都已关闭,请查看我的预期结果....
  • @CM - 如果这对你有帮助,那么至少要投赞成票。如果这是答案,请标记为这样。
【解决方案2】:

您可以使用 min 和 max 来获取第二部分。除了标准选择之外,我不确定您在第一部分中要查找的内容。

SELECT ITEM, TICK_COL, MIN(MAINT_DATE) AS startDate, MAX(MAINT_DATE) AS endDate
FROM yourTableName
GROUP BY ITEM, TICK_COL

【讨论】:

    【解决方案3】:

    试试看这个查询是否有效。

       select item,
               tick_col,
               MAINT_DATE maint_start_date,
               (case when tick_col <> next_tick_col then next_maint_date end) maint_end_date
        from (
          select item,
                 tick_col,
                 lead(MAINT_DATE) over (partition by item 
                                        order by MAINT_DATE asc) next_maint_date,
                 lead(tick_col) over (partition by item 
                                      order by MAINT_DATE asc) next_tick_col,
          from   my_table
    ) where tick_col <> next_tick_col;
    

    【讨论】:

      【解决方案4】:

      基于检测期间开始和结束的变体,然后计算所需日期。 (可以找到几乎相同的解决方案here。)

      SQLFiddle

      with marked_set as (
        -- mark start and end of each maintenance period
        select
          item,
          tick_col,
          maint_date,
          decode( nvl(prev_tick, tick_col||'x'), tick_col, 0, 1 ) is_start,
          decode( nvl(next_tick, tick_col||'x'), tick_col, 0, 1 ) is_end
        from (
          select
            item,
            tick_col,
            maint_date,
            lag(tick_col)  over (partition by item order by maint_date) prev_tick,
            lead(tick_col) over (partition by item order by maint_date) next_tick
          from
            mytable
        )
      ),
      boundary_set as (
        -- Leave only start and end of each period
        -- and get dates from previous and next lines
        select
          item,
          tick_col,
          maint_date,
          is_start,
          is_end,
          ( lag(maint_date) over (
              partition by item order by maint_date)
          )                                          prev_maint_date,
          ( lead(maint_date,1,maint_date) over (
              partition by item order by maint_date
            )
          )                                          next_maint_date
        from
          marked_set
        where
          1 in (is_start, is_end)
      ),
      maintenance_sequence as (
        -- Calculate start and end dates for each maintenance period
        select distinct
          item,
          tick_col,
          decode( is_start,
            1, maint_date,
            prev_maint_date
          )                     start_date,
          decode( is_end,
            1, next_maint_date,
            ( lead(next_maint_date,1,next_maint_date)
               over (partition by item order by maint_date)
            )
          )                    end_date
        from
          boundary_set
      )
      select
        -- Final formatting and ordering.
        -- For end date of last period get exact date, for others get previous date
        -- because it's date of start for maintenance of next item.
        item,
        tick_col,
        to_char(start_date, 'yyyymmdd') maint_start,
        decode( (lead(end_date) over (partition by item order by start_date)),
          null, to_char(end_date, 'yyyymmdd'),
          to_char(end_date - 1, 'yyyymmdd')
        )
         maint_end
      from
        maintenance_sequence
      order by
        maint_start
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-08-13
        • 1970-01-01
        • 2019-11-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-25
        相关资源
        最近更新 更多