连接列时是否可以避免 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
.
,实际上都没有区别
我有一个 "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
.