在数据-SQL中添加缺失的日子

时间:2018-10-04 15:12:29

标签: sql sql-server

我有一张只显示工作日值的表。它从仅在工作日导入的文件中获取这些信息。我还需要在周末(或节假日)中添加先前已知值的值。当我需要在MS Access中使用此question时,我曾问过它。我现在正在将该数据库移至SQL Server。

如果您想在Access中查看对我有用的内容,欢迎您查看link

我尝试使用以下方法使MS Access SQL适应SQL Server:

SELECT a1.IDNbr, a1.Balance, CONVERT(int, DAY(a1.BalDate)) + 3

FROM tblID a1 INNER JOIN tblID a2 ON (CONVERT(int, DAY(a1.BalDate)) + 4 = a2.BalDate) AND (a1.IDNbr = a2.IDNbr)

WHERE NOT EXISTS (
    SELECT *
    FROM tblID a3
    WHERE a3.IDNbr = a1.IDNbr AND a3.BalDate = CONVERT(int, DAY(a1.BalDate)) + 3) AND (DATEPART(W, a1.BalDate) = 6
);

但是,出现错误:

  

第206级2状态4行的消息

     

操作符类型冲突:日期与int不兼容

问题::如何获取此查询(该查询将变为INSERT语句),以显示数据中的所有缺失日期,并将最后一个已知日期的值分配给失踪的日子?

我拥有的数据(从星期五开始):

+-------------------------------------+
|ID |  IDNbr |   Balance  |  BalDate  |
+-------------------------------------+
|001|   91   |     529    | 1/5/2018  |
|002|   87   |     654    | 1/5/2018  |
|003|   45   |     258    | 1/5/2018  |

|004|   91   |     611    | 1/8/2018  |
|005|   87   |     753    | 1/8/2018  |
|006|   45   |     357    | 1/8/2018  |
|...|   ..   |     ...    | ........  | 
+-------------------------------------+
'BalDate then skips past 1/6/2018 and 1/7/2018 to 1/8/2018

我需要的数据:

+-------------------------------------+
|ID |  IDNbr |   Balance  |  BalDate  |
+-------------------------------------+
|001|   91   |     529    | 1/5/2018  |
|002|   87   |     654    | 1/5/2018  |
|003|   45   |     258    | 1/5/2018  |

|004|   91   |     529    | 1/6/2018  |
|005|   87   |     654    | 1/6/2018  |
|006|   45   |     258    | 1/6/2018  |

|007|   91   |     529    | 1/7/2018  |
|008|   87   |     654    | 1/7/2018  |
|009|   45   |     258    | 1/7/2018  |

|010|   91   |     611    | 1/8/2018  |
|011|   87   |     753    | 1/8/2018  |
|012|   45   |     357    | 1/8/2018  |
|...|   ..   |     ...    | ........  |
+-------------------------------------+
'I'm needing it to add the Saturday(1/6/2018) and Sunday(1/7/2018) before continuing on to 1/8/2018

任何帮助将不胜感激。预先谢谢你!

如果有不赞成票,请您解释为什么要不赞成票,以便我纠正!

2 个答案:

答案 0 :(得分:2)

好的,您将需要Bernd的答案中的CalTable()函数。我们将使用它来创建setlocal EnableExtensions for %%I in ("Game Files\*.BNK") do call :ProcessBNK "%%I" exit /b :ProcessBNK set _targetDir="%~n1" md %_targetDir% 2>nul Tools\bnkextr.exe %1 move *.wav Tools\Decoding for %%I in (Tools\Decoding\*.WAV) do call :ProcessWAV "%%I" for %%I in (Tools\Decoding\*.OGG) do Tools\revorb.exe "%%I" move Tools\Decoding\*.OGG %_targetDir% move %1 %_targetDir% exit /b :ProcessWAV Tools\ww2ogg.exe %1 --pcb Tools\packed_codebooks_aoTuV_603.bin del %1 exit /b MIN(BalDate)MAX(BalDate)之间的所有日历日期的列表。我们还将使用tblID值列表来CROSS JOIN,我认为这是DISTINCT IDNbr的PK。

让我们创建一些示例数据。

tblID

接下来,我们将在遗失的日子中将新记录插入#tblID中。这里的神奇之处在于CREATE TABLE #tblID (ID VARCHAR(3), IDNbr INT, Balance INT, BalDate DATE) INSERT INTO #tblID ( ID ,IDNbr ,Balance ,BalDate ) VALUES ('001',91,529,'1/5/2018'), ('002',87,654,'1/5/2018'), ('003',45,258,'1/5/2018'), ('004',91,611,'1/8/2018'), ('005',87,753,'1/8/2018'), ('006',45,357,'1/8/2018') 函数,该函数可以查看上一行的数据。我们根据缺失日期与数据的最后日期之间的差值为其提供一个偏移值的表达式。

LAG()

在这一点上,如果我们不关心;WITH IDs AS ( SELECT DISTINCT IDNbr FROM #tblID ) ,IDDates AS ( SELECT BalDate = c.[Date] ,i.IDNbr FROM [CalTable]((SELECT MIN(BalDate) FROM #tblID), (SELECT MAX(BalDate) FROM #tblID)) c CROSS APPLY IDs i ) ,FullResults AS ( SELECT i.BalDate ,i.IDNbr ,Balance = CASE WHEN t.Balance IS NOT NULL THEN t.Balance ELSE LAG(t.Balance, DATEDIFF( DAY ,(SELECT MAX(t1.BalDate) FROM #tblID t1 WHERE t1.IDNbr = i.IDNbr AND t1.BalDate <= i.BalDate GROUP BY t1.IDNbr) ,i.BalDate ) ) OVER (PARTITION BY i.IDNbr ORDER BY i.BalDate ASC) END FROM IDDates i LEFT JOIN #tblID t ON t.BalDate = i.BalDate AND t.IDNbr = i.IDNbr ) INSERT INTO #tblID ( IDNbr ,Balance ,BalDate ) SELECT f.IDNbr ,f.Balance ,f.BalDate FROM FullResults f LEFT JOIN #tblID t ON t.IDNbr = f.IDNbr AND t.BalDate = f.BalDate WHERE t.IDNbr IS NULL 字段(该字段似乎是行号的3个字符的字符串表示形式),那就很好了。但是,尽管我认为以这种方式使用字符串不是一个好习惯,但我也不是对我不了解的其他人的业务需求发表评论的人。

因此,假设我们必须更新ID字段以匹配预期的输出。我们可以这样:

ID

现在,如果您查询更新的表,您将获得以下信息:

;WITH IDUpdate AS
(
    SELECT 
        ID = RIGHT('000' + CAST(ROW_NUMBER() OVER (ORDER BY BalDate ASC, IDNbr DESC) AS VARCHAR), 3)
       ,t.IDNbr
       ,t.Balance
       ,t.BalDate 
    FROM #tblID t
)
UPDATE t
SET t.ID = i.ID
FROM #tblID t
INNER JOIN IDUpdate i ON i.IDNbr = t.IDNbr AND i.BalDate = t.BalDate

输出:

SELECT 
    ID
    ,IDNbr
    ,Balance
    ,BalDate 
FROM #tblID
ORDER BY BalDate ASC, IDNbr DESC

答案 1 :(得分:1)

以下是链接函数的示例:

create FUNCTION [dbo].[CalTable]
(
@startDate date,
@endDate date
)
RETURNS
@calender TABLE
(
    [Date] date not null primary key CLUSTERED,
    isMondayToFriday bit not null
)
AS
BEGIN
    declare @currentday date = @startDate;
    declare @isMondayToFriday bit;

    while (@currentday<=@endDate)
    begin
    -- respect DATEFIRST depending on language settings
      if (DATEPART(dw, @currentday)+@@DATEFIRST-2)%7+1>5
        set @isMondayToFriday = 0
      else
        set @isMondayToFriday = 1

      insert into @calender values (@currentday, @isMondayToFriday);

      set @currentday = DATEADD(D, 1, @currentday);
    end

    RETURN
END

GO


select * from [CalTable]({d'2018-01-01'}, {d'2018-02-03'});

使用它来查找差距。