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

时间:2015-08-24 20:14:06

标签: 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  |

问题在于,如果值为XYZ,我想获取行中ID为NULL的产品的最后一个已知价格,但是如果它在两个范围内,则仅获取此值天。因此Jan 02& Jan 03我希望看到Jan 01的价值,而不是Jan 06

这就是我的意思:

|  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)

以下是表格定义:

CREATE TABLE dbo.catalogue
(
  [date] DATE NOT NULL ,
  [id] VARCHAR(3) NOT NULL ,
  [price] FLOAT
)

样本数据:

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 )

编辑:另外,我应该提一下,这是在存储过程的子查询中,所以性能肯定很重要。

提前致谢。

2 个答案:

答案 0 :(得分:3)

使用APPLY的另一种解决方案:

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

答案 1 :(得分:2)

如果您使用的是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