我需要搜索所有的值,找到丢失的一个,替换空值,并添加适当的日期,它的新值.

Date Price
3/5/2020 40
5/5/2020 null
7/5/2020 30
30/5/2020 null
1/6/2020 null
3/6/2020 null
5/6/2020 55
Date Price PriceDate
3/5/2020 40 null
5/5/2020 40 3/5/2020
7/5/2020 30 null
30/5/2020 30 7/5/2020
1/6/2020 55 5/6/2020
3/6/2020 55 5/6/2020
5/6/2020 55 null

重点是-对于5月,我需要替换下一个值,对于6月,我需要从6月5日开始取值,并替换前几天的值. 在这两种情况下,我还需要添加包含Date From值的附加列.

我的问题是:如何从以前的日期获取值-在本例中是6月并替换它们,以及如何在该日期(PriceDate)列中添加额外的值?

我也做了一些更改,能够获得我想要的值,但我想知道如何获得这个日期的正确日期(请参见第二个表-作为输出):

https://sqlfiddle.com/sql-server/online-compiler

到目前为止,我所做的是:

CREATE TABLE Sale (
    DatePrice DATE,
    Price FLOAT
);

INSERT INTO Sale (DatePrice, Price) VALUES
('2020-05-02', NULL),
('2020-05-03', 40.00),
('2020-05-05', NULL),
('2020-05-06', NULL),
('2020-05-07', 30.00),
('2020-05-30', NULL),
('2020-06-01', NULL),
('2020-06-03', NULL),
('2020-06-05', 55.00),
('2020-06-06', 60.00),
('2020-06-09', NULL),
('2020-07-02', 72.00),
('2020-07-04', NULL),
('2020-07-06', NULL),
('2020-07-07', NULL),
('2020-07-19', 80.00);


IF OBJECT_ID('tempdb..#FilledPrices') IS NOT NULL DROP TABLE #FilledPrices;
SELECT
    DatePrice,
    Price,
    YEAR(DatePrice) AS Year,
    MONTH(DatePrice) AS Month,
    NULL AS FilledPrice 
INTO #FilledPrices
FROM Sale;


WITH FirstPrices AS (
    SELECT
        Year,
        Month,
        MIN(DatePrice) AS FirstDate
    FROM #FilledPrices
    WHERE Price IS NOT NULL
    GROUP BY Year, Month
)
UPDATE fp
SET fp.FilledPrice = s.Price
FROM #FilledPrices fp
INNER JOIN FirstPrices f ON fp.Year = f.Year AND fp.Month = f.Month
INNER JOIN Sale s ON s.DatePrice = f.FirstDate
WHERE fp.Price IS NULL AND fp.DatePrice <= f.FirstDate;


UPDATE fp
SET fp.FilledPrice = (
    SELECT TOP 1 Price
    FROM #FilledPrices
    WHERE Year = fp.Year AND Month = fp.Month AND DatePrice < fp.DatePrice AND Price IS NOT NULL
    ORDER BY DatePrice DESC
)
FROM #FilledPrices fp
WHERE fp.Price IS NULL AND fp.FilledPrice IS NULL;


UPDATE #FilledPrices
SET FilledPrice = Price
WHERE Price IS NOT NULL;

SELECT
    DatePrice,
    COALESCE(FilledPrice, Price) AS Price
FROM #FilledPrices
ORDER BY DatePrice;

我在本例中使用的是临时表.First Off-我在第一个数据记录之前的特定月份搜索空值.如果出现这种情况,请将空值替换为First Met值.在第二次迭代中,我搜索所有值,如果找到空值,则将其替换为前一条记录中的值.我的结果是,这个方法运行得很好:

DatePrice Price
2020-05-02 40.0
2020-05-03 40.0
2020-05-05 40.0
2020-05-06 40.0
2020-05-07 30.0
2020-05-30 30.0
2020-06-01 55.0
2020-06-03 55.0
2020-06-05 55.0
2020-06-06 60.0
2020-06-09 60.0
2020-07-02 72.0
2020-07-04 72.0
2020-07-06 72.0
2020-07-07 72.0
2020-07-19 80.0

我需要做的最后一件事是使用PriceDate创建额外的表,并为具有空值的记录填充日期,这些记录的日期是我们从记录中获取的值,对于没有更改的记录,将日期值保留为空值-请参见示例作为POST中的第二个表作为示例.

推荐答案

您可以通过查找当前行中价格为beforemaximum日期来解决这个问题--对于当前月份内存在较早记录的所有情况.

然后,为了处理当月不存在价格在该月内的早期记录的情况,您可以找到当前行中价格为after的日期为minimum的日期.

通常,您将使用ID列来执行此操作,但只要日期是唯一的,它就会起作用.

然后,对于价格为空的行,如果存在较早的价格,则将其加入,如果不存在,则将其加入较晚的日期.

通过联接原始行,您可以访问所有列以执行任何您想要的操作.

注为了演示,我在样例数据中添加了额外的一行.

CREATE TABLE dbo.Sale (
    DatePrice DATE,
    Price DECIMAL(9,2)
);

INSERT INTO dbo.Sale (DatePrice, Price)
VALUES
('2020-05-03', 40.00),
('2020-05-05', NULL),
('2020-05-06', NULL),
('2020-05-07', 30.00),
('2020-05-30', NULL),
('2020-06-01', NULL),
('2020-06-03', NULL),
('2020-06-05', 55.00);

WITH SalesWithMonth AS (
    SELECT
        DatePrice
        , Price
        -- Find the closest row with a price prior to this row
        , MAX(CASE WHEN Price IS NOT NULL THEN DatePrice END) OVER (
            PARTITION BY YEAR(DatePrice), MONTH(DatePrice)
            ORDER BY DatePrice
            ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
        ) MaxDatePrice
        -- Find the closest row with a price after this row
        , MIN(CASE WHEN Price IS NOT NULL THEN DatePrice END) OVER (
            PARTITION BY YEAR(DatePrice), MONTH(DatePrice)
            ORDER BY DatePrice
            ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
        ) MinDatePrice
    FROM dbo.Sale
)
SELECT
    swm.DatePrice [Date]
    , coalesce(s.Price, swm.Price) Price
    , s.DatePrice PriceDate
FROM SalesWithMonth swm
LEFT JOIN dbo.Sale s
    ON s.DatePrice = CASE WHEN swm.Price IS NULL THEN COALESCE(MaxDatePrice, MinDatePrice) END
ORDER BY swm.DatePrice;

返回:

Date Price PriceDate
2020-05-03 40.00 NULL
2020-05-05 40.00 2020-05-03
2020-05-06 40.00 2020-05-03
2020-05-07 30.00 NULL
2020-05-30 30.00 2020-05-07
2020-06-01 55.00 2020-06-05
2020-06-03 55.00 2020-06-05
2020-06-05 55.00 NULL

注意:永远不要用FLOAT来表示金钱,从那时起,你将面临舍入误差的问题.使用DECIMAL.

DBFiddle

Sql相关问答推荐

SQL查询以创建手头的流动余额?

如何用3个(半)固定位置建模团队,并有效地搜索相同/不同的团队?

Postgres:对包含数字的字符串列表进行排序

如何在snowflake中进行SQL的反向填充

SQL:如何取上一年的平均值?

SQL:如何在表中同时使用GROUPING和CONDITION?

如何使用SQL Server中的Nodes()方法执行与OPENXML相同的操作

其中使用表名作为;行值;记录?

输出连续出现两次以上的行

具有分组条件的不同计数 (DAX)

SQL 搜索 - 获取最大值日期的奇怪行为

如何在sparksql查询中使用日期值?

Postgres存在限制问题「小值」

为重复的项目编号显示正在处理

使用 regexp_replace 替换所有出现的特殊字符

如果 SQL 中不存在数据,如何根据某个 ID 为所有日期添加前一行

以 15 分钟为间隔的使用情况SQL 查询

Postgres 窗口函数未按预期工作

如何比较同一张表中的行并进行相应更新

当我按 PK 分组时,该表中的所有列在每个组中都具有相同的值.那么为什么 SQL Server 需要对这些列进行聚合呢?