Como usar variáveis ​​na instrução SQL em Python?


91

Ok, então não tenho tanta experiência em Python.

Eu tenho o seguinte código Python:

cursor.execute("INSERT INTO table VALUES var1, var2, var3,")

onde var1é um inteiro var2e var3são strings.

Como posso escrever os nomes das variáveis ​​sem python incluindo-os como parte do texto da consulta?

Respostas:


103
cursor.execute("INSERT INTO table VALUES (%s, %s, %s)", (var1, var2, var3))

Observe que os parâmetros são passados ​​como uma tupla.

A API do banco de dados executa o escape e a cotação adequados de variáveis. Tenha cuidado para não usar o operador de formatação de string ( %), porque

  1. não faz nenhum escape ou citação.
  2. está sujeito a ataques de formato de string não controlado, por exemplo, injeção de SQL .

Interessante, por que funciona com os vars separadamente em vez de em um array (var1, var2, var3)?
— Andomar

De acordo com as especificações da API do banco de dados, parece que pode ser das duas maneiras: python.org/dev/peps/pep-0249
— Ayman Hourieh

9
@thekashyap Leia novamente com atenção. O que é inseguro é usar o operador de formatação de string %. Na verdade, digo isso na resposta.
— Ayman Hourieh de

meu mal .. Eu imaginei um em % vez de ,entre a string e variáveis ​​.. não posso desfazer meu voto para baixo devido a vários motivos .. Eu pessoalmente gostaria de ver palavras como inseguro / ataque etc mencionadas na descrição onde você diz don 't use %..
— Kashyap

1
@eric a resposta diz para não usar o % operador para formatar a string. Aqueles %na string estão sendo usados cursor.executediretamente pelo e, como ele sabe que está gerando SQL, pode fazer mais para protegê-lo.
— Mark Ransom

66

Diferentes implementações da Python DB-API podem usar diferentes marcadores de posição, portanto, você precisará descobrir qual está usando - pode ser (por exemplo, com MySQLdb):

cursor.execute("INSERT INTO table VALUES (%s, %s, %s)", (var1, var2, var3))

ou (por exemplo, com sqlite3 da biblioteca padrão do Python):

cursor.execute("INSERT INTO table VALUES (?, ?, ?)", (var1, var2, var3))

ou outros ainda (depois de VALUESvocê ter (:1, :2, :3), ou "estilos nomeados" (:fee, :fie, :fo)ou (%(fee)s, %(fie)s, %(fo)s)onde você passa um dict em vez de um mapa como o segundo argumento execute). Verifique a paramstyleconstante de string no módulo da API do banco de dados que você está usando e procure por paramstyle em http://www.python.org/dev/peps/pep-0249/ para ver o que são todos os estilos de passagem de parâmetro!


É possível fazer a mesma coisa, mas com o script SQL externo?
— Novitoll

46

Várias maneiras. NÃO use o mais óbvio ( %scom %) no código real, ele está aberto a ataques .

Aqui copie e cole do pydoc do sqlite3 :

# Never do this -- insecure!
symbol = 'RHAT'
c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)

# Do this instead
t = ('RHAT',)
c.execute('SELECT * FROM stocks WHERE symbol=?', t)
print c.fetchone()

# Larger example that inserts many records at a time
purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
             ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00),
             ('2006-04-06', 'SELL', 'IBM', 500, 53.00),
            ]
c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)

Mais exemplos se você precisar:

# Multiple values single statement/execution
c.execute('SELECT * FROM stocks WHERE symbol=? OR symbol=?', ('RHAT', 'MSO'))
print c.fetchall()
c.execute('SELECT * FROM stocks WHERE symbol IN (?, ?)', ('RHAT', 'MSO'))
print c.fetchall()
# This also works, though ones above are better as a habit as it's inline with syntax of executemany().. but your choice.
c.execute('SELECT * FROM stocks WHERE symbol=? OR symbol=?', 'RHAT', 'MSO')
print c.fetchall()
# Insert a single item
c.execute('INSERT INTO stocks VALUES (?,?,?,?,?)', ('2006-03-28', 'BUY', 'IBM', 1000, 45.00))

4
Algumas das implementações do DB-API na verdade usam% s para suas variáveis ​​- mais notavelmente psycopg2 para PostgreSQL. Isso não deve ser confundido (embora seja facilmente) com o uso de% s com o operador% para substituição de string. Eu seria muito bom se, para portabilidade, pudéssemos ter apenas uma forma padrão definida de especificar os parâmetros SQL para DB-API.
— ThatAintWorking

23

http://www.amk.ca/python/writing/DB-API.html

Tenha cuidado ao simplesmente anexar valores de variáveis ​​às suas instruções: Imagine um usuário nomeando a si mesmo ';DROP TABLE Users;'- É por isso que você precisa usar o escape sql, que o Python fornece quando você usa o cursor.execute de maneira decente. O exemplo no url é:

cursor.execute("insert into Attendees values (?, ?, ?)", (name,
seminar, paid) )

13
Na verdade, não é um escape de SQL. É ligação variável, que é muito mais simples e direta. Os valores são vinculados à instrução SQL após a análise, tornando-a imune a qualquer ataque de injeção.
— S.Lott

bem, se é escape de SQL ou ligação de variável depende de quão bom ou ruim é seu servidor de banco de dados / driver de API de banco de dados. Eu vi alguns bancos de dados de produção do mundo real amplamente implantados que têm seu driver DB-API apenas escapando, em vez de manter os dados e o código fora da banda na transmissão. Nem preciso dizer que não tenho muito respeito por esses chamados "bancos de dados".
— Charles Duffy
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.