如何在 SQL Server 中重复上次日期中缺失日期的行?

问题描述 投票:0回答:2

我在工作日有每个帐户的余额,我需要计算

Avg_Balance
,但我需要计算该月的所有日子,包括周末,缺少数据。我想重复丢失日期的帐户的最后可用余额。

例如:

B日期 客户关系管理 ACCT 巴尔
2023-10-24 123 ab123 1000
2023-10-25 123 ab123 1100
2023-10-27 123 ab123 1200
2023-10-28 123 ab123 1300

如您所见,2023-10_26的数据丢失,我想复制2023-10-25的数据,但日期为2023-10-26,如下所示。

B日期 客户关系管理 ACCT 巴尔
2023-10-24 123 ab123 1000
2023-10-25 123 ab123 1100
2023-10-26 123 ab123 1100
2023-10-27 123 ab123 1200
2023-10-28 123 ab123 1300

如何在 SQL Server 查询中执行此操作?我将感谢您的帮助。

t-sql sql-server-2012 ssms
2个回答
0
投票

您的查询可以通过表变量和 while 循环来实现。使用 MIN 和 MAX 获取计算所需的日期范围,您的 while 循环可以简单地检查相关日期是否存在数据,如果不存在,则使用 DATEADD() 函数获取前几天的数据。我已经包括了如何实现下面的结果,但必须对表的结构做出一些假设。

--  Create a table variable to store the data...
DECLARE @CheckBalance AS TABLE
(
    BDate DATE NOT NULL,
    CRM VARCHAR(3) NOT NULL,
    ACCT VARCHAR(5) NULL,
    BAL INT
);

DECLARE @StartDate DATE, @EndDate DATE, @WorkingDate DATE;
--  Get the starting date and the end date you want to calculate...
--  Add an extra day to the end date for the while loop check.
SELECT @StartDate = MIN(BDate), @EndDate = DATEADD(DAY, 1, MAX(BDate)) FROM RunningBalance;

SELECT @WorkingDate = @StartDate;

WHILE @WorkingDate < @EndDate
BEGIN

    IF NOT EXISTS(SELECT 1 FROM RunningBalance WHERE BDate = @WorkingDate)
    BEGIN
        --  Since the data is missing from the WorkingDate, insert the previous days data.
        INSERT INTO @CheckBalance (BDate, CRM, ACCT, BAL)
            SELECT @WorkingDate AS BDate, CRM, ACCT, BAL FROM RunningBalance WHERE BDate = DATEADD(DAY, -1, @WorkingDate);
    END
    ELSE
    BEGIN
        --  Data exists, insert that.
        INSERT INTO @CheckBalance (BDate, CRM, ACCT, BAL)
            SELECT BDate, CRM, ACCT, BAL FROM RunningBalance WHERE BDate = @WorkingDate;
    END

    SELECT @WorkingDate = DATEADD(DAY, 1, @WorkingDate);

END

SELECT BDate, CRM, ACCT, BAL FROM @CheckBalance;

0
投票

假设您有一个日期维度表,您可以加入该表以获得一个包含间隙和岛屿的表。然后将有多个选项来填补空白(NULL 值)。这是一个经典的:

首先,让我们构建您的示例:

CREATE TABLE RUNNUNG_BALANCE_TABLE (
  BDATE DATE NOT NULL,
  CRM INT,
  ACCT NVARCHAR(5),
  BAL INT
);

INSERT INTO RUNNUNG_BALANCE_TABLE
VALUES
  ('2023-10-24',123,'ab123',1000),
  ('2023-10-25',123,'ab123',1100),
  ('2023-10-27',123,'ab123',1200),
  ('2023-10-28',123,'ab123',1300);

CREATE TABLE DIM_DATE (
  DATEKEY INT NOT NULL,
  DATE_ISO DATE NOT NULL
);

INSERT INTO DIM_DATE
VALUES
  (20231024,'2023-10-24'),
  (20231025,'2023-10-25'),
  (20231026,'2023-10-26'),
  (20231027,'2023-10-27'),
  (20231028,'2023-10-28'),
  (20231029,'2023-10-29'),
  (20231030,'2023-10-30');

然后,我们使用通用表表达式 (CTE) 将财务数据表与包含日期值的表连接起来,并创建一个新列来标记条目组。我们通过使用 OVER 子句和 COUNT 作为聚合函数来实现这一点。我们使用此列来确定“最后可用”数据。我们可以在这里使用 MIN(),因为任何值总是大于 NULL。

WITH CTE AS (
  SELECT 
    DATE_ISO,
    CRM,
    ACCT,
    BAL,
    COUNT(CASE WHEN BAL IS NOT NULL THEN 1 END) OVER (ORDER BY DATE_ISO) AS grp
  FROM RUNNUNG_BALANCE_TABLE
  RIGHT JOIN DIM_DATE ON DATE_ISO = BDATE
)
SELECT
  DATE_ISO AS BDATE,
  MIN(CRM) OVER (PARTITION BY grp) AS CRM,
  MIN(ACCT) OVER (PARTITION BY grp) AS ACCT,
  MIN(BAL) OVER (PARTITION BY grp) AS BAL
FROM CTE;

CTE 看起来像这样:

日期_ISO 客户关系管理 ACCT 巴尔 Grp
2023-10-24 123 ab123 1000 1
2023-10-25 123 ab123 1100 2
2023-10-26 (空) (空) (空) 2
2023-10-27 123 ab123 1200 3
2023-10-28 123 ab123 1300 4
2023-10-29 (空) (空) (空) 4
2023-10-30 (空) (空) (空) 4

最终结果如下所示:

BD日期 客户关系管理 ACCT 巴尔
2023-10-24 123 ab123 1000
2023-10-25 123 ab123 1100
2023-10-26 123 ab123 1100
2023-10-27 123 ab123 1200
2023-10-28 123 ab123 1300
2023-10-29 123 ab123 1300
2023-10-30 123 ab123 1300

SQL 小提琴

© www.soinside.com 2019 - 2024. All rights reserved.