SQL SERVER:选择两个日期之间缺少的月份(同年)

时间:2015-01-25 16:19:23

标签: sql-server

我试图获得同一年没有交易的所有月份(如果不可能有不同的年份)

这是我在2个日期之间获取交易的查询,但不知道如何只选择缺少数据库中的交易的月份

SELECT * 
FROM Installment 
WHERE OrderId = 1 
      AND InstallmentDate 
            BETWEEN cast('8/02/2014' as date) 
                AND cast('12/25/2014' as date)

InstallmentId   OrderId CustomerKey InstallmentAmount   InstallmentDate
    18             1      INS-1          3000           2014-09-03
    92             1      INS-1          3000           2014-10-13
   137             1      INS-1          3000           2014-11-05

在这种情况下,缺少第12个月和第8个月的记录,如何使用SQL Server查询获取此信息?

更新

select yymm.yy, yymm.mm
from (select distinct year(InstallmentDate) as yy, month(InstallmentDate) as mm
  from Installment
  where InstallmentDate BETWEEN '2014-09-02' and '2015-01-15'
 ) yymm left join
 Installment i
 on i.OrderId = 1 and
    year(i.InstallmentDate) = yymm.yy and
    month(i.InstallmentDate) = yymm.mm
where i.OrderId is not null;

Gordon的查询从两个日期之间的表格返回所有年份和月份,只需将i.OrderId is null更改为i.OrderId is not null,这是他的查询之外

 yy      mm
2014     9
2014     10
2014     11

预期输出(如果可能)

 yy      mm
2014     12
2015     1

4 个答案:

答案 0 :(得分:5)

使用以下递归CTE

DECLARE @start DATE = '2014-09-02'
DECLARE @end DATE = '2015-01-15'
;WITH IntervalDates (date)
AS
(
    SELECT @start
    UNION ALL
    SELECT DATEADD(MONTH, 1, date)
    FROM IntervalDates
    WHERE DATEADD(MONTH, 1, date)<=@end
)
SELECT YEAR(date) AS Year, MONTH(date) AS Month
FROM IntervalDates

您可以获得两个感兴趣日期之间所有年/月的列表:

Year    Month
==============
2014    9
2014    10
2014    11
2014    12
2015    1

EXCEPT上使用CTE

;WITH IntervalDates (date)
AS
(
    SELECT @start
    UNION ALL
    SELECT DATEADD(MONTH, 1, date)
    FROM IntervalDates
    WHERE DATEADD(MONTH, 1, date)<=@end
)
SELECT YEAR(date) AS Year, MONTH(date) AS Month
FROM IntervalDates

EXCEPT

SELECT DISTINCT YEAR(InstallmentDate) AS yy, MONTH(InstallmentDate) AS mm
FROM Installment
WHERE  OrderId = 1 AND InstallmentDate BETWEEN @start AND @end 

产生所需的结果集:

Year    Month
=============
2014    12
2015    1

答案 1 :(得分:1)

要在SQL中执行此操作,您需要从几个月的列表开始。假设表中每个月至少有一条记录,则可以使用子查询轻松获取缺少的日期。查询的其余部分只是left join并检查不匹配:

select yymm.yy, yymm.mm
from (select distinct year(InstallmentDate) as yy, month(InstallmentDate) as mm
      from Installment
      where InstallmentDate BETWEEN '2014-09-02' and '2015-01-15'
     ) yymm left join
     Installment i
     on i.OrderId = 1 and
        year(i.InstallmentDate) = yymm.yy and
        month(i.InstallmentDate) = yymm.mm
where i.OrderId is null;

答案 2 :(得分:0)

尝试以下脚本。我检索指定日期之间的所有日期,并使用LEFT JOIN来获取表格中不存在的日期:

DECLARE @startDate AS DATETIME, @endDate AS DATETIME
DECLARE @dates AS TABLE (CurrentDate DATETIME)
SET @startDate = '2014-01-01'
SET @endDate = '2014-01-31';
with GetDates AS
(  
SELECT @startDate AS TheDate
UNION ALL  
SELECT DATEADD("DD", 1, TheDate) FROM GetDates
WHERE TheDate < @endDate  
) INSERT INTO @dates SELECT TheDate FROM GetDates
OPTION (MAXRECURSION 0)

SELECT DISTINCT YEAR(d.CurrentDate), MONTH(d.CurrentDate) FROM @dates d
LEFT JOIN InstallmentDate i ON i.InstallmentDate BETWEEN @startDate AND @endDate AND OrderId = 1
WHERE i.InstallmentDate IS NULL

希望这会有所帮助......

答案 3 :(得分:0)

我能想到的最简单的方法是拥有一个日期维度表,其中包含(至少)日期,然后是月份的第1个月。要创建一个,请看看像https://dba.stackexchange.com/questions/74957/best-approach-for-populating-date-dimension-table这样的内容,虽然那个没有像我的示例所示的firstOfMonthDate,但想法是一样的。

然后您的查询变为

SELECT DISTINCT
    firstOfMonthDate
FROM
    dateRef dr
LEFT OUTER JOIN
    InstallmentDate i ON dr.date = i.InstallmentDate AND i.OrderId = 1
WHERE
    i.InstallmentDate IS NULL
AND
    dr.date BETWEEN @startDate and @endDate

根据需要更改会计月份的firstOfMonthDate等。这可以适用于您在表格中的任何日期范围,因此不同的年份不会成为问题。