簡體   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