在 stuff、stuff unique 和 order by 中应用排序

Z.R*_*.T. 3 sql t-sql sql-server sql-server-2008

我需要使用 STUFF 运算符将具有相同值的行合并为一个。我存档了行串联,但值的顺序不正确。

http://www.sqlfiddle.com/#!18/2f420/1/0

正如您在结果窗口中看到的,TypeB 位于 TypeA 旁边,但 Amount 值的序列与 Type 值不对应,其中 0.09K 应位于 3k 旁边

在此输入图像描述

如何使 STUFF 具有不同的值并保存序列(按 rn 排序)?

create table SomeTable (Code int, Type nvarchar(50), Amount nvarchar(50), Date datetime);

insert into SomeTable VALUES(20, 'TypeA', '12k', cast('01/01/2019' as datetime));
insert into SomeTable VALUES(20, 'TypeA', '11k', cast('01/01/2018' as datetime));
insert into SomeTable VALUES(22, 'TypeA', '17k', cast('01/02/2017' as datetime));
insert into SomeTable VALUES(22, 'TypeA', '17k', cast('01/01/2017' as datetime));
insert into SomeTable VALUES(25, 'TypeB', '0.09k', cast('01/02/2019' as datetime));
insert into SomeTable VALUES(25, 'TypeA', '3k', cast('01/01/2019' as datetime));

with t as (

  select 
      row_number() over(partition by st.Code order by st.Date) as rn,
      st.Code, 
      st.Type, 
      st.Amount, 
      st.Date 
  from SomeTable st
)

select 
  t1.Code,
  stuff((select distinct ',' + t.Type from t 
         where t.Code = t1.Code
         for XML path('')), 1,1, '') as Type,
  stuff((select distinct ',' + t.Amount from t 
         where t.Code = t1.Code
         for XML path('')), 1,1, '') as Amount,
  t1.Date
from t as t1
where t1.rn = 1
order by t1.Date
Run Code Online (Sandbox Code Playgroud)

Zoh*_*led 9

对 SQL 中的任何结果应用排序是通过使用order by子句完成的。
这并不是这个stuff函数给你带来了困难,而是你没有order by为子查询指定 an 。
如果没有 andorder by子句,子查询会以任意顺序返回记录 - 这就是您得到现在结果的原因。
但请注意,由于结果的顺序是任意的,因此下次运行查询时可能会得到不同的结果。

因此,您必须order by在子查询中指定生成 CSV 列的子句。

现在我不太确定您期望什么顺序,但它可能是按rn或按排序rn desc(根据图像,我认为这是第一个)。
然而,这里有一个技巧 - 因为你想要不同的 和 值type,所以amount你不能简单地rnorder by子句中使用 - SQL Server 将引发以下错误:

如果指定了 SELECT DISTINCT,则 ORDER BY 项必须出现在选择列表中。

因此,诀窍是不要在子句中使用 use distinct,而是使用 use group by,并且不要rnorder by子句中使用 use but max(rn)。这样,你就得到TypeA,TypeB3k,0.09k- 而且它会是一致的。

话虽如此 - 这是代码的修订版本(cte 保持不变):

select  t1.Code,
  stuff((
            select ','+ t.Type
            from t 
            where t.Code = t1.Code
            group by t.Type
            order by max(rn) 
            for XML path('')
        ), 1,1, '') as Type,
  stuff((select ',' + t.Amount 
         from t 
         where t.Code = t1.Code
         group by  t.Amount 
         order by max(rn) 
         for XML path('')), 1,1, '') as Amount,
  t1.Date
from t as t1
where t1.rn = 1
order by t1.Date
Run Code Online (Sandbox Code Playgroud)

结果:

Code    Type            Amount      Date
22      TypeA           17k         2017-01-01
20      TypeA           11k,12k     2018-01-01
25      TypeA,TypeB     3k,0.09k    2019-01-01
Run Code Online (Sandbox Code Playgroud)

注意 萨尔曼对这个问题的评论(我现在才看到)有一个非常有效的观点 -distinct在这里可能根本不是一个好的选择。在您具有相应金额的
情况下- 如果您执行不同的操作,结果将是和 金额- 并且无法判断哪个金额属于哪种类型。TypeA, TypeB, TypeA10K, 11K, 12K
TypeA, TypeB10K, 11K, 12K