连接列时是否可以避免 select 中的子查询?

Is it possible to avoid subquery in select when concatenating columns?

我有一个 "main" table 包含一个 id(加上一些其他列)和一个又名 table,它通过 [main id] 列连接到 main.id.以下查询 returns 来自 main 的一些列以及来自 aka 的一列以逗号分隔的连接的 "lastName"s:

SELECT m.id, m.name, 
   (SELECT a.[lastname] + ',' AS [text()] 
    FROM   aka a 
    WHERE  a.[main id] = m.[id] 
    FOR xml path ('')) [akas] 
FROM   main m 

这很好用,但我想知道是否有办法避免在子查询中这样做?

由于您有任意数量的记录组合成最终字符串,因此您所拥有的是在 SQL 中执行此操作的最佳选择。通常,您应该 return 每个项目一行,如果您想要 CSV 字符串,请在您的客户端代码中构建它。

使用 CROSS APPLY 您可以从 SELECT 列表中移动子查询:

SELECT m.id, m.name, 
   (SELECT a.[lastname] + ',' AS [text()] 
    FROM   aka a 
    WHERE  a.[main id] = m.[id] 
    FOR xml path ('')) [akas] 
FROM   main m;

至:

SELECT m.id, m.name, s.akas
FROM   main m
CROSS APPLY (SELECT a.[lastname] + ',' AS [text()] 
             FROM   aka a 
             WHERE  a.[main id] = m.[id] 
             FOR xml path ('')) AS s(akas)

备注:

  • 您可以多次参考s.akas
  • 您可以添加 WHERE s.akas ...
  • SELECT 列表中的长子查询可读性较差
  • 如果可能关联子查询 return 没有行,则需要使用 OUTER APPLY 代替。

一般来说,从技术角度来看没有什么反对子查询的...

由于可读性或多参考,您可能更喜欢 APPLY

每当您将子查询直接放入列的列表中时,如下所示:

SELECT Column1
      ,Column2
      ,(SELECT x FROM y) AS Column3
      ,[...]

...本次select必须投递

  • 只有一栏
  • 只有一行

使用FOR XML PATH(''),TYPE 使结果成为XML 类型的单个值。这使得 return 许多 rows/columns "as one" 成为可能。没有 ,TYPE 它将是 XML "as text"。 XML 的连接技巧是可能的,因为 XML 的生成具有空标签名称和 return "as text" 的特性。但在任何情况下:returned 值将只是一个信息位,因此适合列列表。

每当你期望多行时,你必须强制这是一个数据位(比如 - 经常看到! - SELECT TOP 1 x FROM y ORDER BY SomeSortKey,它带回第一个或最后一个或.. .)

获取 1:n 数据的所有其他意图需要 'JOIN' 或 'APPLY'。对于标量数据,就像您的情况一样,无论您使用子 select 还是 APPLY.

,实际上都没有区别