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]
是否有更简单的方法可以实现此目的?
请注意,我只需要返回一个“当前”
编辑
这是我的示例数据,其中包含代码:
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-INV
和 MNTH-STM
的值放在 7 days
和 14 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
我进退两难,我可以转换以下示例数据:
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]
是否有更简单的方法可以实现此目的?
请注意,我只需要返回一个“当前”
编辑
这是我的示例数据,其中包含代码:
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-INV
和 MNTH-STM
的值放在 7 days
和 14 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