Sql 显示最新的视图 + 如果数据集中不存在,则为第一天创建行

Sql view that shows latest + creates row for first day if not present in dataset

我有以下数据:

Date Store Product Price
d1   s1    p1      0
d1   s1    p2      0
d1   s2    p1      0
d2   s1    p1      0
...

因此,数百万行数据包含具有特定日期价格的商店-产品对。 我想创建一个视图,为我提供最近 X 天的数据。像这样的东西很容易:

SELECT * FROM TableName WHERE date > DATEADD(day, -X, GETDATE())

但我还需要确保对于每个商店-产品对,我实际上都有所有 X 天的条目。因此,如果在 today-X 天没有某个商店和产品对的条目,我需要找到该对的最新价格(如果存在),然后将该价格复制到 date = today - X 的行中。这有意义吗?

我会从左到右开始,我的意思是:

为你的日期范围建立一个日历 -> 建立(如果你没有)每个产品商店组合的列表 -> 然后将这 2 个数据集与你的实际 table 结合起来,其余的应该是简单。

检查此方法:

DECLARE @MinDate DATE = DATEADD(DAY, -5, CONVERT(DATE, GETDATE())),
        @MaxDate DATE = CONVERT(DATE, GETDATE())

SELECT  DISTINCT
        MYDATES.DATE,
        MYDATES.STORE,
        MYDATES.PRODUCT,
        --GET LATEST PRICE FOR THE COUPLE PRODUCT-STORE IF THERE IS NOONE IN SELECTED DATE
        CASE    WHEN T.PRICE IS NULL
                THEN (  SELECT MAX(T1.PRICE)
                        FROM MYTAB T1
                        WHERE T1.STORE = MYDATES.STORE
                        AND T1.PRODUCT = MYDATES.PRODUCT
                        AND T1.DATE = ( SELECT MAX(DATE)
                                        FROM MYTAB T2
                                        WHERE T2.PRODUCT = MYDATES.PRODUCT
                                        AND T2.STORE = MYDATES.STORE))
                ELSE T.PRICE END AS PRICE, 
        CASE    WHEN T.PRICE IS NULL
                THEN 'RECOVERED FROM ' + (  SELECT CONVERT(VARCHAR, MAX(DATE), 103)
                                        FROM MYTAB T2
                                        WHERE T2.PRODUCT = MYDATES.PRODUCT
                                        AND T2.STORE = MYDATES.STORE)
                ELSE ''
                END AS [PRICE FROM]

FROM (SELECT * FROM STOREANDPRODSOURCE SP, 
(SELECT TOP (DATEDIFF(DAY, @MinDate, @MaxDate) + 1)
        Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, @MinDate)
FROM    sys.all_objects a
        CROSS JOIN sys.all_objects b) D ) MYDATES
LEFT JOIN MYTAB T ON CONVERT(DATE, T.DATE) = MYDATES.DATE
                     AND T.PRODUCT = MYDATES.PRODUCT
                     AND T.STORE = MYDATES.STORE

也勾选SQL Fiddle

如果我理解这个问题,那么对于这个样本数据

CREATE TABLE t1
    ([Date] DATE, [Store] varchar(2), [Product] varchar(2), [Price] int)
;

INSERT INTO t1
    ([Date], [Store], [Product], [Price])
VALUES
    ('20180525', 's1', 'p3', 0),
    ('20180601', 's1', 'p1', 0),
    ('20180602', 's1', 'p2', 0),
    ('20180603', 's2', 'p1', 0),
    ('20180604', 's1', 'p1', 0)
;

DECLARE @NumOfDays INT = 10

OP 想要显示 ('20180525', 's1', 'p3', 0) 行,因为这是 DATEADD( DAY, -@NumOfDays, GETDATE()) 天前

所以试试这个解决方案

SELECT
     --T.Date
     [Date] = CAST(DATEADD( DAY, -@NumOfDays, GETDATE()) AS DATE)
    ,T.Store
    ,T.Product
    ,T.Price
FROM dbo.t1 T
INNER JOIN(
    SELECT Mxdate = MAX(T2.Date), T2.Store, T2.Product
    FROM dbo.t1 T2
    GROUP BY T2.Store, T2.Product
) MxDate ON MxDate.Product = T.Product AND MxDate.Store = T.Store
WHERE MxDate.Mxdate < DATEADD( DAY, -@NumOfDays, GETDATE())
UNION
SELECT
     T3.Date
    ,T3.Store
    ,T3.Product
    ,T3.Price
FROM dbo.t1 T3
WHERE T3.Date > DATEADD( DAY, -@NumOfDays, GETDATE())

输出

Date        Store   Product Price
2018-05-27  s1      p3      0       --this is the row before the daterange
2018-06-01  s1      p1      0
2018-06-02  s1      p2      0
2018-06-03  s2      p1      0
2018-06-04  s1      p1      0