Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server SQL-按月份和去年的字段值对记录进行计数和分组_Sql Server_Tsql_Date_Count_Group By - Fatal编程技术网

Sql server SQL-按月份和去年的字段值对记录进行计数和分组

Sql server SQL-按月份和去年的字段值对记录进行计数和分组,sql-server,tsql,date,count,group-by,Sql Server,Tsql,Date,Count,Group By,我需要计算表“a”中记录的总数,其中“a”中的字段(比如“type”)有一个特定的值“v”。从所有这些a.type='v'的记录中,我需要对它们进行两次分组:首先按字段'b_id',然后按月份。这些记录的日期范围必须限制为自当前日期起的最后一年 我已经有了带ISNULL()的“b_id”字段的总计,如下所示: SELECT ISNULL( SELECT COUNT(*) FROM a WHERE a.type = 'v' AND b.b_id = a.b_id )

我需要计算表“a”中记录的总数,其中“a”中的字段(比如“type”)有一个特定的值“v”。从所有这些a.type='v'的记录中,我需要对它们进行两次分组:首先按字段'b_id',然后按月份。这些记录的日期范围必须限制为自当前日期起的最后一年

我已经有了带ISNULL()的“b_id”字段的总计,如下所示:

SELECT ISNULL(
    SELECT COUNT(*)
    FROM a
    WHERE a.type = 'v'
    AND b.b_id = a.b_id
), 0) AS b_totals
数据在表a中,并在表b中连接b_id'是表b的主键,可以在表a中找到(虽然它不是a的键的一部分)。a的键与我需要提取的数据无关,但为了简单起见,可以将其表示为“a_id”

我如何:

  • 将这些记录限制在自当前日期起的过去十二个月内
  • 取任意和所有b.id值的总和,并按月对其进行分类。这是每年b.id总数的补充。该日期作为标准日期/时间类型存储在表“a”的字段“date_Occurrent”中
最后的模式应该是这样的,假设当前月份是10月,年份是2016年:

b.id | b_totals | Nov. 2015 | Dec. 2015 | Jan. 2016 .... Oct. 2016
__________________________________________________________________
ID_1      1           0         0           0               1
ID_2      3           2         0           1               0
ID_3      5           1         1           3               0
编辑:我可能应该澄清,我正在计算表“a”中的记录,其中字段“f”具有特定的值“v”。从这些记录中,我需要按月份/日期对它们进行分组。我更新了ISNULL查询以使其更清晰,并更新了a和b的键。“发生日期”应该在表a中,而不是b中,这是我的错误/输入错误

如果有帮助,我可以从高层描述数据而不泄露任何敏感数据的最佳方式是:

  • “b”是位置表,“b.b_id”是每个位置的id
  • “a”是一个事件表。这些事件的位置在“a.b_id”中找到,并在“b.b_id”上加入。每个事件发生的日期在“a.b_发生的日期”中
  • 我需要将事件类型限制为某个值。在本例中,类型为字段“type”。这是ISNULL SQL查询中的“where”子句,它按位置获取总计
  • 从所有此类事件中,我需要计算过去一年中每个地点发生此类事件的次数。一旦我有了去年的总数,我需要按月统计
表结构: a的表结构类似于

a、 a|id | a.b|id | a.type | a.date |

同样,我不需要来自a的ID:只是基于类型、b_ID和发生日期的一系列计数

编辑2:我通过以下查询将b_id的总数限制为过去一年:

SELECT ISNULL(
    SELECT COUNT(*)
    FROM a
    WHERE a.type = 'v'
    AND b.b_id = a.b_id
    AND a.date_occurred BETWEEN (DATEADD(yyyy, -1, GETDATE()) AND (GETDATE())
), 0) AS b_totals

现在需要用一个轴和月份来做这件事。

为了从问题中提供的绝对最小细节中充分详细,我创建了以下两个示例表,其中包含一些数据:

CREATE TABLE Bexample
    ([ID] int)
;

INSERT INTO Bexample
    ([ID])
VALUES
    (1),
    (2),
    (3),
    (4),
    (5),
    (6),
    (7),
    (8),
    (9)
;


CREATE TABLE Aexample
    ([ID] int, [B_PK] int, [SOME_DT] datetime)
;

INSERT INTO Aexample
    ([ID], [B_PK], [SOME_DT])
VALUES
    (1, 1, '2015-01-01 00:00:00'),
    (2, 2, '2015-02-01 00:00:00'),
    (3, 3, '2015-03-01 00:00:00'),
    (4, 4, '2015-04-01 00:00:00'),
    (5, 5, '2015-05-01 00:00:00'),
    (6, 6, '2015-06-01 00:00:00'),
    (7, 7, '2015-07-01 00:00:00'),
    (8, 8, '2015-08-01 00:00:00'),
    (9, 9, '2015-09-01 00:00:00'),
    (10, 1, '2015-10-01 00:00:00'),
    (11, 2, '2015-11-01 00:00:00'),
    (12, 3, '2015-12-01 00:00:00'),
    (13, 1, '2016-01-01 00:00:00'),
    (14, 2, '2016-02-01 00:00:00'),
    (15, 3, '2016-03-01 00:00:00'),
    (16, 4, '2016-04-01 00:00:00'),
    (17, 5, '2016-05-01 00:00:00'),
    (18, 6, '2016-06-01 00:00:00'),
    (19, 7, '2016-07-01 00:00:00'),
    (20, 8, '2016-08-01 00:00:00'),
    (21, 9, '2016-09-01 00:00:00'),
    (22, 1, '2016-10-01 00:00:00'),
    (23, 2, '2016-11-01 00:00:00'),
    (24, 3, '2016-12-01 00:00:00')
;
现在,使用这些表和数据,我可以生成如下结果表:

id  Nov 2015  Dec 2015  Jan 2016  Feb 2016  Mar 2016 Apr 2016 May 2016 Jun 2016 Jul 2016 Aug 2016 Sep 2016 Oct 2016
1        0        0        1        0        0        0        0        0        0        0        0        1
2        1        0        0        1        0        0        0        0        0        0        0        0
3        0        1        0        0        1        0        0        0        0        0        0        0
4        0        0        0        0        0        1        0        0        0        0        0        0
5        0        0        0        0        0        0        1        0        0        0        0        0
6        0        0        0        0        0        0        0        1        0        0        0        0
7        0        0        0        0        0        0        0        0        1        0        0        0
8        0        0        0        0        0        0        0        0        0        1        0        0
9        0        0        0        0        0        0        0        0        0        0        1        0
SELECT id, [Nov 2015],[Dec 2015],[Jan 2016],[Feb 2016],[Mar 2016],[Apr 2016],[May 2016],[Jun 2016],[Jul 2016],[Aug 2016],[Sep 2016],[Oct 2016] FROM
                (
                    select
                          format([mnth],'MMM yyyy') colname
                        , b.id
                        , a.b_pk
                    from #mylist
                    cross join bexample b
                    left join aexample a on #mylist.mnth = DATEADD(month, DATEDIFF(month,0,a.some_dt), 0)
                               and b.id = a.b_pk
               ) sourcedata
                pivot
                (
                    count([b_pk])
                    FOR [colname] IN ([Nov 2015],[Dec 2015],[Jan 2016],[Feb 2016],[Mar 2016],[Apr 2016],[May 2016],[Jun 2016],[Jul 2016],[Aug 2016],[Sep 2016],[Oct 2016])
                ) p
id name          mnth       
-- ------------- -------- - 
1  Atlantic City 2016 Jan 1 
1  Atlantic City 2016 Jul 1 
2  Boston        2016 Aug 1 
2  Boston        2016 Feb 1 
3  Chicago       2016 Mar 1 
3  Chicago       2016 Sep 1 
4  Denver        2016 Apr 1 
4  Denver        2016 Oct 1 
5  Edgbaston     2015 Nov 1 
5  Edgbaston     2016 May 1 
5  Edgbaston     2016 Nov 1 
6  Melbourne     2015 Dec 1 
6  Melbourne     2016 Dec 1 
6  Melbourne     2016 Jun 1 
使用既需要“公共表表达式”(CTE)又需要“动态sql”的查询来生成该结果:

“动态SQL“是一个生成SQL并随后执行的查询。这是必需的,因为列名每月都在更改。因此,对于动态sql,我们声明了两个变量,它们将保存生成的sql。其中一个是存储列名称,在两个位置使用,另一个是保存完成的查询。注意:在开发解决方案时,您可以显示生成的SQL,而不是执行此操作(注意查询末尾执行附近的注释)

除了示例表和数据之外,我们还有一个“时间序列”要考虑12个月。这是“动态”的,因为它是从今天的日期开始计算的,我假设如果今天是2016年11月内的任何一天,“最后12个月”从2015年11月1日开始,到2016年10月31日结束(即12个完整月,没有部分月)

计算的核心是:

DATEADD(month,-12, DATEADD(month, DATEDIFF(month,0,GETDATE()), 0) )
它首先使用
DATEDIFF(month,0,GETDATE())
定位当前月份的第一天,然后从该日期再减去12个月。以此作为开始日期,“递归CTE”用于生成12行,在过去的12个完整月内,每个月生成一行

这12行的目的是确保当我们考虑实际表数据时,12列中没有空隙。这是通过在我们的查询中使用生成的12行作为“from表”来实现的,并且“A”表根据日期列[some_dt]的年/月与12个月的行保持连接

因此,我们生成12行,将示例数据与这些数据连接起来,用于生成数据“透视”所需的SQL。在这里,可以看到生成的sql的
示例非常有用,如下所示:

id  Nov 2015  Dec 2015  Jan 2016  Feb 2016  Mar 2016 Apr 2016 May 2016 Jun 2016 Jul 2016 Aug 2016 Sep 2016 Oct 2016
1        0        0        1        0        0        0        0        0        0        0        0        1
2        1        0        0        1        0        0        0        0        0        0        0        0
3        0        1        0        0        1        0        0        0        0        0        0        0
4        0        0        0        0        0        1        0        0        0        0        0        0
5        0        0        0        0        0        0        1        0        0        0        0        0
6        0        0        0        0        0        0        0        1        0        0        0        0
7        0        0        0        0        0        0        0        0        1        0        0        0
8        0        0        0        0        0        0        0        0        0        1        0        0
9        0        0        0        0        0        0        0        0        0        0        1        0
SELECT id, [Nov 2015],[Dec 2015],[Jan 2016],[Feb 2016],[Mar 2016],[Apr 2016],[May 2016],[Jun 2016],[Jul 2016],[Aug 2016],[Sep 2016],[Oct 2016] FROM
                (
                    select
                          format([mnth],'MMM yyyy') colname
                        , b.id
                        , a.b_pk
                    from #mylist
                    cross join bexample b
                    left join aexample a on #mylist.mnth = DATEADD(month, DATEDIFF(month,0,a.some_dt), 0)
                               and b.id = a.b_pk
               ) sourcedata
                pivot
                (
                    count([b_pk])
                    FOR [colname] IN ([Nov 2015],[Dec 2015],[Jan 2016],[Feb 2016],[Mar 2016],[Apr 2016],[May 2016],[Jun 2016],[Jul 2016],[Aug 2016],[Sep 2016],[Oct 2016])
                ) p
id name          mnth       
-- ------------- -------- - 
1  Atlantic City 2016 Jan 1 
1  Atlantic City 2016 Jul 1 
2  Boston        2016 Aug 1 
2  Boston        2016 Feb 1 
3  Chicago       2016 Mar 1 
3  Chicago       2016 Sep 1 
4  Denver        2016 Apr 1 
4  Denver        2016 Oct 1 
5  Edgbaston     2015 Nov 1 
5  Edgbaston     2016 May 1 
5  Edgbaston     2016 Nov 1 
6  Melbourne     2015 Dec 1 
6  Melbourne     2016 Dec 1 
6  Melbourne     2016 Jun 1 
因此,希望您可以在生成的SQL代码中看到,动态创建的12行变为12列。请注意,因为我们正在执行“动态sql”,所以作为CTE生成的12行需要存储为“临时表”(#mylist)

生成并执行该SQL的查询如下所示

DECLARE @cols AS VARCHAR(MAX)
DECLARE @query  AS VARCHAR(MAX)

;with mylist as (
      select DATEADD(month,-12, DATEADD(month, DATEDIFF(month,0,GETDATE()), 0) ) as [mnth]
      union all 
      select DATEADD(month,1,[mnth]) 
      from mylist
      where [mnth] < DATEADD(month,-1, DATEADD(month, DATEDIFF(month,0,GETDATE()), 0) )
      )
select [mnth]
into #mylist
from mylist


    SELECT @cols = STUFF((SELECT ',' + QUOTENAME(format([mnth],'MMM yyyy'))
                      FROM #mylist
                      FOR XML PATH(''), TYPE
                      ).value('.', 'NVARCHAR(MAX)')
                  ,1,1,'')

    SET @query = 'SELECT id, ' + @cols + ' FROM
                (
                    select
                          format([mnth],''MMM yyyy'') colname
                        , b.id
                        , a.b_pk
                    from #mylist
                    cross join bexample b
                    left join aexample a on #mylist.mnth = DATEADD(month, DATEDIFF(month,0,a.some_dt), 0)
                               and b.id = a.b_pk
               ) sourcedata
                pivot
                (
                    count([b_pk])
                    FOR [colname] IN (' + @cols + ')
                ) p '

--select @query -- use select to inspect the generated sql
execute(@query) -- once satisfied that sql is OK, use execute

drop table #mylist
将@cols声明为VARCHAR(MAX)
将@query声明为VARCHAR(MAX)
;以mylist为例(
选择DATEADD(month,-12,DATEADD(month,DATEDIFF(month,0,GETDATE()),0))作为[mnth]
联合所有
选择日期添加(月,1,[mnth])
来自mylist
其中[mnth]