在SQL中每天计算

时间:2016-09-17 09:16:59

标签: sql sqlite aggregate

我有一个像这样的SQL表:

Id    Date     Price
1  21.09.09     25
2  31.08.09     16
1  23.09.09     21
2  03.09.09     12

所以我需要的是获得每个id的最小和最大日期以及它们之间的天数。这很容易。使用SQLlite语法:

  SELECT id, 
         min(date), 
         max(date), 
         julianday(max(date)) - julianday(min(date)) as dif 
  from table group by id

然后是棘手的问题:如何在这个差异期间每天收到价格。我的意思是这样的:

ID Date      PricePerDay
1  21.09.09      25
1  22.09.09       0
1  23.09.09      21
2  31.08.09      16
2  01.09.09       0
2  02.09.09       0
2  03.09.09      12

我按照你提到的日历创建一个cte,但不知道如何获得所需的结果:

WITH RECURSIVE
cnt(x) AS (
 SELECT 0
 UNION ALL
 SELECT x+1 FROM cnt
  LIMIT (SELECT ((julianday('2015-12-31') - julianday('2015-01-01')) + 1)))
SELECT date(julianday('2015-01-01'), '+' || x || ' days') as date FROM cnt

P.S。如果它将是sqllite语法 - 会很棒!

2 个答案:

答案 0 :(得分:3)

您可以使用递归CTE计算最小日期和最大日期之间的所有天数。剩下的就是left join和一些逻辑:

with recursive cte as (
      select t.id, min(date) as thedate, max(date) as maxdate
      from t
      group by id
      union all
      select cte.id, date(thedate, '+1 day') as thedate, cte.maxdate
      from cte
      where cte.thedate < cte.maxdate
     )
select cte.id, cte.date,
       coalesce(t.price, 0) as PricePerDay
from cte left join 
     t
     on cte.id = t.id and cte.thedate = t.date;

答案 1 :(得分:1)

一种方法是使用计数表 构建日期列表并将其与表格连接。

DD.MM.YY格式的日期戳首先更改为YYYY-MM-DD日期格式。
使它们可以在SQL中实际使用它们作为日期 在最终选择时,它们被格式化为DD.MM.YY格式。

首先是一些测试数据:

create table testtable (Id int, [Date] varchar(8), Price int);

insert into testtable (Id,[Date],Price) values (1,'21.09.09',25);
insert into testtable (Id,[Date],Price) values (1,'23.09.09',21);
insert into testtable (Id,[Date],Price) values (2,'31.08.09',16);
insert into testtable (Id,[Date],Price) values (2,'03.09.09',12);

SQL:

with Digits as (
   select 0 as n  
   union all select 1 
   union all select 2 
   union all select 3 
   union all select 4 
   union all select 5 
   union all select 6 
   union all select 7 
   union all select 8 
   union all select 9 
),
t as (
    select Id, 
    ('20'||substr([Date],7,2)||'-'||substr([Date],4,2)||'-'||substr([Date],1,2)) as [Date],
    Price
    from testtable
),
Dates as (
  select Id, date(MinDate,'+'||(d2.n*10+d1.n)||' days') as [Date]
  from (
    select Id, min([Date]) as MinDate, max([Date]) as MaxDate 
    from t 
    group by Id
  ) q
  join Digits d1 
  join Digits d2
  where date(MinDate,'+'||(d2.n*10+d1.n)||' days') <= MaxDate
)
select d.Id, 
(substr(d.[Date],9,2)||'.'||substr(d.[Date],6,2)||'.'||substr(d.[Date],3,2)) as [Date],  
coalesce(t.Price,0) as Price 
from Dates d
left join t on (d.Id = t.Id and d.[Date] = t.[Date])
order by d.Id, d.[Date];

下面的递归SQL完全受到Gordon Linoff的出色答案的启发 无论如何,递归SQL可能更适合这种情况 (他应该得到15分的接受答案) 此版本的不同之处在于日期戳首先被格式化为YYYY-MM-DD。

with t as (
    select Id, 
    ('20'||substr([Date],7,2)||'-'||substr([Date],4,2)||'-'||substr([Date],1,2)) as [Date],
    Price
    from testtable
),
cte as (
  select Id, min([Date]) as [Date], max([Date]) as MaxDate from t
  group by Id
  union all
  select Id, date([Date], '+1 day'), MaxDate from cte
  where [Date] < MaxDate
)
select cte.Id, 
(substr(cte.[Date],9,2)||'.'||substr(cte.[Date],6,2)||'.'||substr(cte.[Date],3,2)) as [Date], 
coalesce(t.Price, 0) as PricePerDay
from cte
left join t
  on (cte.Id = t.Id and cte.[Date] = t.[Date])
order by cte.Id, cte.[Date];