返回假日/周末的前一条记录

时间:2016-05-16 09:26:34

标签: sql-server sql-server-2008

一张表有股票的股票名称,价值和生效日期,并且不会有任何假期/周末的条目。如果我通过包含假日/周末的日期范围,我想返回之前的日期记录。

E.G。

表名:股票

    ID  Name    Value   EffectiveDate
    1   IBM 200.0000    2015-12-31 00:00:00.000
    2   IBM 201.4500    2016-01-04 00:00:00.000
    3   IBM 201.0000    2016-01-05 00:00:00.000
    4   IBM 202.0000    2016-01-06 00:00:00.000

   SELECT Name, Value, EffectiveDate FROM Stock WHERE Name = 'IBM' AND  EffectiveDate >= '20151231' AND EffectiveDate <= '20160105'

以上查询返回前3条记录,但我想返回以下结果:

    Name    Value   EffectiveDate   ActualDate
    IBM 200.0000    2015-12-31      2015-12-31 
    IBM 200.0000    2015-12-31      2016-01-01 
    IBM 200.0000    2015-12-31      2016-01-02 
    IBM 200.0000    2015-12-31      2016-01-03 
    IBM 201.4500    2016-01-04      2015-01-04 
    IBM 201.0000    2016-01-05      2015-01-05 

01/01/2016至03/01/2016是假期/周末。如果我通过假期/周末日期,我有一个返回上一个日期的函数。任何人都可以帮助在SQL Server中编写查询来实现上述目标吗?

3 个答案:

答案 0 :(得分:2)

DECLARE @table TABLE (
  id int,
  name varchar(20),
  value decimal(10, 4),
  EffectiveDate datetime
)
INSERT INTO @table
  VALUES (1, 'IBM', 200.0000, '2015-12-31 00:00:00.000')
  , (2, 'IBM', 201.4500, '2016-01-04 00:00:00.000')
  , (3, 'IBM', 201.0000, '2016-01-05 00:00:00.000')
  , (4, 'IBM', 202.0000, '2016-01-06 00:00:00.000')

DECLARE @MinDate datetime = '20151231',
        @MaxDate datetime = '20160105';

WITH Dates AS (
    SELECT @MinDate AS ActualDate
  UNION ALL
    SELECT DATEADD(day, 1, ActualDate)
    FROM Dates
    WHERE ActualDate < @MaxDate
)
SELECT [Table].name 
      ,[Table].value
      ,[Table].EffectiveDate
      ,[Dates].ActualDate
FROM Dates
     CROSS APPLY (
         SELECT MAX(EffectiveDate) AS LastEffectiveDate
         FROM @table AS [Table]
         WHERE [Table].EffectiveDate <= Dates.ActualDate
     ) AS CA1
     INNER JOIN @table AS [Table]
         ON [Table].EffectiveDate = CA1.LastEffectiveDate

答案 1 :(得分:0)

如果ActualDate是周末,则以下代码将返回前一日期所需的EffectiveDate,但要包含银行假期的逻辑,您需要在表格中定义这些,然后添加更多逻辑如下。

SELECT Name, Value, EffectiveDate, 
CASE WHEN datename(dw,EffectiveDate) = 'Saturday' 
     THEN DATEADD(DAY, -1, EffectiveDate)
     WHEN datename(dw,EffectiveDate) = 'Sunday'
     THEN DATEADD(DAY, -2, EffectiveDate)
END AS ActualDate
FROM Stock 
WHERE Name = 'IBM' 
AND EffectiveDate BETWEEN '20151231' AND '20160105'

答案 2 :(得分:0)

这可能不是一个完美的解决方案,但这可以解决问题。

DECLARE @table TABLE (
  id int,
  name varchar(20),
  value decimal(10, 4),
  EffectiveDate datetime
)
INSERT INTO @table
  VALUES (1, 'IBM', 200.0000, '2015-12-31 00:00:00.000')
  , (2, 'IBM', 201.4500, '2016-01-04 00:00:00.000')
  , (3, 'IBM', 201.0000, '2016-01-05 00:00:00.000')
  , (4, 'IBM', 202.0000, '2016-01-06 00:00:00.000')

DECLARE @MinDate datetime = '20151231',
        @MaxDate datetime = '20160105';

SELECT
  id,
  (CASE
    WHEN Data.Value IS NULL THEN (SELECT TOP (1)
        value
      FROM @table AS T1
      WHERE T1.EffectiveDate < Data.FinalDate
      ORDER BY FinalDate DESC)
    ELSE Data.value
  END),
  FinalDate
FROM (SELECT
  id,
  name,
  value,
  (CASE
    WHEN EffectiveDate IS NULL THEN Date
    ELSE EffectiveDate
  END) AS FinalDate
FROM @table T
FULL OUTER JOIN (SELECT TOP (DATEDIFF(DAY, @MinDate, @MaxDate) + 1)
  Date = DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY a.object_id) - 1, @MinDate)
FROM sys.all_objects a
CROSS JOIN sys.all_objects b) H
  ON T.EffectiveDate = H.Date) Data
ORDER BY finaldate