【问题标题】:Retrieving the statuses of orders on certain dates using Oracle SQL使用 Oracle SQL 检索特定日期的订单状态
【发布时间】:2013-03-03 09:42:36
【问题描述】:

我在创建 Oracle 查询以报告特定日期(一系列月份中每个月的第一天)的订单历史状态时遇到了困难。我搜了又搜,没有人问过类似的问题。这似乎是一个直截了当的问题,所以希望有人能提供帮助!这是我的例子:

订单表:

    ORDER_NUMBER   STATUS    DATE
    50001000       Created   01-15-2010
    50001000       Released  02-20-2010
    50001000       Completed 02-25-2010
    50001000       Closed    03-10-2010
    50001035       Created   01-20-2010
    50001035       Released  01-25-2010
    50001035       Completed 04-05-2010
    50001035       Closed    05-30-2010

所以我需要的输出是每个月初每个订单的状态。像这样的:

    DATE        ORDER_NUMBER   STATUS
    12-01-2009  
    01-01-2010  
    02-01-2010  50001000       Created   
    02-01-2010  50001035       Released
    03-01-2010  50001000       Completed
    03-01-2010  50001035       Released
    04-01-2010  50001000       Closed
    04-01-2010  50001035       Released
    05-01-2010  50001000       Closed
    05-01-2010  50001035       Completed 
    06-01-2010  50001000       Closed
    06-01-2010  50001035       Closed
    07-01-2010  50001000       Closed
    07-01-2010  50001035       Closed
    ..etc

是否有一些原生关键字可以在没有大量连接和子查询的情况下完成这项工作?

谢谢,

加勒特

【问题讨论】:

  • 听起来您可以按月/年进行分区,然后为每个订单选择最大日期的状态。也许这个线程可能会有所帮助:stackoverflow.com/questions/561836/oracle-partition-by-keyword 另外,订单50001035 的状态不应该是Released,因为它是在 2010 年 1 月 25 日发布的?
  • 是的,你是对的,我的示例中有一个错误,现在已将其更改为 2010 年 2 月 1 日发布。谢谢!

标签: sql oracle


【解决方案1】:

花了一些时间,但我认为这将是您正在寻找的:

select to_char(mf.month_first, 'MON-YYYY'), 
       o.order_name,
       o.status
  from (select add_months(to_date('01-DEC-2009'), level-1) month_first
          from dual
       connect by level <= 12) mf
  left outer join orders o
    on trunc(o.status_date, 'MM') <= mf.month_first
 where not exists(
     select 1
       from orders
      where ((trunc(status_date, 'MM') = trunc(o.status_date, 'MM')
              and status_date < o.status_date)
          or (trunc(status_date, 'MM') != trunc(o.status_date, 'MM') 
              and status_date >= o.status_date))
        and trunc(status_date, 'MM') <= mf.month_first
        and order_name = o.order_name)
 order by mf.month_first, o.order_name

上面的查询确保如果在同一个月有两次状态变化,则显示第一个,这就是为什么status_dateo.status_date之间的比较发生了两次,一次是当你在同一个月,不同月份一次...

connect by level 子选择允许您通过指定当月的第一个日期(在本例中为 01-DEC-2009)和报告的持续时间/长度(12 月)来改变日期范围。

我希望这就是您所追求的,但我不得不说,如果您有很多订单,这很可能会创建很多行(特别是如果订单在 3 月完成,它会显示为Closed 直到报告结束。

这是一个SQLFiddle 看看它的工作原理。

【讨论】:

  • 感谢您的回复我在我们的服务器上运行了这个查询,它似乎超时了。但我也研究了 LEAD ... OVER 功能(加入了 first_day_of_month BETWEEN status_date AND next_status_date; 并且还研究了 MAX ... OVER ... PARTITION BY 加入了 status_date
【解决方案2】:

不确定我是否理解您的示例数据,但以下查询可能对您有所帮助 - 将您的日期与每个月的第一天进行比较:

SELECT * FROM your_table 
 WHERE your_date IN
(
 -- This query will give you the first day of each month --
 Select Add_Months(Trunc(Sysdate,'YEAR'),Level-1) first_day_of_month
   From dual
 Connect By Level <= 12 -- number of months in a year --
)

/

【讨论】:

  • 是的,这很好,我喜欢基于今天而不是硬编码日期的动态查询。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多