Sql 是否有方法根据脚本运行的月份以可变顺序显示列?

Sql 是否有方法根据脚本运行的月份以可变顺序显示列?,sql,sql-server,Sql,Sql Server,设想一个非常简单的表格,用于存储产品的每月使用量: CREATE TABLE [dbo].[ProductUsage]( [ProductId] [int] NOT NULL, [Month1] [int] NOT NULL, [Month2] [int] NOT NULL, [Month3] [int] NOT NULL, [Month4] [int] NOT NULL, [Month5] [int] NOT NULL, [Month6]

设想一个非常简单的表格,用于存储产品的每月使用量:

CREATE TABLE [dbo].[ProductUsage](
    [ProductId] [int] NOT NULL,
    [Month1] [int] NOT NULL,
    [Month2] [int] NOT NULL,
    [Month3] [int] NOT NULL,
    [Month4] [int] NOT NULL,
    [Month5] [int] NOT NULL,
    [Month6] [int] NOT NULL,
    [Month7] [int] NOT NULL,
    [Month8] [int] NOT NULL,
    [Month9] [int] NOT NULL,
    [Month10] [int] NOT NULL,
    [Month11] [int] NOT NULL,
    [Month12] [int] NOT NULL
) ON [PRIMARY]
GO
这存储了滚动历史使用情况-因此,今天的3月6日列Month3包含2019年3月的数据。2020年3月的数据仍然存在,Month2=2020年2月,Month1=2020年1月,Month12=2019年12月,Month11=2019年11月等

我需要从现在开始创建一个产品使用情况的报告,因此列需要有序 ProductId, 月2日, 月1日, 12月12日, 11月

等等。这需要刷新,因此4月份的订单将是: ProductId, 月3日, 月2日, 月1日, 12月12日, 11月

有人能想出一个好办法吗?报告将有一个今天日期的局部变量,从中可以计算列顺序

非常感谢

爱德华是的,很简单

DECLARE @MesAct numeric
set @MesAct=3

DROP TABLE #ProductUsage
DROP TABLE #meses

CREATE TABLE #ProductUsage(
[ProductId] [int] NOT NULL,[Month1] [int] NOT NULL,[Month2] [int] NOT NULL,[Month3] [int] NOT NULL,
[Month4] [int] NOT NULL,[Month5] [int] NOT NULL,[Month6] [int] NOT NULL,[Month7] [int] NOT NULL,
[Month8] [int] NOT NULL,[Month9] [int] NOT NULL,[Month10] [int] NOT NULL,[Month11] [int] NOT NULL,[Month12] [int] NOT NULL) 

INSERT INTO #ProductUsage VALUES('10000','1','2','3','4','5','6','7','8','9','10','11','12')
INSERT INTO #ProductUsage VALUES('20000','12','23','34','45','56','67','78','89','91','102','113','124')

create table #meses (numMes numeric)
insert into #meses values(1)
insert into #meses values(2)
insert into #meses values(3)
insert into #meses values(4)
insert into #meses values(5)
insert into #meses values(6)
insert into #meses values(7)
insert into #meses values(8)
insert into #meses values(9)
insert into #meses values(10)
insert into #meses values(11)
insert into #meses values(12)

DECLARE  @cols  AS NVARCHAR(MAX)
SET @cols = STUFF((SELECT  ',' + QUOTENAME('Month'+CAST(numMes AS VARCHAR)) 
                   FROM #meses 
                   Where numMes<@MesAct  
                   order by numMes desc 
                   FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'),1,1,'')
SET @cols = @cols+','+STUFF((SELECT  ',' + QUOTENAME('Month'+CAST(numMes AS VARCHAR)) 
                             FROM #meses 
                             Where numMes>=@MesAct  
                             order by numMes desc 
                             FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'),1,1,'')
------------------------------
DECLARE @Script nvarchar(max)

set @Script='select ProductId, '+@cols+' from #ProductUsage'
execute (@Script)

在纯SQL中,不能动态更改列名称,但是可以动态更改与每个列相关的值

让我们假设在原始表格中,Month1代表一月,Month2代表二月,Month3代表三月,等等

select * from ProductUsage


+-----------+--------+--------+--------+--------+--------+--------+--------+--------+--------+---------+---------+---------+
| ProductId | Month1 | Month2 | Month3 | Month4 | Month5 | Month6 | Month7 | Month8 | Month9 | Month10 | Month11 | Month12 |
+-----------+--------+--------+--------+--------+--------+--------+--------+--------+--------+---------+---------+---------+
|       111 |      1 |      2 |      3 |      4 |      5 |      6 |      7 |      8 |      9 |      10 |      11 |      12 |
|       222 |     21 |     22 |     23 |     24 |     25 |     26 |     27 |     28 |     29 |      30 |      31 |      32 |
+-----------+--------+--------+--------+--------+--------+--------+--------+--------+--------+---------+---------+---------+
-

使用建议的方法,列名称将始终为Month1、Month2、,Month12按该顺序排列,但如果当前月份为3月,则Month1将保留2月的值,Month2保留1月的值,Month3保留12月的值,以此类推

declare @month int = 3

select  * 
from   (select  ProductId, val, 'Month' + cast((12 - cast(substring(col,6,2) as tinyint) + @month - 1) % 12 + 1 as varchar(7))  as col
        from    ProductUsage 
                unpivot (val for col in (Month1,Month2,Month3,Month4,Month5,Month6,Month7,Month8,Month9,Month10,Month11,Month12)) u
       ) pu_u 
       pivot(max(val) for col in (Month1,Month2,Month3,Month4,Month5,Month6,Month7,Month8,Month9,Month10,Month11,Month12)) p 



+-----------+--------+--------+--------+--------+--------+--------+--------+--------+--------+---------+---------+---------+
| ProductId | Month1 | Month2 | Month3 | Month4 | Month5 | Month6 | Month7 | Month8 | Month9 | Month10 | Month11 | Month12 |
+-----------+--------+--------+--------+--------+--------+--------+--------+--------+--------+---------+---------+---------+
|       111 |      2 |      1 |     12 |     11 |     10 |      9 |      8 |      7 |      6 |       5 |       4 |       3 |
|       222 |     22 |     21 |     32 |     31 |     30 |     29 |     28 |     27 |     26 |      25 |      24 |      23 |
+-----------+--------+--------+--------+--------+--------+--------+--------+--------+--------+---------+---------+---------+

不是特别漂亮,但这样就可以了:

select  ProductId,
 case datepart(month,getdate()) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11 end As LastMonth
 ,case datepart(month,Dateadd(month,-1,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11  end As TwoMonthsAgo
 ,case datepart(month,Dateadd(month,-2,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11  end As ThreeMonthsAgo
 ,case datepart(month,Dateadd(month,-3,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11  end As FourMonthsAgo
 ,case datepart(month,Dateadd(month,-4,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11  end As FiveMonthsAgo
 ,case datepart(month,Dateadd(month,-5,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11  end As SixMonthsAgo
 ,case datepart(month,Dateadd(month,-6,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11  end As SevenMonthsAgo
 ,case datepart(month,Dateadd(month,-7,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11  end As EightMonthsAgo
 ,case datepart(month,Dateadd(month,-8,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11  end As NineMonthsAgo
 ,case datepart(month,Dateadd(month,-9,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11  end As TenMonthsAgo
 ,case datepart(month,Dateadd(month,-10,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11 end As ElevenMonthsAgo
 ,case datepart(month,Dateadd(month,-11,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11 end As TwelveMonthsAgo
    from ProductUsage
或者,如果确实需要将月份的名称作为列标题,则可以执行以下操作:

declare @month varchar(10)
set @month= DateName(month,DateAdd(month, -1,getDate()))
declare @TwoMonthsAgo varchar(10)
set @TwoMonthsAgo= DateName(month,DateAdd(month, -2,getDate()))
declare @Threemonthsago varchar(10)
set @Threemonthsago= DateName(month,DateAdd(month, -3,getDate()))
declare @fourmonthsago varchar(10)
set @fourmonthsago= DateName(month,DateAdd(month, -4,getDate()))
declare @fivemonthsago varchar(10)
set @fivemonthsago= DateName(month,DateAdd(month, -5,getDate()))
declare @sixmonthsago varchar(10)
set @sixmonthsago= DateName(month,DateAdd(month, -6,getDate()))
declare @sevenmonthsago varchar(10)
set @sevenmonthsago= DateName(month,DateAdd(month, -7,getDate()))
declare @eightmonthsago varchar(10)
set @eightmonthsago= DateName(month,DateAdd(month, -8,getDate()))
declare @ninemonthsago varchar(10)
set @ninemonthsago= DateName(month,DateAdd(month, -9,getDate()))
declare @tenmonthsago varchar(10)
set @tenmonthsago= DateName(month,DateAdd(month, -10,getDate()))
declare @elevenmonthsago varchar(10)
set @elevenmonthsago= DateName(month,DateAdd(month, -11,getDate()))
declare @twelvemonthsago varchar(10)
set @twelvemonthsago= DateName(month,DateAdd(month, -12,getDate()))
declare @query varchar(3800)
set @query =
'select ProductId, case datepart(month,getdate()) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11   end as '+@month+' '+
 ',case datepart(month,Dateadd(month,-1,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11 end As '+@TwoMonthsAgo+' '+
 ',case datepart(month,Dateadd(month,-2,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11 end As '+@ThreeMonthsAgo+' '+
 ',case datepart(month,Dateadd(month,-3,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11 end As '+@FourMonthsAgo+' '+
 ',case datepart(month,Dateadd(month,-4,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11 end As '+@FiveMonthsAgo+' '+
 ',case datepart(month,Dateadd(month,-5,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11 end As '+@SixMonthsAgo+' '+
 ',case datepart(month,Dateadd(month,-6,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11 end As '+@SevenMonthsAgo+' '+
 ',case datepart(month,Dateadd(month,-7,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11 end As '+@EightMonthsAgo+' '+
 ',case datepart(month,Dateadd(month,-8,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11 end As '+@NineMonthsAgo+' '+
 ',case datepart(month,Dateadd(month,-9,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11 end As '+@TenMonthsAgo+' '+
 ',case datepart(month,Dateadd(month,-10,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11 end AS '+@ElevenMonthsAgo+' '+
 ',case datepart(month,Dateadd(month,-11,getdate())) when 1 then Month12 when 2 then Month1 when 3 then  Month2 when 4 then  Month3 when 5 then  Month4 when 6 then  Month5 when 7 then  Month6 when 8 then  Month7 when 9 then  Month8 when 10 then  Month9 when 11 then  Month10 when 12 then  Month11 end AS '+@TwelveMonthsAgo+' '+
' From ProductUsage'
exec (@query)

现在,请原谅,我想我需要洗个澡

我想你可能正在寻找SQL视图:这会变得很糟糕。表是否可以重写为只有三列ProductID | Month | Value?然后这是一个简单的Where谓词和pivot的cakewalk。您是否在寻找一个动态查询,根据当前的_日期从表中选择[month 2]、[month 1]、[month 12]?明年这个表有什么好处?处理这个问题的巧妙方法是修复设计。这里有一个非规范化的噩梦。按照@JNevill所说的去做,这是毫无痛苦的。这实际上是一个不,不容易的回答。您正在使用字符串聚合来创建一个带有FOR XML路径的SQL字符串。