使用concat变量选择Sql列

使用concat变量选择Sql列,sql,sql-server,Sql,Sql Server,我见过类似的问题,但都不完全符合我的需要。我有一个12个月的滚动表,列为PL0到PL12。PL0=当前月份,PL1=下个月,等等。我正在尝试设置日历年1月至12月的结果,该结果将选择PL0进入当前月份,PL1进入下个月,等等。前几个月应返回0。我需要能够根据使用月数的计算动态选择列 这是我想做的,但我知道这不对:) 9月份的结果应该是: JanPL |FebPL |MarPL |AprPL |MayPL |JunPL |JulPL |AugPL |SepPL

我见过类似的问题,但都不完全符合我的需要。我有一个12个月的滚动表,列为PL0到PL12。PL0=当前月份,PL1=下个月,等等。我正在尝试设置日历年1月至12月的结果,该结果将选择PL0进入当前月份,PL1进入下个月,等等。前几个月应返回0。我需要能够根据使用月数的计算动态选择列

这是我想做的,但我知道这不对:)

9月份的结果应该是:

JanPL     |FebPL   |MarPL   |AprPL   |MayPL   |JunPL   |JulPL   |AugPL   |SepPL   |OctPL   |NovPL    |DecPL

PL0 data|PL1 data|PL2 data|PL3 data|PL4 data|PL5 data|PL6 data|PL7 data|PL8 data|PL9 data|PL10 data|PL11 data
JanPL---|FebPL |MarPL |AprPL |MayPL |JunPL |JulPL |AugPL |SepPL   |OctPL   |NovPL   |DecPL   |
0      0      0      0      0      0      0      0      PL0 data|PL1 data|Pl2 data|PL3 data|
如何根据定义的concat字符串选择列


提前感谢您提供的帮助/见解。

您的思路是正确的,但是使用“普通”SQL,您无法像您在示例中尝试的那样动态生成列名。为此,您需要求助于SQL“编程”并创建一个存储过程,这(我想)不在您在这里尝试做的范围之内

因此,我对您的方法进行了调整/扩展,如下所示,我用示例数据对其进行了测试,如下所示。虽然它与它有一定的对称性,并且似乎满足了你的要求,但它并不完全简洁或漂亮(!)

WITH myMonth(mm) AS (SELECT MONTH(GETDATE())),
myData(PL0, PL1, PL2, PL3, PL4, PL5, PL6, PL7, PL8, PL9, PL10, PL11) AS
(SELECT 100, 220, 150, 60, 230, 40, 90, 120, 30, 50, 145, 210)
SELECT
CASE WHEN mm = 1 THEN PL0 ELSE 0 END AS JanPL,
CASE WHEN mm = 1 THEN PL1  WHEN mm = 2 THEN PL0 ELSE 0 END AS FebPL,
CASE WHEN mm = 1 THEN PL2  WHEN mm = 2 THEN PL1  WHEN mm = 3 THEN PL0 ELSE 0 END AS MarPL,
CASE WHEN mm = 1 THEN PL3  WHEN mm = 2 THEN PL2  WHEN mm = 3 THEN PL1 WHEN mm = 4 THEN PL0 ELSE 0 END AS AprPL,
CASE WHEN mm = 1 THEN PL4  WHEN mm = 2 THEN PL3  WHEN mm = 3 THEN PL2 WHEN mm = 4 THEN PL1 WHEN mm = 5 THEN PL0 ELSE 0 END AS MayPL,
CASE WHEN mm = 1 THEN PL5  WHEN mm = 2 THEN PL4  WHEN mm = 3 THEN PL3 WHEN mm = 4 THEN PL2 WHEN mm = 5 THEN PL1 WHEN mm = 6 THEN PL0 ELSE 0 END AS JunPL,
CASE WHEN mm = 1 THEN PL6  WHEN mm = 2 THEN PL5  WHEN mm = 3 THEN PL4 WHEN mm = 4 THEN PL3 WHEN mm = 5 THEN PL2 WHEN mm = 6 THEN PL1 WHEN mm = 7 THEN PL0 ELSE 0 END AS JulPL,
CASE WHEN mm = 1 THEN PL7  WHEN mm = 2 THEN PL6  WHEN mm = 3 THEN PL5 WHEN mm = 4 THEN PL4 WHEN mm = 5 THEN PL3 WHEN mm = 6 THEN PL2 WHEN mm = 7 THEN PL1 WHEN mm = 8 THEN PL0 ELSE 0 END AS AugPL,
CASE WHEN mm = 1 THEN PL8  WHEN mm = 2 THEN PL7  WHEN mm = 3 THEN PL6 WHEN mm = 4 THEN PL5 WHEN mm = 5 THEN PL4 WHEN mm = 6 THEN PL3 WHEN mm = 7 THEN PL2 WHEN mm = 8 THEN PL1 WHEN mm = 9 THEN PL0 ELSE 0 END AS SepPL,
CASE WHEN mm = 1 THEN PL9  WHEN mm = 2 THEN PL8  WHEN mm = 3 THEN PL7 WHEN mm = 4 THEN PL6 WHEN mm = 5 THEN PL5 WHEN mm = 6 THEN PL4 WHEN mm = 7 THEN PL3 WHEN mm = 8 THEN PL2 WHEN mm = 9 THEN PL1 WHEN mm = 10 THEN PL0 ELSE 0 END AS OctPL,
CASE WHEN mm = 1 THEN PL10 WHEN mm = 2 THEN PL9  WHEN mm = 3 THEN PL8 WHEN mm = 4 THEN PL7 WHEN mm = 5 THEN PL6 WHEN mm = 6 THEN PL5 WHEN mm = 7 THEN PL4 WHEN mm = 8 THEN PL3 WHEN mm = 9 THEN PL2 WHEN mm = 10 THEN PL1 WHEN mm = 11 THEN PL0 ELSE 0 END AS NovPL,
CASE WHEN mm = 1 THEN PL11 WHEN mm = 2 THEN PL10 WHEN mm = 3 THEN PL9 WHEN mm = 4 THEN PL8 WHEN mm = 5 THEN PL7 WHEN mm = 6 THEN PL6 WHEN mm = 7 THEN PL5 WHEN mm = 8 THEN PL4 WHEN mm = 9 THEN PL3 WHEN mm = 10 THEN PL2 WHEN mm = 11 THEN PL1 WHEN mm = 12 THEN PL0 ELSE 0 END AS DecPL
FROM myData, myMonth

首先,我建议将这种逻辑转移到应用程序代码中,在应用程序代码中,编程语言更适合这种情况

只有12个月和12个可能的案例(不同的当前月份),替代方法是将所有案例“硬编码”到单独的表中,并将其加入到结果中

DECLARE @Months AS TABLE (CurrentMonth INT
    , Jan VARCHAR(10)
    , Feb VARCHAR(10)
    , Mar VARCHAR(10)
    , Apr VARCHAR(10)
    , May VARCHAR(10)
    , Jun VARCHAR(10)
    , Jul VARCHAR(10)
    , Aug VARCHAR(10)
    , Sep VARCHAR(10)
    , Oct VARCHAR(10)
    , Nov VARCHAR(10)
    , Dec VARCHAR(10)
)
INSERT INTO @Months VALUES
(1, 'PL0', 'PL1', 'PL2', 'PL3', 'PL4', 'PL5', 'PL6', 'PL7', 'PL8', 'PL9', 'PL10', 'PL11'),
(2, 'PL0', 'PL0', 'PL1', 'PL2', 'PL3', 'PL4', 'PL5', 'PL6', 'PL7', 'PL8', 'PL9', 'PL10'),
(3, 'PL0', 'PL0', 'PL0', 'PL1', 'PL2', 'PL3', 'PL4', 'PL5', 'PL6', 'PL7', 'PL8', 'PL9'),
(4, 'PL0', 'PL0', 'PL0', 'PL0', 'PL1', 'PL2', 'PL3', 'PL4', 'PL5', 'PL6', 'PL7', 'PL8'),
(5, 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL1', 'PL2', 'PL3', 'PL4', 'PL5', 'PL6', 'PL7'),
(6, 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL1', 'PL2', 'PL3', 'PL4', 'PL5', 'PL6'),
(7, 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL1', 'PL2', 'PL3', 'PL4', 'PL5'),
(8, 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL1', 'PL2', 'PL3', 'PL4'),
(9, 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL1', 'PL2', 'PL3'),
(10, 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL1', 'PL2'),
(11, 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL1'),
(12, 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0', 'PL0');
用法

九月份选举结果:

'PL0 d', 'PL0 d', 'PL0 d', 'PL0 d', 'PL0 d', 'PL0 d', 'PL0 d', 'PL0 d', 'PL0 d', 'PL1 d', 'PL2 d', 'PL3 d'

这种类型的移位操作在SQL中有点棘手。一种选择是取消你拥有的月份,并为它们指定一个真实的日期。这很容易使用
apply
。然后根据日期重新汇总

然后,您可以使用所需的逻辑进行聚合:

  • 您只需要当前年份的日期
  • 您希望当前月份之前的日期
    NULL
    ed out
  • 您希望“pl”值位于相应的月份列中
这可以组合成如下查询:

select t.*, v.*
from t cross apply
     (select max(case when month(getdate()) = 1 and month(v.yyyymm) = 1 then v.pl end) as jan,
             max(case when month(getdate()) <= 2 and month(v.yyyymm) = 2 then v.pl end) as feb,
             max(case when month(getdate()) <= 3 and month(v.yyyymm) = 3 then v.pl end) as mar,
            . . .  
      from (values (datefromparts(year(getdate()), month(getdate()), 1))
           ) d(cur_yyyymm) cross apply
           (values (pl0, dateadd(month, 0, d.cur_yyyymm)),
                   (pl1, dateadd(month, 1, d.cur_yyyymm)),
                   (pl2, dateadd(month, 2, d.cur_yyyymm)),
                   . . . 
                   (pl12, dateadd(month, 12, d.cur_yyyymm))
           ) v(pl, yyyymm)
       where year(v.yyyymm) = year(getdate())
    ) v;
选择t.*,v*
从t交叉应用
(选择最大值(当月份(getdate())=1,月份(v.yyyymm)=1,然后选择v.pl end)作为一月,

max(case when month(getdate())您应该修复数据设计,而不是走这条路。每个月都应该存储在单独的行中,而不是列中。
'PL0 d', 'PL0 d', 'PL0 d', 'PL0 d', 'PL0 d', 'PL0 d', 'PL0 d', 'PL0 d', 'PL0 d', 'PL1 d', 'PL2 d', 'PL3 d'
select t.*, v.*
from t cross apply
     (select max(case when month(getdate()) = 1 and month(v.yyyymm) = 1 then v.pl end) as jan,
             max(case when month(getdate()) <= 2 and month(v.yyyymm) = 2 then v.pl end) as feb,
             max(case when month(getdate()) <= 3 and month(v.yyyymm) = 3 then v.pl end) as mar,
            . . .  
      from (values (datefromparts(year(getdate()), month(getdate()), 1))
           ) d(cur_yyyymm) cross apply
           (values (pl0, dateadd(month, 0, d.cur_yyyymm)),
                   (pl1, dateadd(month, 1, d.cur_yyyymm)),
                   (pl2, dateadd(month, 2, d.cur_yyyymm)),
                   . . . 
                   (pl12, dateadd(month, 12, d.cur_yyyymm))
           ) v(pl, yyyymm)
       where year(v.yyyymm) = year(getdate())
    ) v;