MySQLDB查询不返回所有行

时间:2012-12-19 22:45:42

标签: python mysql python-2.7

我正在尝试使用Python中的MySQLDB进行简单的提取。

我有2张桌子(帐户和产品)。我必须查看Accounts表,从中获取acc_id&使用它查询Products表。

Products表有10行以上。但是,当我运行此代码时,它会在0和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()

奇怪的是,我尝试使用调试器(Eclipse上的PyDev)逐步执行代码并正确获取所有行(存储在变量'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)并返回所有行

2 个答案:

答案 0 :(得分:1)

这实际上不是一个答案,只是试图将与RBK聊天的所有信息聚集在一起,排除了一堆潜在的问题,但仍未提出解释或解决方案,希望其他人可以发现问题或考虑其他事情来尝试。

这显然属于这一行:

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

特别是因为用322代替acc_id可以解决所有问题。 (如下所述。)

这条线实际上有两个问题,可能会妨碍它。您始终希望使用DB-API绑定而不是字符串格式(以及任何其他语言中的等效项),以避免SQL注入攻击,转义/转换等的正确性以及效率。此外,DB-ABI绑定和字符串格式化都需要tuple个参数,而不是单个参数。 (由于遗留原因,单个参数经常有效,但有时它不起作用,然后它只是混乱调试...最好不要这样做。)所以,这应该是:

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可能与使用{{1}}不同。然而,确实如此。

在聊天的某个时刻,我们显然已经从产品转移到了设备,从322移到了333,但无论如何,上面显示的测试肯定完全如图所示,并返回了不同的结果。

也许他有一个错误或安装严重的MySQLDb版本。他将尝试寻找更新版本或其他Python MySQL库之一,看看它是否有所作为。

我在这一点上的最佳猜测是,RBK无意中激怒了一些技术上复杂的恶作剧之神,但我甚至无法想到其中一个不在我头顶。

答案 1 :(得分: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中调用)需要几秒钟才能在Product表中添加10个条目。

当我的代码(代码块2)运行了一个获取查询时,所有10行都没有被添加,因此被提取到0到6行之间(当时添加了多少)。

我做了解决这个问题的方法是让代码在我执行SQL查询之前休眠5秒钟:

Code Block 1
time.sleep(5)
Code Block 2

当我对acc_id进行硬编码时它起作用的原因是,我硬编码的acc_id来自一个宝贵的执行(每次运行返回一个新的acc_id)。 并且它在调试器中工作的原因是手动步进就像给它一个睡眠时间。

对我来说,了解一些关于API的内部工作(即使它们应该像黑盒子)并且考虑这样的竞争条件,下次我遇到类似问题时,这是一个教训。