CREATE TABLE [arsenal] (
[id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[agent] INTEGER NOT NULL,
[haul] DECIMAL NOT NULL,
[target] INTEGER NOT NULL);
INSERT INTO arsenal (agent, haul, target) VALUES (1, 10, 2), (1, 100, 2), (2, 20, 1), (2, 200, 1);
我有一张看起来像这样的桌子。我想为每个用户获取所有haul
的总和,但用户分为两列agent
和target
。例如,具有用户id = 1的代理具有110的总和,而目标字段中的相同用户具有220的总和。因此有效总和是110 + 220 = 330.类似地,用户id = 2具有330的有效总和(代理列中220,目标列中110。)
如果我的来源是:
id agent haul target
1 1 10 2
2 1 100 2
3 2 20 1
4 2 200 1
,我需要输出:
user haul
1 330
2 330
。我可以通过以下方式实现这一目标:
SELECT user, SUM(sum)
FROM (
SELECT agent AS user, SUM(haul) AS sum
FROM arsenal
GROUP BY agent
UNION ALL
SELECT target, SUM(haul)
FROM arsenal
GROUP BY target
) AS t
GROUP BY user;
我正试图摆脱联盟,因为围绕Union All的实际选择查询有点复杂,所以我认为这是一个瓶颈。有没有更好的方法来实现这一点,可能没有子查询?
Here's a very similar thread但答案对我没有吸引力。感谢
修改:以下是实际查询:
SELECT user, SUM(sum)
FROM (
SELECT agent AS user, SUM(haul) AS sum
FROM arsenal AS a
JOIN bucket AS b ON b.parent_id=a.id
JOIN region AS r ON r.terminal = b.terminal
WHERE a.status=@status AND r.savedStatus=@savedStatus
GROUP BY agent
UNION ALL
SELECT target, SUM(haul)
FROM arsenal
JOIN bucket AS b ON b.parent_id=a.id
JOIN region AS r ON r.terminal = b.terminal
WHERE a.status=@status AND r.savedStatus=@savedStatus
GROUP BY target
) AS t
GROUP BY user;
此外,它在SELECT
中有更多字段。这里需要注意的是,它与SELECT
中的UNION
中运行两次的查询完全相同。所以我试图完全避免UNION
并依赖某种JOIN
左右来避免冗余。
答案 0 :(得分:2)
为了避免联合, 可以 加入另一个表,以有效地加倍行数。 (您的UNION ALL目前正在对行进行加倍。)
Agent
INNER JOIN
Haul
ON Agent.ID = Haul.Agent
OR Agent.ID = Haul.Target
但是连接只能使用一个索引。并且没有一个sinlgle索引完全满足OR条件。 您无法对记录进行排序,使您符合这两个标准;同一代理的记录彼此相邻,并且同一目标的记录彼此相邻。)
这里的通常的 SQL代码优化是您不喜欢的UNION ALL。
这可以通过将代理和目标字段移动到规范化表中来解决,其中包含以下字段:
- Haul_ID
- Agent_ID
- Is_Target
每个已经有两个记录......
HaulAgentMap
INNER JOIN
Haul
ON Haul.ID = HaulAgentMap.Haul_ID
HaulAgentMap上的单个索引也会将所有相应的记录保持在一起。
在 general 中,此类规范化有益于您的代码和性能。以及可维护性,适应性等等
(对不起,我正在打电话......)
修改强>
为了减少代码中的重复,但不太可能改变性能,你可以加入联盟......
(
SELECT id, Agent, val FROM haul
UNION ALL
SELECT id, Target, val FROM haul
)
AS haul
INNER JOIN
etc, etc
在生成查询计划时,RDBMS通常会将其扩展。换句话说,它将像您的原始查询一样,但代码中的重复次数较少。