每个用户的字段总和,但分为两列

时间:2012-11-10 07:22:30

标签: select sqlite

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的总和,但用户分为两列agenttarget。例如,具有用户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左右来避免冗余。

1 个答案:

答案 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通常会将其扩展。换句话说,它将像您的原始查询一样,但代码中的重复次数较少。