SQL Server:所有日历日的工作日

时间:2017-09-25 14:45:47

标签: sql sql-server

我有以下表格。由于加拿大日是7月1日,我的数据来源仅在工作日。请注意,TABLE_A(名称:conm)缺少7月1日,这是我的源表。

CREATE TABLE [dbo].[comn]
(
    CONM varchar(48),
    valuedate datetime,
    closeprice decimal(5,2)
)
GO

INSERT INTO comn VALUES ('SAPUTO INC', '2016-06-27', 37.66);
INSERT INTO comn VALUES ('SAPUTO INC', '2016-06-28', 38.34);
INSERT INTO comn VALUES ('SAPUTO INC', '2016-06-29', 38.48);
INSERT INTO comn VALUES ('SAPUTO INC', '2016-06-30', 38.37);
INSERT INTO comn VALUES ('SAPUTO INC', '2016-07-04', 38.12);
INSERT INTO comn VALUES ('SAPUTO INC', '2016-07-05', 38.59);
INSERT INTO comn VALUES ('SAPUTO INC', '2016-07-06', 38.75);
GO

我还有TABLE_B(businessdaysCAN)加上所有加拿大假期。

CREATE TABLE [dbo].[businessdaysCAN]
(
    valuedate datetime,
    isholidayCA decimal(5,2)
)
GO

INSERT INTO businessdaysCAN VALUES ('2016-02-15',1);
INSERT INTO businessdaysCAN VALUES ('2016-03-25', 1);
INSERT INTO businessdaysCAN VALUES ('2016-05-23', 1);
INSERT INTO businessdaysCAN VALUES ('2016-07-01', 1);
INSERT INTO businessdaysCAN VALUES ('2016-08-01', 1);
INSERT INTO businessdaysCAN VALUES ('2016-09-05', 1);
INSERT INTO businessdaysCAN VALUES ('2016-10-10', 1);
GO

我想有一个输出表,例如加拿大假期时,我在最后一张桌子上的假期日期与前一天的价格一致。

CONM        valuedate                closeprice
------------------------------------------------
SAPUTO INC  2016-06-27 00:00:00.000     37.66
SAPUTO INC  2016-06-28 00:00:00.000     38.34
SAPUTO INC  2016-06-29 00:00:00.000     38.48
SAPUTO INC  2016-06-30 00:00:00.000     38.37
SAPUTO INC  2016-07-04 00:00:00.000     38.12
SAPUTO INC  2016-07-05 00:00:00.000     38.59
SAPUTO INC  2016-07-06 00:00:00.000     38.75

2 个答案:

答案 0 :(得分:0)

这将为您提供自2000年1月1日以来所有日期的表格,如果您需要更长或更短的范围,只需更改代码中的日期(如果您需要更长时间,则可能需要添加额外的" PASS&# 34;在CTE但65k是很多天!);然后你可以LEFT JOINRIGHT JOIN到你的桌子并使用你的这里的值为null ...

WITH
    _PASS0 AS (SELECT 1 AS Num UNION ALL SELECT 1),         --2 ROWS
    _PASS1 AS (SELECT 1 AS Num FROM _PASS0 AS A, _PASS0 AS B),  --4 ROWS
    _PASS2 AS (SELECT 1 AS Num FROM _PASS1 AS A, _PASS1 AS B),  --16 ROWS
    _PASS3 AS (SELECT 1 AS Num FROM _PASS2 AS A, _PASS2 AS B),  --256 ROWS
    _PASS4 AS (SELECT 1 AS Num FROM _PASS3 AS A, _PASS3 AS B),  --65,536 ROWS
    _TALLY AS (SELECT 0 AS Number UNION ALL SELECT ROW_NUMBER() OVER(ORDER BY Num) AS Number FROM _PASS4)

SELECT dateadd(DAY,Number,'20000101') AS CalendarDate
FROM _Tally
WHERE  Number <= datediff(DAY,'20000101',getdate());

答案 1 :(得分:0)

你可以尝试一下

DECLARE @comn table (conm varchar(10) , valueDate date,  closePrice decimal(10,2));
DECLARE @businessdaysCAN table(calDate  date, isHolidayCA bit);

INSERT @comn (conm,valueDate,closePrice) VALUES
 ('SAPUTO INC','2016-06-27',37.66)
,('SAPUTO INC','2016-06-28',38.34)
,('SAPUTO INC','2016-06-29',38.48)
,('SAPUTO INC','2016-06-30',38.37)
,('SAPUTO INC','2016-07-04',38.12)
,('SAPUTO INC','2016-07-05',38.59)
,('SAPUTO INC','2016-07-06',38.75);

INSERT @businessdaysCAN (calDate, isHolidayCA) VALUES
 ('2016-05-23',1)
,('2016-07-01',1)
,('2016-08-01',1);

WITH 
cteMinMaxDates as
(
select 
 conm 
,Min(valueDate) as startdate
,Max(valueDate) as enddate
from @comn
Group by conm
),
cteAllDates 
     AS (SELECT  conm 
                ,startdate 
                ,enddate 
                ,valueDate = ( SELECT valueDate FROM @comn a where  a.valueDate = t.startdate and a.conm = t.conm)
         FROM   cteMinMaxDates t 
         UNION ALL 
         SELECT conm 
                ,Dateadd(day, 1, startdate) startdate 
                ,enddate 
                ,valueDate = CASE WHEN ( SELECT valueDate FROM @comn a where  a.valueDate = startdate and a.conm = conm) IS NULL THEN valueDate ELSE ( SELECT valueDate FROM @comn a where  a.valueDate = startdate and a.conm = conm) END 
         FROM   cteAllDates 
         WHERE  startdate < enddate) 
SELECT 
     D.conm
    ,D.startdate valuedate
    ,IsNull(A.closePrice , B.closePrice) closePrice
FROM cteAllDates D 
       LEFT JOIN @comn A 
              ON D.conm = A.conm 
                 AND D.startdate = A.valuedate 
       LEFT JOIN @comn B 
              ON D.valuedate = B.valuedate 
WHERE  A.valuedate IS NOT NULL 
       OR EXISTS (SELECT 1 FROM @businessdaysCAN c where d.startdate = c.calDate)

结果

conm       valuedate  closePrice
---------- ---------- ---------------------------------------
SAPUTO INC 2016-06-27 37.66
SAPUTO INC 2016-06-28 38.34
SAPUTO INC 2016-06-29 38.48
SAPUTO INC 2016-06-30 38.37
SAPUTO INC 2016-07-01 38.37
SAPUTO INC 2016-07-04 38.12
SAPUTO INC 2016-07-05 38.59
SAPUTO INC 2016-07-06 38.75

如果您需要该范围内的所有日期,请删除

WHERE  A.valuedate IS NOT NULL 
       OR EXISTS (SELECT 1 FROM @table_b c where d.startdate = c.calDate)

结果

conm       valuedate  closePrice
---------- ---------- ---------------------------------------
SAPUTO INC 2016-06-27 37.66
SAPUTO INC 2016-06-28 38.34
SAPUTO INC 2016-06-29 38.48
SAPUTO INC 2016-06-30 38.37
SAPUTO INC 2016-07-01 38.37
SAPUTO INC 2016-07-02 38.37
SAPUTO INC 2016-07-03 38.37
SAPUTO INC 2016-07-04 38.12
SAPUTO INC 2016-07-05 38.59
SAPUTO INC 2016-07-06 38.75