繁体   English   中英

使用SUM()在3个表上进行INNER JOIN

[英]INNER JOIN on 3 tables with SUM()

我在尝试在总共三个表中进行联接时遇到问题:

  • 表用户:用户ID,上限(ADSL带宽)
  • 表计费:用户标识,会话日期,已用带宽
  • 临时表:用户名,日期,购买金额

我想要一个查询,该查询返回一组所有用户,其上限,本月使用的带宽以及本月的临时购买:

< TABLE 1 ><TABLE2><TABLE3>
User   | Cap | Adhoc | Used
marius | 3   | 1     | 3.34
bob    | 1   | 2     | 1.15
(simplified)

这是我正在处理的查询:

SELECT
        `msi_adsl`.`id`,
        `msi_adsl`.`username`,
        `msi_adsl`.`realm`,
        `msi_adsl`.`cap_size` AS cap,
        SUM(`adsl_adhoc`.`value`) AS adhoc,
        SUM(`radacct`.`AcctInputOctets` + `radacct`.`AcctOutputOctets`) AS used
FROM
        `msi_adsl`
INNER JOIN
        (`radacct`, `adsl_adhoc`)
ON
        (CONCAT(`msi_adsl`.`username`,'@',`msi_adsl`.`realm`) 
           = `radacct`.`UserName` AND `msi_adsl`.`id`=`adsl_adhoc`.`id`)

WHERE
        `canceled` = '0000-00-00'
AND
        `radacct`.`AcctStartTime`
BETWEEN
        '2010-11-01'
AND
        '2010-11-31'
AND
        `adsl_adhoc`.`time`
BETWEEN
        '2010-11-01 00:00:00'
AND
        '2010-11-31 00:00:00'
GROUP BY
        `radacct`.`UserName`, `adsl_adhoc`.`id` LIMIT 10

该查询有效,但是它会为adhoc和used返回错误的值; 我的猜测是联接中的逻辑错误,但我看不到它。 很感谢任何形式的帮助。

您的查询布局太分散了,无法满足我的口味。 特别是,BETWEEN / AND条件应分别位于1行,而不是5行。 我还删除了反引号,尽管“时间”列可能需要它们。

由于您的表布局与示例查询不匹配,因此使工作变得非常困难。 但是,表布局都包含一个UserID(这是明智的),因此我编写了查询以使用UserID进行相关的联接。 正如我在评论中指出的那样,如果您的设计有必要使用CONCAT操作来连接两个表,那么您将有可能导致性能下降。 更新您的实际架构,以便表可以通过UserID进行联接,因为表布局建议应该可行。 显然,您可以在联接中使用函数结果,但是(除非您的DBMS支持“函数索引”,并且您创建了适当的索引),否则DBMS将无法使用对函数进行评估的表上的索引来加快查询速度。 对于一次性查询,可能没有关系; 对于生产查询,这通常很重要。

有机会完成您想要的工作。 由于要聚合两个表,因此需要FROM子句中的两个子查询。

SELECT u.UserID,
       u.username,
       u.realm,
       u.cap_size AS cap,
       h.AdHoc,
       a.OctetsUsed
  FROM msi_adsl AS u
  JOIN (SELECT UserID, SUM(AcctInputOctets + AcctOutputOctets) AS OctetsUsed
          FROM radact
         WHERE AcctStartTime BETWEEN '2010-11-01' AND '2010-11-31'
         GROUP BY UserID
       )    AS a ON a.UserID = u.UserID
  JOIN (SELECT UserID, SUM(Value) AS AdHoc
          FROM adsl_adhoc
         WHERE time BETWEEN '2010-11-01 00:00:00' AND '2010-11-31 00:00:00'
         GROUP BY UserId
       )    AS h ON h.UserID = u.UserID
 WHERE u.canceled = '0000-00-00'
 LIMIT 10

每个子查询都会计算指定时间段内每个用户的汇总值,并生成UserID和汇总值作为输出列; 然后,主查询仅从主用户表中提取正确的用户数据,并与聚合子查询联接。

我认为问题出在这里

FROM  `msi_adsl`
INNER JOIN
        (`radacct`, `adsl_adhoc`)
ON
        (CONCAT(`msi_adsl`.`username`,'@',`msi_adsl`.`realm`)
           = `radacct`.`UserName` AND `msi_adsl`.`id`=`adsl_adhoc`.`id`)

您正在将联接与笛卡尔积相混合,但这不是一个好主意,因为它很难调试。 尝试这个:

FROM  `msi_adsl`
INNER JOIN
        `radacct`
ON
      CONCAT(`msi_adsl`.`username`,'@',`msi_adsl`.`realm`) = `radacct`.`UserName`
JOIN  `adsl_adhoc` ON  `msi_adsl`.`id`=`adsl_adhoc`.`id`

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM