外部应用中的 WITH 语句

WITH-statement inside Outer Apply

我正在使用 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,1,'') as Ids,
    Stuff((select ',' + Convert(varchar(10),t2.Number)
    from t t2
    where t2.city=t.city and t2.country=t.country
    for xml path(''),type).value('(./text())[1]','varchar(10)'),1,1,'') as Numbers
)x

outer apply里面的select-cases/queries是一样的。我想知道是否可以重用这个查询?我尝试在 outer apply 中创建一个 CTE,但这似乎不被 SQL 服务器接受:

select max(x.Ids), max(x.Number), (select country,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 ',' + Convert(varchar(10),t2.Id)
    from Test_CTE t2        
    for xml path(''),type).value('(./text())[1]','varchar(10)'),1,1,'') as Ids,
    Stuff((select ',' + Convert(varchar(10),t2.Number)
    from Test_CTE t2 
    for xml path(''),type).value('(./text())[1]','varchar(10)'),1,1,'') as Numbers
)x

以上尝试出现以下错误:

Incorrect syntax near the keyword 'with'.

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

然后,在外层逻辑中,可以查询具体的有问题的元素,转换为字符串,结束标签替换为空字符串,开始标签替换为逗号,第一个逗号用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, 'a', 'z');

你可以这样做:

select      [Json] = (select t.country, t.city for json path),
        
            Ids = stuff(replace(replace(convert(varchar(max),
                ap._xml.query('./Id')
            ),'<Id>', ','),'</Id>',''), 1, 1, ''),
        
            Nums = stuff(replace(replace(convert(varchar(max),
                ap._xml.query('./Number')
            ),'<Number>', ','),'</Number>',''), 1, 1, '')

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;

并得到这样的输出:

Json Ids Nums
[{"country":"b","city":"y"}] 2 102
[{"country":"a","city":"z"}] 1,3 101,103

但我不知道你是否认为新方法比原来的方法更优雅。我会说它是,但仍然很丑陋。请记住,较新版本的 sql 服务器具有 string_agg 功能,可以为您完成这一切。