繁体   English   中英

如何从t-sql中获取过去一年中每个月的数据,每个月应该在不同的列中

[英]how can I get data from every month from past one year in t-sql and each month should be in different column

我想要过去1年的数据,例如今天是2014年2月5日,我需要2013年5月,2013年6月的数据。直到2014年4月作为单独的列。 如果有人可以在t-sql中使用此代码,这对我将非常有帮助。 谢谢

好的,我想要数据。 以下是我的专栏

created date
------------
02-05-2013
16-05-2013
05-06-2013
22-07-2013
01-08-2013
09-08-2013
02-09-2013
03-10-2013
19-11-2013
11-12-2013
03-01-2014
29-02-2014
15-03-2014
19-04-2014

我想要结果

May 2013    June 2013    July 2013    August 2013 till   April 2014
--------    ---------    ---------    -----------        ----------
02-05-2013 05-06-2013   22-07-2013   01-08-2013          19-04-2014
16-05-2013                           09-08-2013

而且我想动态创建 ,这对我的查询非常重要

尽管每个人都很快建议使用PIVOT ,但这在这里真的行不通,因为PIVOT需要将每一列汇总为该月和年份的一个(最大,最小,任何日期)日期。

我给了这个问题一些注意,因为它实际上是一个有趣的挑战。 现实情况是,最好通过某些报告工具(例如SSRS)来完成此操作,因为您的输出实际上是时间轴报告。

由于需要动态列之类的东西,因此我真的看不到没有变量和一些动态sql怎么办,所以假设这是可以接受的,下面的内容将经过测试,并将完全输出您所描述的内容。 它实际上创建了12个CTE表,每个表包含一个月和一年的日期(从运行sql的任何月份和年份开始向后计数)。 然后,它只需使用所有表的FULL OUTER JOIN创建报告。 但是,如果仅将12个表完全连接在一起,则每一列的值将在几行中随机排列,并且在许多行之间存在空值。 要在顶部的每一列中排列日期,必须添加一个基表,该基表具有每个月/年表可以加入的顺序编号。 对于任何给定的年/月,最多生成最大数量的序列号。 (注意:对于基数表, LEFT OUTER JOIN也足够了...)

假定表名称为dbo.MyTable ,日期dbo.MyTable CreatedDate

DECLARE @cteSql nvarchar(MAX) = '';
DECLARE @tblSql nvarchar(MAX) = '';
DECLARE @frmSql nvarchar(MAX) = '';
DECLARE @colNm  varchar(10);
DECLARE @tblNm  varchar(3);
DECLARE @i int = 0;

/* today's date */
DECLARE @td date = GETDATE();
/* max number of dates per yr/mo */
DECLARE @maxItems int = (SELECT MAX(CNT) FROM (SELECT COUNT(*) AS CNT FROM dbo.MyTable GROUP BY YEAR(CreatedDate), MONTH(CreatedDate)) T)

/* a table of sequential numbers up to the max per yr/mo; this is so the full outer join is laid out neatly */
SET @cteSql = 'WITH T(id) AS( SELECT id = 1 UNION ALL SELECT id + 1 FROM T WHERE id + 1 <= ' + CAST(@maxItems AS varchar(16)) + ')';

/* count down from current date to past 12 months */
WHILE @i > -12
BEGIN
  /* a simple name for each CTE: T0, T1, T2 etc */
  SET @tblNm = 'T' + CAST((@i*-1) AS varchar(2));
  /* rpt column names; [Jan 2014], [Feb 2014] etc */
  SET @colNm = '[' + RIGHT(CONVERT(varchar(11), DATEADD(m, @i, @td), 106),8) + ']';

  /* each CTE contains a sequential id and the dates belonging to that month and yr */
  SET @cteSql += ', ' + @tblNm + '(id, ' + @colNm + ')'
               + ' AS (SELECT ROW_NUMBER() OVER(ORDER BY CreatedDate) AS id, CreatedDate FROM dbo.MyTable WHERE YEAR(CreatedDate) = ' + CAST(YEAR(DATEADD(m, @i, @td)) AS varchar(4))
               + ' AND MONTH(CreatedDate) = ' + CAST(MONTH(DATEADD(m, @i, @td)) AS varchar(2)) + ')';

  /* this will eventually be the SELECT statement for the report...just the month columns, not the id */
  SET @tblSql = ', ' + @colNm + @tblSql;
  /* concatenate all the columns using FULL OUTER JOIN with the first table of simple sequential numbers as the driver */
  SET @frmSql += ' FULL OUTER JOIN ' + @tblNm + ' ON T.id = ' + @tblNm + '.id ';

  SET @i -= 1;
END

/* put all the sql together */
SET @tblSql = @cteSql + ' SELECT' + STUFF(@tblSql, 1, 1, '') + ' FROM T ' + @frmSql

/*  view the generated sql */
-- SELECT @tblSql AS X

/*  this should generate the report you described above, showing the last 12 months from whatever date you run it */
EXECUTE (@tblSql)

输出:

Jun 2013   Jul 2013   Aug 2013   Sep 2013   Oct 2013   Nov 2013   Dec 2013   Jan 2014   Feb 2014   Mar 2014   Apr 2014   May 2014
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
2013-06-05 2013-07-22 2013-08-01 2013-09-02 2013-10-03 2013-11-19 2013-12-11 2014-01-03 2014-02-28 2014-03-15 2014-04-19 NULL
2013-06-07 NULL       2013-08-09 NULL       NULL       NULL       NULL       NULL       NULL       NULL       NULL       NULL
NULL       NULL       2013-08-10 NULL       NULL       NULL       NULL       NULL       NULL       NULL       NULL       NULL

事实证明,生成的sql在概念上与@Hogan所建议的类似,尽管我最初并未意识到。 它实际上只是添加了动态命名以及按年/月而不是仅按月进行的隔离。

这是一种无需动态调整即可完成的方法。 我只在2013年这样做,您可以看到添加更多列所需的内容:

(工作提琴: http ://sqlfiddle.com/#!6/ d9797/1

with nums as
(
  select [create date],
         MONTH([create date]) as M,
         ROW_NUMBER() OVER (ORDER BY [create date] ASC) as RN
  from table1       
  where  MONTH([create date]) =1
  union all      
  select [create date],
         MONTH([create date]) as M,
         ROW_NUMBER() OVER (ORDER BY [create date] ASC) as RN
  from table1       
  where  MONTH([create date]) =2
  union all      
  select [create date],
         MONTH([create date]) as M,
         ROW_NUMBER() OVER (ORDER BY [create date] ASC) as RN
  from table1       
  where  MONTH([create date]) =3
  union all      
  select [create date],
         MONTH([create date]) as M,
         ROW_NUMBER() OVER (ORDER BY [create date] ASC) as RN
  from table1       
  where  MONTH([create date]) =4
  union all      
  select [create date],
         MONTH([create date]) as M,
         ROW_NUMBER() OVER (ORDER BY [create date] ASC) as RN
  from table1       
  where  MONTH([create date]) =5
  union all      
  select [create date],
         MONTH([create date]) as M,
         ROW_NUMBER() OVER (ORDER BY [create date] ASC) as RN
  from table1       
  where  MONTH([create date]) =6
  union all      
  select [create date],
         MONTH([create date]) as M,
         ROW_NUMBER() OVER (ORDER BY [create date] ASC) as RN
  from table1       
  where  MONTH([create date]) =7
  union all      
  select [create date],
         MONTH([create date]) as M,
         ROW_NUMBER() OVER (ORDER BY [create date] ASC) as RN
  from table1       
  where  MONTH([create date]) =8
  union all      
  select [create date],
         MONTH([create date]) as M,
         ROW_NUMBER() OVER (ORDER BY [create date] ASC) as RN
  from table1       
  where  MONTH([create date]) =9
  union all      
    select [create date],
         MONTH([create date]) as M,
         ROW_NUMBER() OVER (ORDER BY [create date] ASC) as RN
  from table1       
  where  MONTH([create date]) =10
  union all      
  select [create date],
         MONTH([create date]) as M,
         ROW_NUMBER() OVER (ORDER BY [create date] ASC) as RN
  from table1       
  where  MONTH([create date]) =11
  union all      
  select [create date],
         MONTH([create date]) as M,
         ROW_NUMBER() OVER (ORDER BY [create date] ASC) as RN
  from table1       
  where  MONTH([create date]) =12
),maxrn as
(
  select MAX(RN) as maxnum from nums
), rowNumbers as
(
   select 1 as RN
   union all
   select RN+1 AS RN
   from rowNumbers
   where RN < (select maxnum from maxrn)
)
SELECT 
   nJan.[create date] as [Jan 2013],
   nFeb.[create date] as [Feb 2013],
   nMar.[create date] as [Mar 2013],
   nApr.[create date] as [Apr 2013],
   nMay.[create date] as [May 2013],
   nJun.[create date] as [Jun 2013],
   nJul.[create date] as [Jul 2013],
   nAug.[create date] as [Aug 2013],
   nSep.[create date] as [Sep 2013],
   nOct.[create date] as [Oct 2013],
   nNov.[create date] as [Nov 2013],
   nDec.[create date] as [Dec 2013]
FROM rowNumbers n
LEFT JOIN nums nJan ON n.RN = nJan.RN and nJan.M = 1
LEFT JOIN nums nFeb ON n.RN = nFeb.RN and nFeb.M = 2
LEFT JOIN nums nMar ON n.RN = nMar.RN and nMar.M = 3
LEFT JOIN nums nApr ON n.RN = nApr.RN and nApr.M = 4
LEFT JOIN nums nMay ON n.RN = nMay.RN and nMay.M = 5
LEFT JOIN nums nJun ON n.RN = nJun.RN and nJun.M = 6
LEFT JOIN nums nJul ON n.RN = nJul.RN and nJul.M = 7
LEFT JOIN nums nAug ON n.RN = nAug.RN and nAug.M = 8
LEFT JOIN nums nSep ON n.RN = nSep.RN and nSep.M = 9
LEFT JOIN nums nOct ON n.RN = nOct.RN and nOct.M = 10
LEFT JOIN nums nNov ON n.RN = nNov.RN and nNov.M = 11
LEFT JOIN nums nDec ON n.RN = nDec.RN and nDec.M = 12
ORDER BY n.RN ASC

OOOPS这个已经有答案T_T,
但是,如果您有空的话,请尝试一下。 :)

在这种情况下要使用很多东西:

  1. CTE
  2. 东西
  3. 兑换
  4. SUBSTRING

声明@xCol nvarchar(max);

--Begin create column
with cte as
(
    select 1 as id,
        aa.month as mm, aa.Year
        --,aa.xmonth as mmm
        , aa.ord
    from
    (
    select 
        xdate
        ,Year(xdate) as Year
        --,month(xdate) as xmonth
        , substring(convert(nvarchar(max),xdate,106),3,len(convert(nvarchar(max),xdate,106))) as month
        ,convert(nvarchar(6), xdate,112) as ord
    from tempData vv
    ) aa
    group by aa.ord, aa.month,aa.Year
    --order by aa.Year
)
select 

    distinct 
    --c.id,
    @xCol = stuff(
        (
            select ',' + c2.mm
            from cte c2
            where c.id = c2.id
            for xml path ('')
        ),1,0,''
    )
from cte c

;

set @xCol= SUBSTRING(@xCol,2, len(@xCol))
select @xCol = '[' + replace(@xCol,',','],[') + ']'
--select @xCol as '@columns', len(@xCol)

--END CREATE COLUMNS

--CREATE INPUT STRING
Declare @tbl_inputstr table
(
  id int,
  xstr nvarchar(max)
)
;

    with cte as
    (
        select 
            a.xdate, a.month
            ,row_number() over(partition by a.month order by a.xdate) as xrow
        from
        (
        select 
                xdate
                ,Year(xdate) as Year
                ,month(xdate) as xmonth
                ,convert(nvarchar(6),xdate,112) as month2
                , substring(convert(nvarchar(max),xdate,106),3,len(convert(nvarchar(max),xdate,106))) as month
        from tempData 
        ) a
    )
    insert into @tbl_inputstr(id,xstr)
    select  distinct c.xrow as id,
        ' Insert into @tempData (' + substring(stuff(
            (
                select ',[' + cast(c2.month as nvarchar(max)) + ']'
                from cte c2
                where c.xrow = c2.xrow
                for xml path ('')
            ),1,0,''
        ),2,len(stuff(
            (
                select ',[' + cast(c2.month as nvarchar(max)) + ']'
                from cte c2
                where c.xrow = c2.xrow
                for xml path ('')
            ),1,0,''
        ))) + ')'
        +' Values(' + Substring(stuff(
            (
                select ',''' + cast(c2.xdate as nvarchar(max)) + ''''
                from cte c2
                where c.xrow = c2.xrow
                for xml path ('')
            ),1,0,''
        ),2,len(stuff(
            (
                select ',''' + cast(c2.xdate as nvarchar(max)) + ''''
                from cte c2
                where c.xrow = c2.xrow
                for xml path ('')
            ),1,0,''
        ))) + ')'
    from cte c
    order by c.xrow;

select * from @tbl_inputstr

Declare @inputStr nvarchar(max)
select @inputStr = 
    substring(stuff
    (
        (
            select ';' + xstr
            from @tbl_inputstr
            for xml path('')
        ),1,0,''
    ),2, len(stuff
    (
        (
            select ';' + xstr
            from @tbl_inputstr
            for xml path('')
        ),1,0,''
    ))
    ) 


select @inputStr= 'Declare @tempData Table (' +replace(@xCol,']', '] nvarchar(max)') + ');' + @inputStr 
    + '; select ' + @xCol 
    + ' from @tempData'



exec(@inputStr)
--END INPUT STRING

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM