【问题标题】:Python MySQLdb test for select count(*) = zero选择 count(*) = 零的 Python MySQLdb 测试
【发布时间】:2014-09-24 18:59:24
【问题描述】:

我使用SELECT COUNT(*) FROM db WHERE <expression> 来查看一组记录是否为空。所以:

>>> cnt = c.fetchone()
>>> print cnt
(0L,)

我的问题是:您如何测试这种情况?

我还有很多其他方法可以做到这一点。是否可能出现以下情况?

if cnt==(0L,): 
    # do something

【问题讨论】:

    标签: python mysql-python


    【解决方案1】:

    fetchone 返回一行,即一系列列。

    如果要获取序列中的第一个值,请使用[0]

    可以按照您的建议将该行与(0,) 进行比较。但据我所知,一般的 DB-API 和特定的 MySQLdb 库都不能保证一行的序列是什么种类;它可以是一个列表,也可以是一个自定义序列类。因此,依靠它是一个元组这一事实可能不是一个好主意。而且,既然这样做同样容易,为什么不安全又便携呢?

    所以:

    count_row = c.fetchone()
    count = count_row[0]
    if count == 0:
        do_something()
    

    或者,将它们放在一行中:

    if c.fetchone()[0] == 0:
        do_something()
    

    【讨论】:

      【解决方案2】:

      谢谢。你的第一个序列有效,不知道我怎么没有尝试过,但我没有。第二个构造得到一个错误:...object has no attribute 'getitem'。我猜我的 MySQLdb 版本(1.2.3_4,Python 2.7)不支持它。

      我在此期间所做的是通过执行构造为返回零记录的 count(*) 来构造零元组。这似乎工作正常

      【讨论】:

        【解决方案3】:

        使用游标对象的.rowcount 属性来检查结果集中是否有任何行通常更容易。这个属性是specified in the Python Database API

        这个只读属性指定了最后的行数 .execute*() 产生(对于像 SELECT 这样的 DQL 语句)或 受影响(对于像 UPDATEINSERT 这样的 DML 语句)。 [9]

        如果没有执行.execute*(),则该属性为-1 上一次操作的游标或行数不能 由接口决定。 [7]

        .rowcount无法使用时

        请注意,根据上述规范,当最后一条语句“无法由接口确定”产生或影响的行数时,应将Cursor.rowcount 设置为-1。使用 SSCursorSSDictCursor 游标类时会发生这种情况。

        原因是 MySQL C API 有两个不同的函数用于检索结果集:mysql_store_result()mysql_use_result()。不同之处在于mysql_use_result() 在您请求时从结果集中读取行,而不是在执行查询后立即存储整个结果集。对于非常大的结果集,这种“无缓冲”方法可以更快,并且在客户端机器上使用更少的内存;但是,在执行查询时,接口无法确定结果集包含多少行。

        SSCursorSSDictCursor 都调用mysql_use_result(),因此无论结果集的大小如何,它们的.rowcount 属性都应保持值-1。相比之下,DictCursor 和默认的Cursor 类调用mysql_store_result(),在执行查询后立即读取并统计整个结果集。

        更糟糕的是,.rowcount 属性仅在第一次打开光标时才保存值-1;一旦你执行一个查询,它就会收到mysql_affected_rows()的返回值。问题是mysql_affected_rows() 返回一个无符号长整型,它以can be very counterintuitive 的方式表示值-1,并且不会被cursor.rowcount == -1 这样的条件捕获。

        为计数而计数

        如果您正在做的唯一事情是计算记录,那么.rowcount 就没那么有用了,因为无论记录是否存在,您的COUNT(*) 查询都会返回一行。在这种情况下,测试零值的方式与从查询中获取结果时测试任何值的方式相同。是否可以c.fetchone()[0] == 0 取决于您使用的游标类;它适用于CursorSSCursor,但不适用于DictCursorSSDictCursor,它们获取字典而不是元组。

        重要的是在你的代码中清楚地知道发生了什么,这就是为什么我不建议使用c.fetchone() == (0,)。当您需要做的只是测试单个值时,它会测试整行;在测试之前将值从行中取出,您的代码会更加清晰。就个人而言,我发现c.fetchone()[0] 是不必要的不​​透明;我更喜欢:

        row = cursor.fetchone()
        if row[0] == 0:
            do_something()
        

        这清楚地表明,您正在测试行的第一项,而不是冗长。当我做的事情比简单的COUNT()EXISTS() 更复杂时,我更喜欢使用DictCursor,这样我的代码(最多)依赖于显式别名,而从不依赖于隐式列排序。

        测试空结果集

        另一方面,如果您确实需要获取结果集并且计数纯粹是偶然的,只要您不使用无缓冲游标类之一,您就可以只执行重要查询而不必担心COUNT():

        cursor.execute(r"SELECT id, name, email FROM user WHERE date_verified IS NULL;")
        if cursor.rowcount == 0:
            print 'No results'
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-01-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-11-25
          相关资源
          最近更新 更多