在左联接为空的情况下如何重复值

时间:2020-05-29 12:08:01

标签: sql-server

我有一个带日历的桌子和一个带利率的桌子。在包含费率的表中,周末中没有几天的值存在。我正在尝试将两者合并,以便获得一个表格,列出所有天的费率,我需要将周末的费率作为最新的费率。它的Instad显示NULL值,就像您进行左连接并且该记录不存在时一样,它应该只取最新的可用值,并重复先前的值。

我有下面的代码,可以正常工作,但是在7,397行上需要2分钟,这太长了。

有人知道更快的方法来获得相同的结果吗?

SELECT
c.CalendarID, 
MAX(r.RateID)

FROM Dim_Calendar c

LEFT JOIN Dim_Rates r ON r.RateDate <= c.CalendarID

在没有<=而只有=的情况下,我得到的是以下内容

CalendarID | RateID
20131001   | 2
20131002   | 3
20131003   | 4
20131004   | 5
20131005   | NULL
20131006   | NULL
20131007   | 6

这是所需的表:

CalendarID | RateID
20131001   | 2
20131002   | 3
20131003   | 4
20131004   | 5
20131005   | 5
20131006   | 5
20131007   | 6

3 个答案:

答案 0 :(得分:1)

您可以使用相关的子查询来填补空白:

SELECT
    c.CalendarID, 
    (SELECT TOP 1 r.RateID FROM Dim_Rates r
     WHERE r.RateDate <= c.CalendarID AND r.RateID IS NOT NULL
     ORDER BY r.RateDate DESC) AS RateID
FROM Dim_Calendar c
ORDER BY c.CalendarID;

可以使用以下索引改进此查询:

CREATE INDEX idx ON Dim_Rates (RateDate, RateID);

答案 1 :(得分:1)

您可以使用LAG()窗口功能:

SELECT c.CalendarID,
  COALESCE(
    r.RateID,
    LAG(r.RateID, 1) OVER (ORDER BY c.CalendarID),
    LAG(r.RateID, 2) OVER (ORDER BY c.CalendarID)
  ) RateID
FROM Dim_Calendar c LEFT JOIN Dim_Rates r 
ON r.RateDate = c.CalendarID
ORDER BY c.CalendarID

请参见demo
结果:

> CalendarID | RateID
> ---------: | :-----
>   20131001 | 2     
>   20131002 | 3     
>   20131003 | 4     
>   20131004 | 5     
>   20131005 | 5     
>   20131006 | 5     
>   20131007 | 6  

答案 2 :(得分:0)

如前所述,您需要检查索引是否正确和覆盖范围。看来您正在针对DW DB运行a,如果是这种情况,那么如果查询计划中估计的行数估算值不理想,则可以用索引临时表替换CTE。

;WITH NormalizedData AS
(
    SELECT
        RateID,CalendarID,
        VirtualGroupID = SUM(LastRecordBeforeGap) OVER (ORDER BY CalendarID ROWS UNBOUNDED PRECEDING)
    FROM
    (
        SELECT RateID,CalendarID,
        LastRecordBeforeGap = CASE WHEN LEAD(RateID) OVER(ORDER BY CalendarID) IS NULL AND RateID IS NOT NULL THEN 1 ELSE 0 END
        FROM
            Dim_Calendar  c
            LEFT JOIN Dim_Rates  r ON r.RateDate = c.CalendarID
    )AS x
)

SELECT 
    RateID = ISNULL(RateID, SUM(RateID) OVER(PARTITION BY VirtualGroupID)),
    CalendarID 
FROM 
    NormalizedData