有效地从子查询中选择多个列(放置在 SELECT 线索中)
Posted
技术标签:
【中文标题】有效地从子查询中选择多个列(放置在 SELECT 线索中)【英文标题】:SELECT Multiple Columns FROM a subquery (placed in the SELECT Clues) Efficiently 【发布时间】:2019-10-03 04:55:15 【问题描述】:我有 3 张桌子:
-
表A
表B
表C
我需要对其中的一些列执行几个聚合函数(COUNT 和 SUM)。
我没有找到将它们连接在一起的方法(即使使用下面的 ClientId 列)所以我尝试了:
SELECT
(SELECT COUNT(*) FROM TableA
WHERE ClientId = 2 AND IsDisabled != 1 AND IsDeleted != 1) AS ColumnName1,
(SELECT COUNT(*) FROM TableB
WHERE ClientId = 2 AND DisabledWhen IS NULL) AS ColumnName2,
(SELECT COUNT(*) FROM TableC
WHERE ClientId = 2 AND TDate >= CURRENT_TIMESTAMP -30) AS ColumnName3,
(SELECT SUM(TPrice + COALESCE (PPrice,0)) FROM TableC
WHERE ClientId = 2 AND TDate >= CURRENT_TIMESTAMP -30) AS ColumnName4;
它正在工作,结果是:
+--------------+-------------+-------------+--------------+
| ColumnName1 | ColumnName2 | ColumnName3 | ColumnName4 |
+--------------+-------------+-------------+--------------+
| 202 | 86 | 25 | 4574.0000 |
+--------------+-------------+-------------+--------------+
但我想将最后两个子查询合并为一个子查询。
所以我尝试这样做:
(SELECT COUNT(*) AS ColumnName3, SUM(TPrice + COALESCE (PPrice,0)) AS ColumnName4 FROM TableC
WHERE ClientId = 2 AND TDate >= CURRENT_TIMESTAMP -30);
但我收到此错误:
不引入子查询EXISTS时,选择列表中只能指定一个表达式。
如何从一个子查询中获取多个列?
进行上述查询的有效方法是什么?
【问题讨论】:
如果您为单个客户端 ID 执行此操作,那么问题已得到解答。如果您想要跨多个客户端进行查询,那么使用表之间的连接可能有更好的方法。但是您必须向我们提供有关架构的一些信息,以便我们回答。 @TOMC 这是针对单个客户端 ID 【参考方案1】:您可以将TableC
上的查询移动到最外层的选择,保持前两个子查询不变:
SELECT
(SELECT COUNT(*) FROM TableA
WHERE ClientId = 2 AND IsDisabled != 1 AND IsDeleted != 1) AS ColumnName1,
(SELECT COUNT(*) FROM TableB
WHERE ClientId = 2 AND DisabledWhen IS NULL) AS ColumnName2,
COUNT(*) AS ColumnName3,
SUM(TPrice + COALESCE (PPrice, 0)) AS ColumnName4
FROM TableC
WHERE
ClientId = 2 AND
TDate >= CURRENT_TIMESTAMP - 30;
之所以有效,是因为前两个子查询基本上被视为常量。查询的其余部分仅在 TableC
上运行,让我们选择多个聚合。
【讨论】:
非常感谢,它运行良好!在大表中效率高吗? 其实这不是一个很有效的方法,你可以在count函数中只使用主键列,比如COUNT(Id)。但是此时您必须考虑为什么需要它,请检查整个架构,如果这是一种报告或类似的东西,这是您唯一拥有的有效方法。 @Dogan 相反,如果 OP 想要从 3 个不同的表中进行 4 个计数,这种方法是有效的,只需要扫描三个表中的每一个。 @tim-biegeleisen,乍一看你是对的,但后来我认为 tableC 末尾的条件看起来像返回很多行,所以这不意味着子查询将被执行得尽可能多作为行数?所以这会导致性能下降? @Dogan 我敢打赌,SQL Server 优化器足够聪明,可以识别出TableA
和TableB
表上的子查询与外部查询不相关在TableC
表上。因此,它只会运行一次子查询,然后在某处缓存计数。所以,我的回答比你想象的更有效率。以上是关于有效地从子查询中选择多个列(放置在 SELECT 线索中)的主要内容,如果未能解决你的问题,请参考以下文章