用于select count(*)= 0的Python MySQLdb测试

时间:2014-09-24 18:59:25

标签: python mysql-python

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

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

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

我还有很多其他方法可以实现这一目标。有类似以下内容吗?

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

3 个答案:

答案 0 :(得分:2)

fetchone返回一行,这是一系列列。

如果您想获得序列中的第一个值,请使用[0]

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

所以:

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

或者,将它们放在一行:

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

答案 1 :(得分:0)

谢谢。你的第一个序列有效,不知道我怎么没试过那个,但我没有。第二种结构出错:...对象没有属性“ getitem ”。我猜我的MySQLdb版本(1.2.3_4,Python 2.7)不支持它。

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

答案 2 :(得分:0)

使用游标对象的.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'