Использование MySQLdb для добавления строк и строк на сервер MySql - PullRequest
1 голос
/ 29 июля 2011

Я использую 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'

и я понимаю, почему это происходит, но я не могу найти альтернативный способ генерации строки. Есть ли лучший способ производства этих строк?

Я использую Python27 на 64-битной Win7.

Ответы [ 4 ]

5 голосов
/ 29 июля 2011

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, что это кортеж.

1 голос
/ 29 июля 2011

Другие посты правильно определили ошибку, но не ответили на ваш вопрос о том, как лучше форматировать строки.

Я не уверен, что это форматирует вещи именно так, как вы хотите, так как ваш код немного сложен для чтения.В итоге вы получите такие запросы:

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.join и str.format.

Действительно, вы должны использовать параметризованный запрос, который помещает значения в строку либо в соединитель базы данных, либо в саму базу данных.

1 голос
/ 29 июля 2011

Вы пробовали просто обернуть values[i][j] в str() как str(values[i][j])?

Похоже, вы могли бы также сделать

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) +","
0 голосов
/ 29 июля 2011

Ошибка вообще не связана с MySQLdb.

Вы используете оператор «+» для слияния строки с целым числом. Ваш массив values содержит смешанные строки и целые числа, и вы добавляете их с помощью оператора добавления строки, который не может работать со смешанными строками str и int (вы делаете что-то вроде mystry = 1+',').

Решением вашей проблемы может быть просто использование str () для элементов из массива. Как:

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

...