【问题标题】:Is it possible to avoid subquery in select when concatenating columns?连接列时是否可以避免选择中的子查询?
【发布时间】:2016-04-30 20:05:58
【问题描述】:

我有一个“主”表,其中包含一个 id(加上一些其他列)和一个通过 [main id] 列连接到 main.id 的 aka 表。以下查询从 main 中返回一些列以及来自 aka 的连接逗号分隔的“lastName”列:

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 

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

【问题讨论】:

  • 不使用子查询,在最终选择结果之前,您可能仍然需要加入 2 个表。
  • 你有什么理由不能用 aka 加入 main 吗?有什么特别的,所以你用于 xml 路径?
  • 您可以创建自己的 CLR 聚合,然后它将是一个没有子查询的普通 group by

标签: sql-server subquery


【解决方案1】:

使用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 列表中的长子查询可能不太可读
  • 如果相关子查询可能不返回任何行,则需要使用 OUTER APPLY

【讨论】:

    【解决方案2】:

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

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

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

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

    ...这个子选择必须交付

    • 只有一列
    • 只有一排

    使用FOR XML PATH(''),TYPE 让结果是一个XML 类型的单一值。这使得可以“作为一个”返回许多行/列。如果没有,TYPE,它将是“作为文本”的 XML。由于生成带有空标签名称并返回“作为文本”的 XML 的特殊性,使用 XML 的连接技巧是可能的。但无论如何:返回的值将只是一点信息,因此适合列列表。

    每当您期望不止一行时,您都必须将其强制为一位数据(例如 - 经常看到!-SELECT TOP 1 x FROM y ORDER BY SomeSortKey,这会带回第一行或最后一行或......)

    获取 1:n 数据的所有其他意图都需要“加入”或“应用”。对于标量数据,就像您的情况一样,无论您使用子选择还是APPLY,实际上都没有区别。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2016-06-20
        • 1970-01-01
        • 2020-05-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多