SQL 按月末计数行 - 年初至今落在两个日期之间

问题描述 投票:0回答:1

MS SQL 2014。

我正在尝试创建一个查询,该查询可以返回截至上个月最后一天的两个日期之间的行数以及运行查询时的当月 (MTD) 计数。例如,假设我今天需要这份报告。我可以使用一年中每个月的查询(过去的条件,而不是未来的条件)手动创建报告。一月、二月、三月、四月等。我使用 date1< End of Month (eom) and date2>eom.

但是,我想创建一个查询,自动给出 date1 在 eom 之前和 date2 在 eom 之后(或 date2 为空)的行数。我想也许有办法使用 systemdate 和 dateadd 来倒数,但我不知道如何将其放在一起以提供截至每个月最后一天的最后 12 个月的所有数据。每个月的最后一天不是直接存储在我需要从中提取的表中的列。

有一个日期维度表,但我不确定如何将其包含在我从中提取日期的表中(如果有必要的话)。小于和大于日期表示我需要在几个月或一年内进行计数的“截至日期”。

Select count(column1) as "September Count"
From table a
 Left Outer Join a table b on a.pk=b.pk
Where a.date1 <= '2023-09-30 00:00:00'
 AND b.date2 > '2023-09-30 00:00:00'
        OR date2 is null)

联合所有

Select count(a.column1) as "August Count"
,b.otherstuff as "Important"
,a.OtherStuff as "Also Important"
From table a
Left Outer Join table2 b on a.pk=b.pk
Where a.date1 <= '2023-08-31 00:00:00'
 AND (b.date2 > '2023-08-31 00:00:00'
        OR b.date2 is null)

等等......

结果应该是这样的:

八月计数 |九月计数|重要|同样重要 46890 39640 |东西|其他东西

如果我需要提供更多详细信息,请告诉我。该数据库是专有的,但如果有必要,我可以发布更多虚假信息进行解释。非常感谢您的帮助!

我知道我可以为每个月创建一个查询并将它们合并在一起,但我想要一种更好的方法来做到这一点,可以更加自动化,更少手动。

结果应该是这样的:

八月计数 九月计数 重要 也很重要
46890 39640 东西 其他东西

重要 也很重要
46890 八月 东西 其他东西
39640 九月 东西2 2 其他东西

如果我需要提供更多详细信息,请告诉我。该数据库是专有的,但如果有必要,我可以发布更多虚假信息进行解释。非常感谢您的帮助!

sql-server datetime count partition rolling-computation
1个回答
0
投票

我只是确定您感兴趣的时间段,并在按这些日期进行过滤时按日期对数据进行分组。

以下是当前日期前后 180 天的完整胡言乱语数据:

drop table if exists #tab
create table #tab
(
    SK int identity(1,1),
    Dt date,
    Value int
)

insert into #Tab
(
    Dt,
    Value
)
select top 100000
    dateadd(day, checksum(newid()) % 180, getdate()),
    abs(checksum(newid()))
from sys.all_objects a, sys.all_objects b

接下来,您想要查找当月和上个月的所有行。您可以通过多种方式做到这一点;您可以使用变量(就像我所做的那样)或使用内联语句来完成此操作。您可以检查日期列的年份和月份值,但这在年底时会有点棘手,因为如果您在一月运行此操作,则必须回溯年份。所以我认为最简单的方法就是我在这里展示的,您可以获取上个月月初到本月底之间的所有行。

declare 
    @Now date = getdate(),
    @StartOfPreviousMonth date,
    @EndOfPreviousMonth date,    
    @StartOfCurrentMonth date,
    @EndOfCurrentMonth date

select
    @EndOfCurrentMonth = eomonth(getdate()),
    @StartOfCurrentMonth = datefromparts(year(@Now), month(@Now), 1),
    @StartOfPreviousMonth = dateadd(month, -1, @StartOfCurrentMonth),
    @EndOfPreviousMonth = eomonth(@StartOfPreviousMonth)

select
    StartOfCurrentMonth = @StartOfCurrentMonth,
    EndOfCurrentMonth = @EndOfCurrentMonth,
    StartOfPreviousMonth = @StartOfPreviousMonth,
    EndOfPreviousMonth = @EndOfPreviousMonth

select
    _Year = year(dt),
    _Month = month(dt),
    Ct = count(1)
from #tab
where Dt between @StartOfPreviousMonth and  @EndOfCurrentMonth
group by year(Dt), month(dt)

关于格式化的最后一点,通常,我不喜欢将这样的数据旋转到单行上。如果列名称中包含月份,则您无法轻松地重新运行相同的查询,并且无法让应用程序知道要查找的字段(即,您的应用程序是否必须查找列的所有可能的月份名称? )。我建议将其保留为两个单独的行。但如果这是不可能的,我建议也许将字段命名为“CurrentMonthTotal”和“PreviousMonthTotal”,因为至少这样列的命名是可预测的。

因此,如果您想将它们合并到同一行,可以尝试这样的操作:

select
    PreviousMonthCt = max(case when _Month = month(@StartOfPreviousMonth) then Ct else null end),
    CurrentMonthCt =  max(case when _Month = month(@StartOfCurrentMonth) then Ct else null end)
from
(
    select
        _Year = year(dt),
        _Month = month(dt),
        Ct = count(1)
    from #tab
    where Dt between @StartOfPreviousMonth and  @EndOfCurrentMonth
    group by year(Dt), month(dt)
) a
© www.soinside.com 2019 - 2024. All rights reserved.