【问题标题】:MySQL query seems to be ignoring part of WHERE statement within stored functionMySQL 查询似乎忽略了存储函数中的 WHERE 语句的一部分
【发布时间】:2013-01-24 15:45:27
【问题描述】:

我对 MySQL 中的存储函数有一个非常令人沮丧的问题。 我有一个数据库,其中包含来自连接到无线热点的用户的会话数据。我正在尝试从选定月份内选择单个用户下载统计信息。我的问题是函数中的子查询似乎忽略了 WHERE 语句中的 mac 字段。这是我的代码:

CREATE FUNCTION get_month_download(mo varchar(45), box int(11), mac varchar(45))   RETURNS DOUBLE
BEGIN
    DECLARE dwnld double;
    IF mo IS NULL THEN
        SET mo := CONCAT(CONCAT(YEAR(NOW()), '-', MONTH(NOW())),'-','01');
    END IF;
    SET dwnld := (
        SELECT SUM(`tx_bytes`) 
        FROM `session` 
        WHERE `assoc_time` > UNIX_TIMESTAMP(mo) 
        AND `disassoc_time` < UNIX_TIMESTAMP(DATE_ADD(mo, INTERVAL 1 MONTH))
        AND `mac` = mac
        AND `controller_id` = box
    );
    return dwnld;
END

运行这个:

SELECT get_month_download('2012-09-01', '2', '00:21:5c:56:be:a3');

返回整个表的下载数据,尽管它使用controller_id 过滤数据。

如果我使用相同的参数在函数外部运行子查询,它可以正常工作。什么给了?

为了更清楚,运行这个查询:

SELECT SUM(`tx_bytes`) 
FROM `session` 
WHERE `assoc_time` > UNIX_TIMESTAMP('2012-09-01') 
AND `disassoc_time` < UNIX_TIMESTAMP(DATE_ADD('2012-09-01', INTERVAL 1 MONTH))
AND `mac` = '00:21:5c:56:be:a3'
AND `controller_id` = '2';

返回该用户的正确下载统计信息。该函数返回该控制器的所有用户的统计信息。

【问题讨论】:

  • AND controller_id = box); 中方框后面的多余括号是什么?
  • @Ray:它匹配SET dwnld := (SELECT SUM(tx_bytes) 中的左括号。 dwnld 的值被设置为子查询的结果。一开始我也很困惑:)
  • 为了清楚起见,我已经编辑了这个问题。
  • 您能否提供一个示例表架构和数据使用SQLFiddle
  • 在 SQLFiddle 中:sqlfiddle.com/#!2/2f703/1。我确实删除了一个约束,但这没关系。

标签: mysql function field where


【解决方案1】:

您确定有多个controller_id 在场吗?

SELECT DISTINCT controller_id FROM session

此查询获取了多少条记录?

如果这仅获取一条记录,并且对应于 box = 2,则没有问题。

如果有多个控制器 ID,则运行此查询,

SELECT COUNT(1), controller_id 
FROM session 
WHERE assoc_time > '2012-01-01' 
AND disassoc_time < '2012-01-31'
AND mac = '00:21:5c:56:be:a3'
GROUP BY controller_id

这会返回多少行?如果它只返回一个 controller_id 2 的记录,则没有任何问题。

【讨论】:

  • 有 4 个controller_ids。我已经确认它正确选择了 controller_id 为 2 的行。
  • 添加了第二个查询以检查是否有任何内容被其他子句过滤掉
  • 我需要在两个日期中添加UNIX_TIMESTAMP() 以便它返回任何内容,因为时间存储在int 字段中而不是日期时间中——数据从不同的数据库传输过来。它确实返回了一个计数为 268 的记录。
  • 我同意应该没有问题。但是,当将此查询放入函数并使用 IN 参数作为 WHERE 语句中的值时,它无法使用 mac 字段进行过滤。
【解决方案2】:

我真的应该更经常地反思我的老师在大学里教给我的东西。问题是变量 mac 在 select 语句的范围内被视为表中的字段,而不是函数中的参数。因此,更改参数名称解​​决了问题:

CREATE FUNCTION get_month_download(mo varchar(45), box int(11), inmac varchar(60)) RETURNS DOUBLE 
BEGIN  
    DECLARE dwnld double;
    IF mo IS NULL THEN
        SET mo := CONCAT(CONCAT(YEAR(NOW()), '-', MONTH(NOW())),'-','01');
    END IF;
    SET dwnld := (
        SELECT SUM(`tx_bytes`)   
        FROM `session`    
        WHERE `assoc_time` > UNIX_TIMESTAMP(mo)    
        AND `disassoc_time` < UNIX_TIMESTAMP(DATE_ADD(mo, INTERVAL 1 MONTH))      
        AND `controller_id` = box
        AND `mac` = inmac
    );
     return dwnld; 
END

这是一个“打脸”的时刻。谢谢大家的帮助。

【讨论】:

  • :) 很高兴我从您的查询而不是从我的经验中了解到这一点!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-30
  • 1970-01-01
  • 2013-09-15
  • 2012-12-29
  • 2019-07-11
  • 2018-11-19
相关资源
最近更新 更多