【问题标题】:Using MySQLdb to add ints and strings to a MySql server使用 MySQLdb 将整数和字符串添加到 MySql 服务器
【发布时间】:2011-07-28 21:05:46
【问题描述】:

我正在使用MySQLdb 将大量数据从文本文件上传到 MySQL 服务器。如果我手动准备一个字符串(例如'as', '123', 12, 23),这可以正常工作,但是我不知道如何循环遍历一个列表来生成它,因为我需要连接字符串和整数。

一个有效的插入语句示例如下:

""" INSERT INTO ACS(ST, CODE, BC001, BC002, BC003) 
VALUES ('AK', '1234567', 20, 30, 40)""" 

这就是我尝试从列表中生成此语句的方式:

import MySQLdb

# sample data
table = 'TestTable'
header = ['ST', 'CODE', 'BC001', 'BC002', 'BC003']
values = [['AA', '1234567', 20, 30, 40], ['BB', '1234567', 20, 30, 40], ['CC', '1234567', 20, 30, 40],['DD', '1234567', 20, 30, 40]]


# local SQL server on my computer
db = MySQLdb.connect (host = 'localhost', user = 'root', passwd = '', db = 'test')
# prepare a cursor object using cursor() method
cursor = db.cursor()

# header columns
sql1 = '('
for i in range(len(header)):
    sql1 += header[i] + ','
sql1 = 'INSERT INTO ' + table + sql1[:-1] + ')'

# now loop through data values and combine with header each time
for i in range(len(values)):

    sql2 = ''
    for j in range(len(values[i])):
        sql2 += values[i][j] + ','        #error occurs here

    # structure: sql2 = """ VALUES ('AA', '1234567', 20, 30, 40)"""
    sql2 = 'VALUES ' + table + sql2[:-1] + ')'     
    sql = sql1 + sql2

    try:
       # Execute the SQL command
       cursor.execute(sql)
       # Commit your changes in the database
       db.commit()
    except:
       # Rollback in case there is any error
       db.rollback()

# disconnect from server
db.close()

我得到的错误信息是

TypeError: unsupported operand type(s) for +: 'int' and 'str'

我明白为什么会这样,但我想不出另一种生成字符串的方法。有没有更好的方法来生成这些字符串?

我在 Win7 64 位上使用 Python27。

【问题讨论】:

  • 对不起,我在google上查了一下,没有pymsql这样的东西?可以给个主页链接吗?
  • 糟糕,我写错了包名。这是 MySQLdb - 我会更新问题;对此感到抱歉。

标签: python mysql sql database string-formatting


【解决方案1】:

MySQLdb 已经可以做到这一点,而无需您手动对变量进行类型转换。

你想这样做,因为 MySQLdb 会在某种程度上自动引用并保护你免受 SQL 注入攻击。这在任何实际环境中都非常重要,如果您打算从事任何专业的数据库工作,您应该习惯这一点。

使用 MySQLdb 游标对象,execute() 命令将自动正确格式化您的整数、字符串和其他变量,以便它们在您的INSERT 语句中工作。他们使用一种特殊的格式字符串来做到这一点。

c=db.cursor()
max_price = 5
min_price = 1
c.execute("""SELECT spam, eggs, sausage FROM breakfast
          WHERE price < %s AND price > %s""", (max_price, min_price))

注意两点:首先,所有变量,无论类型如何,都应该在这些特殊格式的字符串中表示为%s。这就是它的工作方式。其次,execute() 的第二个参数应该是一个元组,所以如果你只有一个变量要使用,你需要像(max_price,) 一样输入它。括号末尾的逗号告诉 python 它是一个元组。

【讨论】:

  • 这绝对是一个更好的方法;我刚刚在上面提到我不知道这种方法。我刚刚通过传递一个列表对其进行了测试,并注意到 MySQL 使用引号 'AA' 显示字符串,而其他方法没有这样做(它们只显示为 AA)。我可以阻止这种情况发生吗?
  • 我们在这里讨论的是什么 MySQL 数据类型?我的印象是所有字符串都必须用引号括起来。
  • 如果您想要不带引号的字符串,请使用 python 老式格式字符串。尝试在解释器中输入以下内容:"W%s H%d%d" % ('AA', 0, 0)
  • 但我很确定任何 CHAR 或 VARCHAR 都应该始终有单引号。
  • 查看此文档了解更多详情:docs.python.org/library/…
【解决方案2】:

其他帖子正确识别了错误,但没有回答您关于更好地进行字符串格式化的问题。

我不确定这是否完全符合您的要求,因为您的代码有点难以阅读。您最终会遇到如下查询:

INSERT INTO TestTable (ST,CODE,BC001,BC002,BC003) VALUES ('AA','1234567',20,30,40)

代码如下:

sql = (('INSERT INTO {0} ({1}) VALUES ({2})'.format(table, ','.join(header), 
                         ','.join(("'" + v + "'" if isinstance(v, str) 
                             else str(v)) for v in val))) for val in values)

然后你就这样做:

for q in sql:
    try:
        # Execute the SQL command
        cursor.execute(q)
        # Commit your changes in the database
        db.commit()
    except:
        # Rollback in case there is any error
        db.rollback()

它为字符串添加引号,并使用str.joinstr.format

确实,您应该使用参数化查询,它将值放入字符串中,发送到数据库连接器或数据库本身。

【讨论】:

  • 你可能想在isinstance调用中使用basestring而不是str,只是为了增加通用性。也可以链接到 python 文档docs.python.org/library/stdtypes.html#str.format
  • 啊!我不知道更好。我刚刚阅读了如何进行参数化查询,也许我应该这样做。这是在个人计算机上一次性上传的海量数据,因此安全性不是问题。
【解决方案3】:

您是否尝试过像str(values[i][j]) 一样将values[i][j] 简单地包装在str() 中?

看来你也可以这样做

sql2 = ','.join([str(x) for x in values[i]]) + ','

如果您想进一步简化它。 (不确定是否需要尾随逗号,但我包含它以匹配您的代码。)

例子:

>>> my_list = ['abc', 1, 2,3, 'do','re','mi']
>>> [str(x) for x in my_list]
['abc', '1', '2', '3', 'do', 're', 'mi']
>>> ','.join([str(x) for x in my_list])
'abc,1,2,3,do,re,mi'

另一方面,如果您需要在最终查询中将原本是字符串的对象用单引号括起来,就像您所做的那样,您可能需要做一些更复杂的事情,例如

sql2 = ''
for x in values[i]:
    if isinstance(x, basestring):
        sql2 += "'"+x+"',"
    else:
        sql2 += str(x) +","

【讨论】:

  • 感谢您的建议。我需要能够三重引用""",并且还需要用' 包围字符串类型的变量,否则数据库不会更新。
  • 对不起,我刚刚注意到第二部分并相应地编辑了我的回复。不过,我不确定您所说的需要三重引号是什么意思。
【解决方案4】:

该错误与 MySQLdb 完全无关。

您正在使用“+”运算符将字符串与整数合并。您的 values 数组包含混合的字符串和整数,并且您使用字符串追加运算符添加它们,这不能与混合的 str 和 int 一起使用(您正在执行类似 mystry = 1+',' 的操作)。

您的问题的解决方案可以是对数组中的项目使用 str()。喜欢:

sql2 += str(values[i][j]) + ','

【讨论】:

  • 但是他只是在做手动的一块一块的格式字符串。该错误可能与 MySQLdb 无关,但如果您查看问题的内容,您会意识到他正在尝试将值列表插入一行,而这正是由他使用的函数提供的。
猜你喜欢
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多