上一行结束日期作为SQL

时间:2016-09-30 14:42:42

标签: sql postgresql amazon-redshift

需要一些帮助,请

我有一个名为'hist_lastupdated'的字段,其中包含修改产品价格的最后更新日期。

基于此字段,我想提取修改的开始日期和结束日期。 enter image description here

事实上我有这个:

**Product_id , Price ,        hist_lastupdated**
284849       18.95          2015-05-29 00:53:55
284849       15.95          2015-08-14 01:04:46
284849       18.95          2016-06-11 00:50:31
284849       15.95          2016-08-24 00:45:11

我希望得到这样的结果:

**Product_id , Price ,   hist_lastupdated    ,start_date  ,           End_date**
284849  18.95  2015-05-29 00:53:55  2014-05-01 00:00:00   2015-05-29 00:53:55  
284849  15.95  2015-08-14 01:04:46  2015-05-29 00:53:55   2015-08-14 01:04:46
284849  18.95  2016-06-11 00:50:31  2015-08-14 01:04:46   2016-06-11 00:50:31
284849  15.95  2016-08-24 00:45:11  2016-06-11 00:50:31   2016-08-24 00:45:11

用两个词来说,开始日期是上一行的结束日期 我有很多产品ID

4 个答案:

答案 0 :(得分:1)

这样的事情:

select Product_id, 
       Price,        
       hist_lastupdated, 
       lag(hist_lastupdated) over (partition by product_id order by hist_lastupdated) as start_date, 
       hist_lastupdated as end_date
from the_table

您没有解释计算第一列的start_date的位置。如果那是从hist_lastupdated开始的月份,您可以执行以下操作:

lag(hist_lastupdated, 1, date_trunc('month', hist_lastupdated)) over (...)

答案 1 :(得分:0)

我不确定如何只使用SQL来执行此操作,但如果您能够执行一些脚本编写,则可以编写一个类似于此的快速程序(伪代码):

lines = execute(SELECT product_id, price, hist_lastupdated FROM ProductTable)

startDate = 00:00:00 2014-05-01

outputLines = []

for row in lines:

    outLine = []
    outline.append(row[0])
    outline.append(row[1])
    outline.append(row[2])
    outline.append(startDate)
    outline.append(row[2])

    startDate = row[2]

#Now do what you want with the output you have in a nice list of lists in the format you need, insert into a different table, write to a file, whatever you want.

答案 2 :(得分:0)

我会在MS SQL Server中使用其中一种解决方案。希望其中一个适用于您的问题。

纯SQL语句如下所示:

select
    t.product_id, t.price, s.start_date, t.end_date
from 
    product t
    outer apply
    (
        select top 1 
            end_date start_date
        from
            product o
        where
            o.end_date < t.end_date
        order by
            o.end_date desc
    ) s

即使索引良好,返回的每个记录的交叉申请也可能是性能问题。

如果您的SQL Server支持LAG功能:

select
    t.product_id, t.price, 
    LAG(T.end_date) over (order by t.end_date),
    t.end_date
from 
    product t

或者您可以找到一种方法,使用update语句中的变量执行相同的操作,以“记住”先前更新的记录中的值,如T-SQL:

-- Insert the desired output into a table variable that also has a start_date field.
-- Be sure to insert the records ordered by the date value.

declare @output table (product_id int, price numeric(10,2), [start_date] datetime, [end_date] datetime)

insert @output (product_id, price, end_date)
select 1, 10, '1/1/2015'
union all select  2, 11, '2/1/2015'
union all select 3, 15, '3/1/2015'
union all select 4, 20, '4/1/2015'
order by 3

-- Update the start date using the end date from the previous record
declare @start_date datetime, @end_date datetime

update 
    @output
set
    @start_date = @end_date,
    @end_date = end_date,
    start_date = @start_date

select * from @output

我不认为这种技术是微软推荐的,但它对我起到了很好的作用并且始终如一。我只将这种技术用于表变量。我不太愿意相信实际表中记录的更新顺序。现在我会使用LAG()代替。

答案 3 :(得分:0)

enter image description here

这是我找到它的解决方案,我想使用滞后函数,但结果不是我想要的。

解决方案:

WITH 
price_table_1 as (
   select
   -1 + ROW_NUMBER() over (partition by t1.product_id,t1.id ,t1.channel_id)  as rownum_w1,
   t1.id,
   t1.product_id,
   t1.channel_id,
   t1.member_id,
   t1.quantity,
   t1.price,
   t1.promo_dt_start,
   t1.promo_dt_end,
   t1.hist_lastupdated
FROM dwh_prod.hist_prices t1
where   t1.channel_id='1004' and t1.product_id = '5896'  and t1.quantity = '1' and t1.promo_dt_start is null
order by t1.product_id,t1.channel_id,t1.hist_lastupdated
),price_table_2 as (
   select
   ROW_NUMBER() over (partition by t2.product_id,t2.id ,t2.channel_id) as     rownum_w2,
   t2.id,
   t2.product_id,
   t2.channel_id,
   t2.member_id,
   t2.quantity,
   t2.price,
   t2.promo_dt_start,
   t2.promo_dt_end,
   t2.hist_lastupdated
FROM dwh_prod.hist_prices t2
where    t2.channel_id='1004' and t2.product_id = '5896'  and t2.quantity = '1' and t2.promo_dt_start is null
order by t2.product_id,t2.channel_id,t2.hist_lastupdated
)

   select
   t1.id,
   t1.product_id,
   t1.channel_id,
   t1.member_id,
   t1.quantity,
   t1.price,
   t1.promo_dt_start,
   t1.promo_dt_end,
   t2.hist_lastupdated as start_date,
   t1.hist_lastupdated as end_date

FROM price_table_1 t1
inner join price_table_2 t2
on t2.product_id = t1.product_id and t2.id = t1.id and t2.channel_id =        t1.channel_id
and rownum_w1 = (rownum_w2)
UNION ALL
select
   t1.id,
   t1.product_id,
   t1.channel_id,
   t1.member_id,
   t1.quantity,
   t1.price,
   t1.promo_dt_start,
   t1.promo_dt_end,
   CONVERT(TIMESTAMP,'2014-01-01') as start_date,
   t1.hist_lastupdated as end_date

FROM price_table_1 t1 
where rownum_w1 = '0';