SQL根据连续日期获取值的变化

Posted

技术标签:

【中文标题】SQL根据连续日期获取值的变化【英文标题】:SQL get change in values based on consecutive dates 【发布时间】:2012-05-12 11:40:15 【问题描述】:

我想获得每天的价格变化。什么 SQL 查询将完成此操作?

原表

Date       Company    Price
---------------------------
1/4/2012   Apple      458
1/3/2012   Apple      462
1/2/2012   Apple      451
1/1/2012   Apple      450

想要的表

Date       Company    Price   Day_Change
-------------------------------------
1/4/2012   Apple      458     -4    
1/3/2012   Apple      462     9
1/2/2012   Apple      451     1
1/1/2012   Apple      450     NULL

【问题讨论】:

您的结果不正确。 451 - 450 = 1(正确),462 - 451 = 9(错误) 【参考方案1】:

将表连接到自身以获得该公司昨天的价格,然后从今天的价格中减去它

select
    t1.date,
    t1.company,
    t1.price,
    t1.price - t2.price as day_change
from price_table t1
left join price_table t2 
    on t2.date = subdate(t1.date, 1)
    and t2.company = t1.company

在此之后您可以添加一个普通的where 子句,例如where t1.date > subdate(current_date(), 7) 以获取最近 7 天的价格

仅供参考,如果昨天的价格没有一行,day_change 将是 NULL

【讨论】:

关于 仅供参考,如果昨天的价格没有一行,day_change 将为 NULL,请考虑我的回答 :-) ***.com/a/10423889 @MichaelBuen 如果您仔细阅读问题,您会发现NULL 正是他想要的 - 请参阅 OP 示例输出的最后一行 :) 他的NULL 与您的查询相比,并不是因为数据不连续。我推断他的NULL 可能只是表明该行是趋势中的第一行:-) 我也可以这样做;-) 该死,你是对的,虽然你说它在输出的最后一行,但标题说明了一切SQL get change in values based on 连续日期【参考方案2】:

另一种方法,即使在不连续的日期也可以工作:

来源数据:

CREATE TABLE fluctuate
    (Date datetime, Company varchar(10), Price int);

INSERT INTO fluctuate
    (Date, Company, Price)
VALUES
    ('2012-01-04 00:00:00', 'Apple', 458),
    ('2012-01-03 00:00:00', 'Apple', 462),
    ('2012-01-02 00:00:00', 'Apple', 451),
    ('2012-01-01 00:00:00', 'Apple', 450),
    ('2012-01-01 00:00:00', 'Microsoft', 1),
    ('2012-01-03 00:00:00', 'Microsoft', 7),
    ('2012-01-05 00:00:00', 'Microsoft', 5),
    ('2012-01-07 00:00:00', 'Microsoft', 8),
    ('2012-01-08 00:00:00', 'Microsoft', 12);

输出:

DATE                       COMPANY             PRICE               DAY_CHANGE
January, 04 2012           Apple               458                 -4
January, 03 2012           Apple               462                 11
January, 02 2012           Apple               451                 1
January, 01 2012           Apple               450                 NULL
January, 08 2012           Microsoft           12                  4
January, 07 2012           Microsoft           8                   3
January, 05 2012           Microsoft           5                   -2
January, 03 2012           Microsoft           7                   6
January, 01 2012           Microsoft           1                   NULL

查询:

select 

date, 
company, 
price, 
day_change

from
(    
  select 

     case when company <> @original_company then 
         -- new company detected, 
         -- reset the original price based on the new company
         @original_price := null
     end,
    f.*,
    price - @original_price as day_change,
    (@original_price := price),
    (@original_company := company)


  from fluctuate f

  cross join
  (
    select 
     @original_price := null,
     @original_company := company
     from fluctuate 
     order by company, date limit 1
  )
  as zzz

  order by company, date 

) as yyy
order by company, date desc

来源:http://www.sqlfiddle.com/#!2/56de3/3

【讨论】:

【参考方案3】:

@Bohemian 的回答是正确的,将返回自前一天以来的价格差异,但实际上我怀疑您实际上会想要自前一天交易以来的价格差异(可能跨越周末、公共假期)等)。

要做到这一点,必须首先使用子查询来确定每家公司交易的最后一天(个别公司可以暂停交易,或者可能在不同的市场交易受不同的假期);然后使用 (date,company) 对来查找最新价格...

SELECT current.*, current.Price - previous.Price AS Day_Change
FROM (
    SELECT yourtable.*, MAX(before.Date) AS prevDate
    FROM
           yourtable
      JOIN yourtable AS before
            ON before.Date    < yourtable.Date
           AND before.Company = yourtable.Company
    GROUP BY yourtable.Date, yourtable.Company
  ) AS current
  JOIN yourtable AS previous
        ON previous.Date   = current.prevDate
       AND previous.Company= current.Company

【讨论】:

由于相关子查询(您有“n”个查询),这将表现不佳。最好使用用户定义的变量,并且只在表格上进行一次传递。 没错,这将表现不佳。仅靠基于集合的思维方式无法直接处理某些类型的查询。一个例子,请看 Adam Machanic sqlblog.com/blogs/adam_machanic/archive/2006/07/12/… 的这个运行总和 关于但实际上我怀疑您实际上会想要自前一天交易以来的价格差异(可能跨越周末、公共假期等),请参阅我的方法:@ 987654322@

以上是关于SQL根据连续日期获取值的变化的主要内容,如果未能解决你的问题,请参考以下文章

Oracle sql查询需要根据时区变化

使用jmeter实现当前日期连续增加达到连续签到目的

从十进制 (8, 0) 格式的日期获取 n-3 或 n-x 个月(约 90 天前),在 SQL Server 和 DB2 中具有年份变化影响

SQL server:如何计算每个观察的最大连续变化

根据列值的变化对pyspark数据框进行分区

SQL 状态随开始日期和结束日期而变化