STRING_AGG 具有特定标准

STRING_AGG with specific criteria

我进退两难,我可以转换以下示例数据:

declare @table table
(
    iTermID int
,   cTermDesc1 varchar(30)
,   cTermDesc2 varchar(30)
,   cTermDesc3 varchar(30)
,   cTermDesc4 varchar(30)
,   cTermDesc5 varchar(30)
,   cTermDesc6 varchar(30)
,   cTermDesc7 varchar(30)
)

insert into @table
(
    iTermID
,   cTermDesc1
,   cTermDesc2
,   cTermDesc3
,   cTermDesc4
,   cTermDesc5
,   cTermDesc6
,   cTermDesc7
)
values
    (1,'Current','30 Days','60 Days','90 Days','120 Days','150 Days','180 Days')
,   (3,'Current','30 Days','60 Days','90 Days','120 Days','150 Days','180 Days')
,   (4,'Current','7 Days','14 Days','21 Days','28 Days','35 Days','42 Days')
,   (5,'Current','14 Days','28 Days','42 Days','56 Days','70 Days','84 Days');

使用此脚本:

with cte as (
select
cTermDesc1+','+cTermDesc2+','+cTermDesc3+','+cTermDesc4+','+cTermDesc5+','+cTermDesc6+','+cTermDesc7    term
from    @table
)
,   data as (
select  distinct
Value
from    cte
outer apply string_split(term,',')
)
,   retur as (
select
Value
,
case Value
when 'Current'  then 1
when '7 Days'   then 2
when '14 Days'  then 3
when '21 Days'  then 4
when '28 Days'  then 5
when '35 Days'  then 6
when '42 Days'  then 7
when '56 Days'  then 8
when '70 Days'  then 9
when '84 Days'  then 10
when '30 Days'  then 11
when '60 Days'  then 12
when '90 Days'  then 13
when '120 Days' then 14
when '150 Days' then 15
when '180 Days' then 16
else 17 end sort
from    data
)

select
string_agg(quotename(Value),',') within group (order by sort desc)
from    retur

看起来像这样(预期结果)(fiddle):

[180 Days],[150 Days],[120 Days],[90 Days],[60 Days],[30 Days],[84 Days],[70 Days],[56 Days],[42 Days],[35 Days],[28 Days],[21 Days],[14 Days],[7 Days],[Current]

我需要获得与上述预期结果相同的结果,但不使用 CASE

我尝试将我的 CTE 更改为:

with cte as (
select
'1-'+cTermDesc1+','+'2-'+cTermDesc2+','+'3-'+cTermDesc3+','+'4-'+cTermDesc4+','+'5-'+cTermDesc5+','+'6-'+cTermDesc6+','+'7-'+cTermDesc7 term
from    @table
)
,   data as (
select  distinct
Value
from    cte
outer apply string_split(term,',')
)
,   retur as (
select
    substring(Value,charindex('-',Value,1)+1,20)    Value
,   left(Value,1) sort
from    data
)

select
string_agg(quotename(Value),',') within group (order by sort desc)
from    retur

但现在我没有得到与上面预期结果相同的订单。

结果:

[180 Days],[42 Days],[84 Days],[150 Days],[35 Days],[70 Days],[120 Days],[28 Days],[56 Days],[21 Days],[42 Days],[90 Days],[14 Days],[28 Days],[60 Days],[14 Days],[30 Days],[7 Days],[Current]

fiddle

是否有更简单的方法可以实现此目的?

请注意,我只需要返回一个“当前”

编辑

这是我的示例数据,其中包含代码:

declare @table table
(
    iTermID int
,   Code        varchar(30)
,   cTermDesc1  varchar(30)
,   cTermDesc2  varchar(30)
,   cTermDesc3  varchar(30)
,   cTermDesc4  varchar(30)
,   cTermDesc5  varchar(30)
,   cTermDesc6  varchar(30)
,   cTermDesc7  varchar(30)
)

insert into @table
(
    iTermID
,   Code
,   cTermDesc1
,   cTermDesc2
,   cTermDesc3
,   cTermDesc4
,   cTermDesc5
,   cTermDesc6
,   cTermDesc7
)
values
    (1,'MNTH-INV','Current','30 Days','60 Days','90 Days','120 Days','150 Days','180 Days')
,   (3,'MNTH-STM','Current','30 Days','60 Days','90 Days','120 Days','150 Days','180 Days')
,   (4,'7 Days','Current','7 Days','14 Days','21 Days','28 Days','35 Days','42 Days')
,   (5,'14 Days','Current','14 Days','28 Days','42 Days','56 Days','70 Days','84 Days')

这是一个通用版本,它将始终按顺序将 MNTH-INVMNTH-STM 的值放在 7 days14 days 的值之前。它为问题中的输入给出了正确的值序列。

很难确定这是否在所有情况下都是正确的,因为定义顺序的规则没有在 question/comments 中明确给出。

(这里的所有逻辑都是在没有 CASE 的情况下编写的,因为当我在处理它时我没有看到解释为什么 OP 要避免 CASE 的评论)

;WITH grpCTE
AS
(
    SELECT  v.grp,
            t.cTermDesc1,t.cTermDesc2,t.cTermDesc3,t.cTermDesc4,t.cTermDesc5,t.cTermDesc6,t.cTermDesc7
    FROM    @table AS t
    JOIN    (VALUES (1,1),(3,1), (4,2), (5,2)) AS v(iTermID, grp)
    ON      v.iTermID = t.iTermID
) 
,valuesCTE
AS
(

    SELECT grp, cTermDesc1 AS dayCount FROM grpCTE
    UNION
    SELECT grp, cTermDesc2 AS dayCount FROM grpCTE
    UNION                              
    SELECT grp, cTermDesc3 AS dayCount FROM grpCTE
    UNION                              
    SELECT grp, cTermDesc4 AS dayCount FROM grpCTE
    UNION                              
    SELECT grp, cTermDesc5 AS dayCount FROM grpCTE
    UNION                              
    SELECT grp, cTermDesc6 AS dayCount FROM grpCTE
    UNION                              
    SELECT grp, cTermDesc7 AS dayCount FROM grpCTE
)
,aggCTE
AS
(
    SELECT STRING_AGG(QUOTENAME(dayCount),',') WITHIN GROUP (ORDER BY grp, TRY_CAST(LEFT(dayCount,3) AS INT) desc) AS retur
    FROM    valuesCTE
    WHERE TRY_CAST(LEFT(dayCount,3) AS INT) IS NOT NULL
)
SELECT CONCAT(retur, ',[' + v.dayCount + ']') AS retur
FROM aggCTE AS a
OUTER 
APPLY (SELECT TOP(1) dayCount FROM  valuesCTE WHERE dayCount = 'Current') AS v