【问题标题】:SQL query to get the latest price from the data?SQL查询从数据中获取最新价格?
【发布时间】:2020-02-15 08:09:44
【问题描述】:

我的 Oracle 表中有这些数据:

在此表中,我有多个产品,在特定时间具有 product_id 和价格。

我想编写一个 SQL 查询,根据TIME 列(Oracle - Long 类型)获取每种产品的最新价格。

但问题出在这里,因为我们对产品的表价监控从前一天的 23:00 开始。

需要输出:当我将 2019 年 12 月 2 日作为参数传递给 SQL 查询时

如何使用 SQL 查询来做到这一点?还是我需要为它写一个存储过程,基于 if 和 else 条件?

提前致谢。

【问题讨论】:

  • But here is the problem ... 您似乎在 12 月 19 日晚上 11 点前后都获得了结果。请解释你的逻辑。
  • @Tim 日期不是 12 月 19 日,而是 2019 年
  • 抱歉,现在是 2019 年 12 月 2 日,但我的问题仍然存在。
  • @Tim 让我解释一下逻辑:我想要每个产品的最新价格。现在我将在我的查询中传递日期作为参数。但是,我需要考虑时间超过 230000(hhmmss) 和上一个日期的所有行。你可以看到我展示的输出。对于产品 ID 13520,时间是 231150,local_date 是 1-Dec 。因此,当我在 sql 查询中将 2-Dec 作为参数传递时,您可以看到 13520 id 没有其他行,我想将该行视为 230000 之后的最新行。
  • 以防万一,如果不清楚,我会用更多的数据来解释..

标签: sql oracle function case


【解决方案1】:

我们可以尝试使用ROW_NUMBER 来满足这个要求:

WITH cte AS (
    SELECT t.*, ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY time DESC) rn
    FROM yourTable t
    WHERE system_date = date '2019-12-19'
)

SELECT local_date, system_date, currency, product_id, time, current_price
FROM cte
WHERE rn = 1;

【讨论】:

    【解决方案2】:

    哦,我明白了。 ORDER BY中可以使用两个参数:

    SELECT local_date, system_date, currency, product_id, time, current_price
    FROM (SELECT t.*,
                 ROW_NUMBER() OVER (PARTITION BY product_id
                                    ORDER BY local_date DESC, time DESC
                                   ) as seqnum
          FROM t
          WHERE system_date = @parameter
         ) t
    WHERE rn = 1;
    

    我不确定你是否真的想要这样的日期过滤。你可能想要:

          WHERE system_date <= @parameter
    

    或:

          WHERE system_date < @parameter + interval '1' day
    

    如果在参数指定的日期没有数据,这些将允许您从早期获取数据。如果system_date 具有时间组件(Oracle 中允许date 数据类型使用),第二个版本也可以工作。

    【讨论】:

      【解决方案3】:

      首先,您将日期和时间分开存储,这使得处理日期和时间比需要的复杂。

      将两者结合的一种方法:

      local_date + interval '1' second * (to_number(substr(time, 5, 2)) +
                                          to_number(substr(time, 3, 2)) * 60 +
                                          to_number(substr(time, 1, 2)) * 3600)
      

      另一个:

      to_date(to_char(local_date, 'yyyymmdd') || time, 'yyyymmddhh24miss')
      

      有了这个日期时间,你想要一些类似的东西

      where the_time >= timestamp '2019-12-01 23:00:00' and the_time < date '2019-12-03'
      

      对于运行查询时将提供的一些未知日期:

      where the_time >= :date - interval '1' hour and the_time < :date + interval '1' day
      

      当日,假设表中没有未来数据:

      where the_time >= trunc(sysdate) - interval '1' hour
      

      至于更喜欢当前的日期时间而不是较旧的日期时间,请使用窗口函数,例如MAX OVER.

      with rows_with_datetime as
      (
        select
          mytable.*, 
          to_date(to_char(local_date, 'yyyymmdd') || time, 'yyyymmddhh24miss') as dt
        from mytable
      )
      , two_days_with_maxdatetime as
      (
        select
          rows_with_datetime.*,
          max(dt) over (partition by product_id order by dt) as max_dt
        from rows_with_datetime
        where dt >= trunc(sysdate) - interval '1' hour
      )
      select *
      from two_days_with_maxdatetime
      where dt = max_dt
      order by product_id;
      

      随着日期时间的计算,此处不会使用索引,因此查询可能会很慢。因此,您最好将数据模型更改为具有可以轻松索引和使用的日期时间,而不是单独的日期和时间。如果不能,您可能希望仅在日期上应用额外的冗余条件:

      where local_date >= trunc(sysdate) - interval '1' day
      

      【讨论】:

        【解决方案4】:

        您可以从其他答案扩展这个想法(使用ROW_NUMBER)来定义一个视图,只提供每天最后一次价格的记录。

        您必须在 PARTITION BY 子句中为您提供维度(product_id 和 day),这适用于任何产品和任何一天 - 仅选择具有每天最高时间和产品的行

        create view last_price_per_day as 
        with last_price as (
        select 
          SYSTEM_DATE, PRODUCT_ID, TIME, CURRENT_PRICE,
          row_number() over (partition by PRODUCT_ID, SYSTEM_DATE order by TIME desc) as rn
        from tab)
        select 
          SYSTEM_DATE, PRODUCT_ID, TIME, CURRENT_PRICE
        from last_price
        where rn = 1;
        

        请注意,这种方法优于在相关子查询中使用 MAX(TIME) 的替代方法,因为即使出现平局(更多行具有相同的最高时间),它也能正常工作。

        如果这是一个相关主题,您可以在ORDER BY 子句中添加更多列,例如通过添加CURRENT_PRICE DESC,您将从绑定的行中获得最高价格。

        对此类最后一行视图的一个很好的检查是验证PARTITIEN BYORDER BY 中的列在表中是否唯一。

        在您的情况下,PRODUCT_ID, SYSTEM_DATE, TIME 应该是唯一的,否则视图不是确定性的,并且会在重复查询时返回不同的结果 - 这可能不是您所期望的。

        【讨论】:

          猜你喜欢
          • 2010-09-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-23
          • 2022-06-19
          • 2018-03-12
          • 2021-09-06
          • 1970-01-01
          相关资源
          最近更新 更多