获取SQL Server 2008 R2中某列的最后两个非空值

获取SQL Server 2008 R2中某列的最后两个非空值,sql,sql-server,sql-server-2008-r2,Sql,Sql Server,Sql Server 2008 R2,现在,我有一个select语句返回这个结果集: | date | id | price | +--------+-----+-------+ | Jan 01 | XYZ | 5.00 | | Jan 02 | XYZ | NULL | | Jan 03 | XYZ | NULL | | Jan 06 | XYZ | NULL | | Jan 07 | XYZ | 3.00 | | Jan 08 | XYZ | NULL | 问题是,如果该值为空,我希望获得该行中id为XYZ

现在,我有一个select语句返回这个结果集:

|  date  | id  | price |
+--------+-----+-------+
| Jan 01 | XYZ | 5.00  |
| Jan 02 | XYZ | NULL  |
| Jan 03 | XYZ | NULL  |
| Jan 06 | XYZ | NULL  |
| Jan 07 | XYZ | 3.00  |
| Jan 08 | XYZ | NULL  |
问题是,如果该值为空,我希望获得该行中id为XYZ的产品的最后一个已知价格,但只有在两天内才能获取该价格。因此,对于02年1月和03年1月,我希望看到01年1月的值,但不是06年1月的值

我的意思是:

|  date  | id  | price |
+--------+-----+-------+
| Jan 01 | XYZ | 5.00  |
| Jan 02 | XYZ | 5.00  | (Jan 01)
| Jan 03 | XYZ | 5.00  | (Jan 01)
| Jan 06 | XYZ | NULL  | << Stays NULL
| Jan 07 | XYZ | 3.00  |
| Jan 08 | XYZ | 3.00  | (Jan 07)
以及样本数据:

INSERT  INTO dbo.catalogue
    ( [date], [id], [price] )
VALUES  
    ( '2015-01-01', 'XYZ', 5.00 ),
    ( '2015-01-02', 'XYZ', NULL ),
    ( '2015-01-03', 'XYZ', NULL ),
    ( '2015-01-06', 'XYZ', NULL ),
    ( '2015-01-07', 'XYZ', 3.00 ),
    ( '2015-01-08', 'XYZ', NULL )
编辑:另外,我应该提到这是在存储过程的子查询中,所以性能肯定很重要


提前感谢。

如果您使用的是2012+版本,使用LAG会更容易一些,但您可以在2008年使用cte来实现这一点。感谢您发布耗材ddl和样本数据。这样做容易多了

这里有一种方法可以做到这一点

with cte as
(
    select *
        , ROW_NUMBER() over (partition by id order by date) as RowNum
    from catalogue
)

select c.date
    , c.id
    , isnull(case when DATEDIFF(day, c2.date, c.date) <= 2 
        then 
        (
            select MAX(price) from cte c3 
            where c3.RowNum >= c2.RowNum - 1
        )
        end, c.price) as NewPrice
from cte c
left join cte c2 on c2.RowNum = c.RowNum - 1
另一个使用APPLY的解决方案:


缺少的日期行中的id列不是也为NULL吗?@Amit我给出的查询示例不正确。很抱歉造成混淆。什么版本的sql server?如果您以可消费的格式发布ddl和示例数据,这样我们就可以对其生成查询,这会容易得多。@SeanLange更新为version.ddl=数据定义语言创建表/对象脚本。DML=数据操作语言CRUD这是一篇关于这方面的优秀文章。你能用Lag发布一个答案吗?我想我们可能会很快升级我们的服务器,我一定会回来尝试使用Lag
with cte as
(
    select *
        , ROW_NUMBER() over (partition by id order by date) as RowNum
    from catalogue
)

select c.date
    , c.id
    , isnull(case when DATEDIFF(day, c2.date, c.date) <= 2 
        then 
        (
            select MAX(price) from cte c3 
            where c3.RowNum >= c2.RowNum - 1
        )
        end, c.price) as NewPrice
from cte c
left join cte c2 on c2.RowNum = c.RowNum - 1
SELECT  
    c.[date],
    c.id,
    price = ISNULL(c.price, x.price)
FROM dbo.catalogue c
OUTER APPLY(
    SELECT TOP 1 price
    FROM dbo.catalogue
    WHERE 
        DATEDIFF(DAY, [date], c.[date]) <= 2
        AND c.[date] > [date]
        AND id = c.id
    ORDER BY date DESC
)x