【问题标题】:How to check if record exists with Python MySQdb如何使用 Python MySQdb 检查记录是否存在
【发布时间】:2012-11-02 15:43:27
【问题描述】:

我正在创建一个连接到 mysql 的 python 程序。

我需要检查一个表是否包含数字 1 以表明它已成功连接,这是我目前的代码:

xcnx.execute('CREATE TABLE settings(status INT(1) NOT NULL)')
  xcnx.execute('INSERT INTO settings(status) VALUES(1)')
  cnx.commit()
  sqlq = "SELECT * FROM settings WHERE status = '1'"
  xcnx.execute(sqlq)
  results = xcnx.fetchall()
  if results =='1':
    print 'yep its connected'
  else:
    print 'nope not connected'

我错过了什么?我是一个 sql 菜鸟,谢谢大家。

【问题讨论】:

  • 您只是想检查您是否可以连接到数据库,或者您是否可以成功创建表并插入数据?
  • 不,我知道我可以连接创建和插入,我只需要知道如何检查和验证记录是否存在。

标签: python mysql mysql-python


【解决方案1】:

我相信最有效的“是否存在”查询就是执行count

sqlq = "SELECT COUNT(1) FROM settings WHERE status = '1'"
xcnx.execute(sqlq)
if xcnx.fetchone()[0]:
    # exists

不是要求数据库对字段或行执行任何计数操作,而是要求它在结果产生任何匹配时返回 1 或 0。这比返回实际记录并计算客户端的数量效率更高,因为它节省了双方的序列化和反序列化以及数据传输。

In [22]: c.execute("select count(1) from settings where status = 1")
Out[22]: 1L  # rows

In [23]: c.fetchone()[0]
Out[23]: 1L  # count found a match

In [24]: c.execute("select count(1) from settings where status = 2")
Out[24]: 1L  # rows

In [25]: c.fetchone()[0]
Out[25]: 0L  # count did not find a match

count(*) 将与count(1) 相同。在您的情况下,因为您正在创建一个新表,它将显示 1 个结果。如果您有 10,000 个匹配项,它将是 10000 个。但是您在测试中关心的是它是否不为 0,因此您可以执行布尔真值测试。

更新

实际上,只使用rowcount甚至不获取结果会更快:

In [15]: if c.execute("select (1) from settings where status = 1 limit 1"): 
            print True
True

In [16]: if c.execute("select (1) from settings where status = 10 limit 1"): 
            print True

In [17]: 

这也是 django 的 ORM 执行queryObject.exists() 的方式。

【讨论】:

  • 我绝对同意你的方法,并且会在任何其他情况下使用它,但我相信COUNT(*) 是一个奇怪的情况,即使在不匹配的情况下也会返回一行(行只包含数字 0)。
  • @RocketDonkey:我刚刚更正了我的示例以使用尽可能最少的处理来检查查询是否存在。做count(1) 更小。您将检查第一个结果是否有单个 int。
  • @RocketDonkey:谢谢。它与您的答案相似,但我只关注count 以及它是否返回非零。
  • 是的,这样看起来更聪明/更高效(而且它摆脱了丑陋的[0][0]。逻辑再次盛行:)
  • 我知道 django 使用行数来做到这一点。只需要查找并确认。通过询问结果绝对可以节省任何进一步的沟通。
【解决方案2】:

如果您只想检查是否已成功建立连接,那么您为什么要尝试创建表、插入一行,然后从中检索数据?

您可以简单地执行以下操作...

sqlq = "SELECT * FROM settings WHERE status = '1'"
xcnx.execute(sqlq)
results = xcnx.fetchone()
if results =='1':
  print 'yep its connected'
else:
  print 'nope not connected'

其实如果你的程序到目前为止没有抛出异常就说明你已经建立连接成功了。 (请检查上面的代码,我不确定 fetchone 在这种情况下是否会返回元组、字符串或 int)。

顺便说一句,如果由于某种原因确实需要创建表,我建议在退出之前将其删除,以便您的程序第二次成功运行。

【讨论】:

    【解决方案3】:

    当您运行results = xcnx.fetchall() 时,返回值是包含行值的元组序列。因此,当您检查是否为results == '1' 时,您正在尝试将一个序列与一个常量进行比较,该常量将返回False。在您的情况下,将返回单行值 0,因此您可以尝试以下操作:

    results = xcnx.fetchall()
    # Get the value of the returned row, which will be 0 with a non-match
    if results[0][0]:
      print 'yep its connected'
    else:
      print 'nope not connected'
    

    您也可以使用DictCursor(创建光标时,使用.cursor(MySQLdb.cursors.DictCursor),这会使代码更容易解​​释,但结果是一样的:

    if results[0]['COUNT(*)]':
        # Continues...
    

    此外,在这种情况下没什么大不了的,但是您正在将整数值与字符串进行比较。 MySQL 将进行类型转换,但您可以使用 SELECT COUNT(*) FROM settings WHERE status = 1 并节省(非常小的)一点处理。

    【讨论】:

      【解决方案4】:

      我最近提高了效率,而不是查询 select,只是将主索引添加到唯一列,然后添加它。 MySQL 只会在它不存在时添加它。

      所以不是 2 个语句:

       Query MySQL for exists:
           Query MySQL insert data
      

      只要做 1,它只有在它是唯一的时候才会起作用:

      Query MySQL insert data
      

      1 查询优于 2。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-01
        • 2019-04-07
        • 1970-01-01
        • 1970-01-01
        • 2021-02-21
        相关资源
        最近更新 更多