外部应用内的 WITH 语句

问题描述

我使用 for xml path 来聚合值:

select max(x.Ids),max(x.Number),(select country,city for json path) as [Json]
from t
outer apply (
    select Stuff((select ',' + Convert(varchar(10),t2.Id)
    from t t2
    where t2.city=t.city and t2.country=t.country
    for xml path(''),type).value('(./text())[1]','varchar(10)'),1,'') as Ids,Stuff((select ',t2.Number)
    from t t2
    where t2.city=t.city and t2.country=t.country
    for xml path(''),'') as Numbers
)x

outer apply 中的选择案例/查询是相同的。我想知道是否可以重用这个查询?我尝试在 outer apply 内创建 CTE,但这似乎不被 sql Server 接受:

select max(x.Ids),city for json path) as [Json]
from t
outer apply (
    with Test_CTE( Id,Number) AS (
        SELECT ID,Number FROM t t2
        where t2.city=t.city and t2.country=t.country
    )
    select Stuff((select ',t2.Id)
    from Test_CTE t2        
    for xml path(''),t2.Number)
    from Test_CTE t2 
    for xml path(''),'') as Numbers
)x

上述尝试给出了以下错误

关键字“with”附近的语法不正确。

解决方法

在您的 for xml 中,您可以包含两列,避免使用“,”连接,并保留列的名称,以便输出的值包含在元素中。

然后,在外层逻辑中,您可以查询有问题的特定元素,转换为字符串,用空字符串替换结束标记,用逗号替换开始标记,并用{{1}杀死第一个逗号}.

在开始保存一些处理之前,您也可以考虑对源应用 stuff 子句。

所以,对于这样的数据:

distinct

你可以这样做:

declare @t table (Id int,Number int,country char(1),city char(1));
insert @t values 
    (1,101,'a','z'),(2,102,'b','y'),(3,103,'z');

得到这样的输出:

杰森 ID 数字
[{"country":"b","city":"y"}] 2 102
[{"country":"a","city":"z"}] 1,3 101,103

但我不知道您是否认为新方法比原始方法更优雅。我会说它是,但仍然很丑陋。请记住,较新版本的 sql server 具有 select [Json] = (select t.country,t.city for json path),Ids = stuff(replace(replace(convert(varchar(max),ap._xml.query('./Id') ),'<Id>',','),'</Id>',''),1,Nums = stuff(replace(replace(convert(varchar(max),ap._xml.query('./Number') ),'<Number>','</Number>','') from (select distinct t.city,t.country from @t t) t cross apply (select _xml = ( select t2.Id,t2.Number from @t t2 where t2.city = t.city and t2.country = t.country for xml path(''),type )) ap; 函数,可为您完成所有这些工作。