【问题标题】:STRING_AGG with specific criteria具有特定条件的 STRING_AGG
【发布时间】:2020-07-20 07:06:54
【问题描述】:

我有一个难题,我能够转换以下示例数据:

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')

【问题讨论】:

  • 你能稍微改变一下数据库结构吗?
  • 不幸的是不是@ZoharPeled,因此我不得不解决它......
  • 你能解释一下这个特定顺序的逻辑吗?起初我以为只是天数递减,但后来我说你在 84 天之前有 60 天和 30 天,所以现在我很困惑。
  • 谢谢@ZoharPeled,我之所以需要它,是因为它必须在 Pivot 中显示。 (我正在动态旋转上面的内容)所以我从这个脚本中得到的结果是我的动态透视的列名......
  • 我真的不在乎为什么你需要这个顺序,我更想知道规定这个顺序的逻辑。我的意思是,为什么180 days150 days 之前,而60 days84 days 之前?

标签: tsql sql-server-2017


【解决方案1】:

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

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

(这里的所有逻辑都是在没有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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-14
    相关资源
    最近更新 更多