我试图获得同一年没有交易的所有月份(如果不可能有不同的年份)
这是我在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
答案 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等。这可以适用于您在表格中的任何日期范围,因此不同的年份不会成为问题。