2016-01-13 1 views
4

Мне нужно построить запрос динамического обновления для postgresql. Его динамика, потому что заранее я должен определить, какие столбцы нужно обновить.Создайте запрос динамического обновления в psycopg2

Учитывая пример таблицы:

create table foo (id int, a int, b int, c int) 

Тогда я построю программно «набор» пункт

_set = {} 
_set['a'] = 10 
_set['c'] = NULL 

После того, что я должен построить запрос на обновление. И здесь я застрял. я должен построить эту команду SQL Update:

update foo set a = 10, b = NULL where id = 1 

Как сделать это с psycopg2 параметризованным команду? (т. е. зацикливание через dict, если оно не пустое и построить предложение set)?

UPDATE

Пока я спал, я нашел решение самостоятельно. Он динамичен, как именно я хотел быть :-)

create table foo (id integer, a integer, b integer, c varchar) 

updates = {} 
updates['a'] = 10 
updates['b'] = None 
updates['c'] = 'blah blah blah' 
sql = "upgrade foo set %s where id = %s" % (', '.join("%s = %%s" % u for u in updates.keys()), 10) 
params = updates.values() 
print cur.mogrify(sql, params) 
cur.execute(sql, params) 

И результат, что и как мне нужно (особенно обнуляемая и цитируемая колонна):

"upgrade foo set a = 10, c = 'blah blah blah', b = NULL where id = 10" 

ответ

1

Нет необходимость динамического SQL , Предположим, что a не может быть NULL, и b является допустимым.

Если вы хотите обновить как a и b:

_set = dict(
    id = 1, 
    a = 10, 
    b = 20, b_update = 1 
) 
update = """ 
    update foo 
    set 
     a = coalesce(%(a)s, a), -- a is not nullable 
     b = (array[b, %(b)s])[%(b_update)s + 1] -- b is nullable 
    where id = %(id)s 
""" 
print cur.mogrify(update, _set) 
cur.execute(update, _set) 

Выход:

update foo 
set 
    a = coalesce(10, a), -- a is not nullable 
    b = (array[b, 20])[1 + 1] -- b is nullable 
where id = 1 

Если вы хотите обновить никто:

_set = dict(
    id = 1, 
    a = None, 
    b = 20, b_update = 0 
) 

Выход:

update foo 
set 
    a = coalesce(NULL, a), -- a is not nullable 
    b = (array[b, 20])[0 + 1] -- b is nullable 
where id = 1 
+0

К сожалению, я должен использовать динамический запрос, как моя реальная таблица имеет 30+ столбцов, и я только хочу, чтобы обновить те столбцы, которые имеют (если есть). И, конечно же, я должен позаботиться о столбцах варчара, которые должны быть указаны. Но я не могу автоматически указывать все значения, потому что, например, значение для столбца с нулевым значением станет «Нет» или «NULL» – Gabor

+0

@Gabor: Я думаю, вы не понимаете, как это работает. Я отвечу позже или завтра. –

+0

OK. Я ищу решение. Но я не хочу иметь полное количество столбцов внутри _set dict или внутри строки обновления. И, конечно же, я должен позаботиться о цитируемых столбцах, например, если бы это была нулевая колонка varchar. – Gabor

3

Существует на самом деле немного чист способ сделать это, используя the alternative column-list syntax:

sql_template = "UPDATE foo SET ({}) = %s WHERE id = {}" 
sql = sql_template.format(', '.join(updates.keys()), 10) 
params = (tuple(addr_dict.values()),) 
print cur.mogrify(sql, params) 
cur.execute(sql, params) 
+1

это хорошо, но я также рекомендую использовать '% s' для значения id, чтобы вы могли предотвратить SQL-инъекцию с помощью psycopg2 - на всякий случай это значение исходит от неизвестного клиента. – phouse512

+0

True story phouse! – Rmatt

Смежные вопросы