【问题标题】:How to compare the column values of the max and min dates of a group of rows in Oracle?如何比较Oracle中一组行的最大和最小日期的列值?
【发布时间】:2021-03-07 22:49:40
【问题描述】:

给定一个看起来像这样的表,我将如何创建另一个获取此数据的查询,比较该 store_id 的最早和最晚日期的 sales_net_amt,并为每个 store_id 返回一行,显示纯文本是否“增加”或在另一列中“减少”加班?

对于计算列,我假设我可以只使用“case when”子句,但我不确定如何导出最新日期和最早日期的两个单独值来进行比较。 我能做的最好的事情是创建一个显示最新和最早日期及其 sales_net_amt 的查询,但我不知道如何根据现有值添加计算列

这是我所做的查询(QUARTER 列是不需要的,这使得查询不必要地冗长,只是想我会暂时添加它,以防我最终使用它):

select case when extract(month from full_date) between 1 and 3 then substr(item_scan_timestamp, -4) || 'Q1'
     when extract(month from full_date) between 4 and 6 then substr(item_scan_timestamp, -4) || 'Q2'
     when extract(month from full_date) between 7 and 9 then substr(item_scan_timestamp, -4) || 'Q3'
     when extract(month from full_date) between 10 and 12 then substr(item_scan_timestamp, -4) || 'Q4' end quarter, r.store_id, p.full_date, r.sales_net_amt
from retailsalesfact r join purchasedate p on p.purchase_date_id = r.purchase_date_id
where (r.store_id, p.full_date) in (select r.store_id, max(p.full_date) full_date
        from retailsalesfact r join purchasedate p on p.purchase_date_id = r.purchase_date_id
        group by r.store_id)
union all
select case when extract(month from full_date) between 1 and 3 then substr(item_scan_timestamp, -4) || 'Q1'
     when extract(month from full_date) between 4 and 6 then substr(item_scan_timestamp, -4) || 'Q2'
     when extract(month from full_date) between 7 and 9 then substr(item_scan_timestamp, -4) || 'Q3'
     when extract(month from full_date) between 10 and 12 then substr(item_scan_timestamp, -4) || 'Q4' end quarter, r.store_id, p.full_date, r.sales_net_amt
from retailsalesfact r join purchasedate p on p.purchase_date_id = r.purchase_date_id
where (r.store_id, p.full_date) in (select r.store_id, min(p.full_date) full_date
        from retailsalesfact r join purchasedate p on p.purchase_date_id = r.purchase_date_id
        group by r.store_id)
order by store_id, full_date, sales_net_amt;

select store_id, full_date, sales_net_amt
from retailsalesfact r join purchasedate p on p.purchase_date_id = r.purchase_date_id
order by store_id;

任何建议表示赞赏。

【问题讨论】:

  • 您运行的是什么版本的 Oracle DB?
  • @etch_45 Oracle 12c

标签: sql oracle group-by case


【解决方案1】:

您可以在GROUP BY 中使用KEEP 子句,因为您希望每个商店有一条记录,如下所示:

select store_id, 
       case when max(SALES_NET_AMT) keep (dense_rank first order by FULL_DATE desc) 
                  > max(SALES_NET_AMT) keep (dense_rank first order by FULL_DATE) 
            then 'Increased' 
            else 'Decreased' 
      end as result
  from your_Table t
group by store_id

【讨论】:

  • 嘿,这很好用!您能解释一下keep 子句在这种情况下的作用吗?您是否也可以将数据分区为窗口函数的一部分,而不是使用 group by 子句?
  • KEEP 子句根据组的其他值给出数据。您必须从 oracle 文档中了解它。
【解决方案2】:

假设您的FULL_DATE 列实际上是一个日期,您可以使用FIRST_VALUELAST_VALUE 按日期获取第一个和最后一个值,然后进行比较:

SELECT DISTINCT STORE_ID,
       CASE WHEN LAST_VALUE(SALES_NET_AMT) OVER (PARTITION BY STORE_ID ORDER BY FULL_DATE) >
                 FIRST_VALUE(SALES_NET_AMT) OVER (PARTITION BY STORE_ID ORDER BY FULL_DATE) THEN 'Increased'
            ELSE 'Decreased'
       END AS SALES_CHANGE
FROM YourTable

【讨论】:

  • 这非常有效。你能解释一下这个方法和@Tejash 的方法之间的主要区别吗?在阅读您的答案并对其进行一些研究之前,我从来不知道窗口和分析函数,所以我对查询的每个部分到底在做什么感到困惑。
  • @Andrew 此查询使用窗口函数(last_valuefirst_value),它们有效地按 full_date 对行进行排序,并选择与这些行对应的 sales_net_amt 的值,其中其他解决方案使用keep 进行聚合以过滤它进行聚合的行。我怀疑这个查询会更快——它不那么复杂——但看看真实数据的性能结果会很有趣。
猜你喜欢
  • 2019-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-31
相关资源
最近更新 更多