MySQL数据库查询未返回所有行

3
我正在尝试在Python中使用MySQLDB进行简单的获取操作。
我有两个表(Accounts和Products)。我需要查询Accounts表,获取acc_id并使用它来查询Products表。
Products表有超过10行。但是当我运行此代码时,每次运行它都会随机返回0至6行。
以下是代码片段:
# Set up connection
con = mdb.connect('db.xxxxx.com', 'user', 'password', 'mydb')

# Create cursor
cur = con.cursor()

# Execute query 
cur.execute("SELECT acc_id FROM Accounts WHERE ext_acc = '%s'" % account_num ) # account_num is alpha-numberic and is got from preceding part of the program

# A tuple is returned, so get the 0th item from it
acc_id = cur.fetchone()[0] 
print "account_id = ", acc_id

# Close the cursor - I was not sure if I can reuse it
cur.close() 

# Reopen the cursor
cur = con.cursor() 

# Second query
cur.execute("SELECT * FROM Products WHERE account_id = %d" % acc_id)

keys = cur.fetchall()
print cur.rowcount # This prints incorrect row count

for key in keys: # Does not print all rows. Tried to directly print keys instead of iterating - same result :(
    print key

# Closing the cursor & connection
cur.close()
con.close()

奇怪的是,我试图使用调试器(PyDev on Eclipse)逐步执行代码,它正确获取了所有行(变量'keys'中存储的值以及控制台输出都是正确的)。
我确定我的数据库数据是正确的,因为我在MySQL控制台上运行了相同的SQL并得到了正确的结果。
为了确保我没有错误地关闭连接,我尝试使用with con而不是手动关闭连接,但结果是一样的。
我看了一下RTM,但是里面没有太多有助于解决这个问题的信息。
我错在哪里?
谢谢。 编辑:我现在注意到另一个奇怪的事情。在这一行中cur.execute("SELECT * FROM Products WHERE account_id = %d" % acc_id),我硬编码了acc_id的值,即使它成为了cur.execute("SELECT * FROM Products WHERE account_id = %d" % 322),它返回了所有行。

fethall()是一个东西吗?fet*c*hall()呢?这有什么区别吗?另外,您说表格有超过10行......您是否考虑了您的where子句? - Colleen
糟糕!我在发布的代码中写错了fethall()!但是我在我的IDE中已经更正了它 :) 我在问题中进行了修正... 是的,我考虑了where子句。在mysql控制台上,完全相同的查询返回了10行。 - Bharat
@Droogans,我已经在我的机器上删除了代码中的游标关闭和重新打开。 - Bharat
@Droogans,是的,不起作用。我现在注意到另一件奇怪的事情。在这行代码中 cur.execute("SELECT * FROM Products WHERE account_id = %d" % acc_id),我硬编码了acc_id的值,即将其设为cur.execute("SELECT * FROM Products WHERE account_id = %d" % 322),它返回所有行。 - Bharat
1
@RBK:不,(acc_id) 不是一个元组,它只是和 acc_id 一样的东西。如果你想要一个包含一个元素的元组,你需要加上逗号,就像我上面的例子中写的那样:(acc_id,)。另外,你在这里根本不应该使用 % - abarnert
显示剩余6条评论
2个回答

1
这实际上并不是一个答案,只是试图汇总与RBK的聊天中排除了一堆潜在问题的所有信息,但仍然没有得出解释或解决方案,希望其他人能够发现问题或想到其他尝试方法。
很明显问题出在这一行:
cur.execute("SELECT * FROM Products WHERE account_id = %d" % acc_id)

特别是将acc_id替换为322后,一切问题都得到了解决。(如下所示)

实际上,该行存在两个问题,可能会妨碍操作。您始终希望使用DB-API绑定而不是字符串格式化(以及任何其他语言的等效方式),以避免SQL注入攻击,确保转义/转换等正确性和效率。此外,DB-ABI绑定和字符串格式化都需要一个元组参数,而不是单个参数。(由于历史原因,单个参数通常有效,但有时不起作用,然后调试起来就很困难...最好不要这样做。)因此,应该是:

cur.execute("SELECT * FROM Products WHERE account_id = %d", (acc_id,))

很遗憾,在聊天中讨论并尝试了很多方法后,我们仍然无法找到实际的问题所在。总结一下我们尝试过的:

然后,我们尝试了:

cur.execute("SELECT COUNT(*) FROM Devices WHERE account_id = %s" , (333,)) 
print cur.fetchone()[0]

print 'account id =', acc_id
print type(acc_id)
cur.execute("SELECT COUNT(*) FROM Devices WHERE account_id = %s" , (acc_id,)) 
print cur.fetchone()[0]

输出结果为:
10
account id = 333
<type 'long'>
2

当重复运行时,最后一个数字从0到6变化,而第一个数字始终为10。使用acc_id与使用333没有任何不同的方式,但实际上确实存在差异。即使有一次查询在某种程度上“感染”了下一个查询,没有前两行,其余部分也会以相同的方式工作。

因此,使用acc_id与使用333不可能有任何不同。但是,它确实存在差异。

在聊天过程中,我们显然从产品转移到设备,并从322转移到333,但无论如何,上面显示的测试肯定是按照所示进行的,并返回了不同的结果。

也许他安装的MySQLDb版本有缺陷或安装不良。他将尝试寻找更新版本或其他Python MySQL库,并查看是否有所不同。

我目前最好的猜测是RBK无意中激怒了某个技术精湛的恶作剧之神,但我甚至想不起来其中的一个。


感谢您的帖子。设备和产品是相同的。我在这里发布问题时使用了“产品”作为别名,因为我不想使用我们工作中数据库中使用的相同名称 :) - Bharat

1

我有点想通了问题。最后发现是个愚蠢的错误,是竞态条件!

这是我的实际代码组织方式:


 Code Block 1
 {code which calls an API which creates an entry in Accounts table &
 Creates corresponding entries in Product table(10 entries)}

......

Code Block2
{The code I had posted in my question}

问题在于API(在代码块1中调用)需要几秒钟才能将10个条目添加到产品表中。
当我的代码(代码块2)运行获取查询时,所有10行都没有被添加,因此在0到6行之间获取了一些行(无论当时添加了多少行)。
为了解决这个问题,我让代码在执行SQL查询之前休眠5秒钟:
Code Block 1
time.sleep(5)
Code Block 2

硬编码账户ID时它能够正常工作的原因是,我所硬编码的账户ID是来自上一次执行(每次运行都会返回一个新的账户ID)。 而在调试器中手动步进时它能够正常工作的原因是手动步进就像是给它一个等待时间。
这对我来说是一个教训,即使API通常被视为黑盒子,我也应该了解一些内部工作原理,并考虑像这样的竞争条件,下次遇到类似问题时就会知道如何处理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接