【问题标题】:python : mysql : Return 0 when no rows foundpython:mysql:找不到行时返回0
【发布时间】:2010-01-22 17:28:44
【问题描述】:

表结构 - 数据存在 5 分钟。插槽 -

数据点 |点日期

12 | 00:00

14 | 00:05

23 | 00:10

10 | 00:15

43 | 00:25

10 | 00:40

当我运行查询 30 分钟时。如果存在数据,我将得到 6 行(每 5 分钟邮票一行)。简单查询 -

select data_point
from some_table
where point_date >= start_date
AND point_date < end_date
order by point_date

现在,当我没有特定时间段的条目时(例如,缺少时间段 00:20),我希望将“data_point”返回为 0

REPLACEIFIFNULLISNULL 在没有返回行时不起作用。

我认为使用默认值的 Union 会起作用,但它也失败了,或者我没有正确使用它。

有没有办法只通过 sql 完成这项工作?

注意: Python 2.6 & mysql 5.1 版

【问题讨论】:

    标签: python mysql null


    【解决方案1】:

    是的,您只能使用 SQL 来执行此操作。一个解决方案是使用存储例程。下面的存储过程产生以下输出:

    start   cnt
    00:05:00   1
    00:10:00   0
    00:15:00   1
    00:20:00   0
    00:25:00   1
    00:30:00   0
    00:35:00   1
    00:40:00   0
    00:45:00   0
    00:50:00   0
    00:55:00   2
    

    我使用的表格

    CREATE TABLE `timedata` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `c1` datetime DEFAULT NULL,
      `c2` varchar(20) DEFAULT NULL,
      PRIMARY KEY (`id`)
    )
    

    这里是存储过程(根据您的环境进行调整):

    DROP PROCEDURE IF EXISTS per5min;
    DELIMITER //
    CREATE PROCEDURE per5min ()
    BEGIN
      DECLARE dtMin DATETIME;
      DECLARE dtMax DATETIME;
      DECLARE dtStart DATETIME;
      DECLARE dtStop DATETIME;
      DECLARE tmDiff TIME;
      DECLARE result INT UNSIGNED;
      SET @offset = 5 * 60;
      SELECT MIN(c1) into dtMin FROM timedata;
      SELECT MAX(c1) into dtMax FROM timedata;
    
      CREATE TEMPORARY TABLE tmp_per5min (
          start TIME,
          cnt INT UNSIGNED
      );
    
      SET dtStart = dtMin;
      REPEAT
        SELECT dtStart + INTERVAL @offset SECOND into dtStop;
        SELECT count(c2) into result FROM timedata WHERE c1 BETWEEN dtStart and dtStop;
        SELECT TIME(SUBTIME(dtStop,TIME(dtMin))) into tmDiff;
        INSERT INTO tmp_per5min (start,cnt) VALUES (tmDiff,result);
        SET dtStart = dtStop;
      UNTIL dtStop >= dtMax END REPEAT;
    
      SELECT * FROM tmp_per5min;
      DROP TABLE tmp_per5min;
    END;
    //
    DELIMITER ;
    
    CALL per5min();
    

    如果将上述内容保存到名为“per5minproc.sql”的文件中,则可以这样加载:

    shell> mysql -uroot test < per5minproc.sql
    

    在 Python 中使用 MySQLdb(我没有在 MySQL Connector/Python 中得到这个工作,我很惭愧!):

    import MySQLdb as m
    
    if __name__ == '__main__':
        db = m.connect(user='root',db='test')
        c = db.cursor()
        c.callproc("per5min")
        print(c.fetchall())
        c.close()
        db.close()
    

    上述解决方案有效,但可能需要一些调整,例如dtStart 可以是 SP 的参数。 而且,确实都是 SQL!

    【讨论】:

    • 上面的存储过程做的很快,所以可能会有一些错误..但它可能会让你继续前进!
    【解决方案2】:

    你不能查询你没有的数据。

    您(作为一个有思想的人)可以声称缺少 00:20 的数据;但是在更正式的 SQL 意义上没有简单的方法来定义“缺失”。

    您能做的最好的事情就是创建一个包含所有预期时间的表。

    然后您可以在预期时间(包括 0 表示 00:20)和实际时间(缺少 00:20 示例)之间进行外部连接,您将获得您期望的结果。

    【讨论】:

      【解决方案3】:

      我认为没有简单的方法可以凭空创建不存在的记录,但是您可以自己创建一个 point_dates 表,其中包含您感兴趣的所有时间戳,并将其加入您的数据:

      select pd.slot, IFNULL(data_point, 0) from point_dates pd left join some_table st on st.point_date=pd.slot where point_date >= start_date AND point_date < end_date order by point_date

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多