SQL Dinámico y parámetros (Era: problema de novato)

Juan Ignacio Rodríguez de León jileon en parcan.es
Lun Mar 21 21:35:37 CET 2005


Marcos Sánchez Provencio wrote:

 > El modo correcto de usar sql desde programas
 > (con cualquier lenguaje,no sólo Python) implica
 > no meter valores dentro del sql; en lugar de cada
 > valor se mete una marca de parámetro

> Hay varios tipos de marcador de parámetro:
> 1) Por secuencia: El marcador suele ser %s o ?
> 2) Por nombre: El marcador suele ser %(nombre)s o :nombre
> 3) Por orden: El marcador suele ser :1, :2...

Gracias por la respuesta. he pasado este tiempo
haciendo algunas pruebas y aquí resumo lo
aprendido, por si fuera de utilidad a alguien:

En el ODBC pedestre que viene con las extensiones
para windows[1] de Mark Hammond si que se puede
usar sql dinámico, pasando los parámetros con
la tercera sintaxis que explicó Marcos (por
orden). Véase un ejemplo:

 >>> import dbi, odbc
 >>> db = odbc.odbc('PERFUMERIA2')
 >>> cur = db.cursor()
 >>> cur.execute('''
SELECT id_proveedor, nombre
   FROM Proveedor
  WHERE id_Proveedor = :1''', [23])
 >>> print cur.fetchone()
(23, 'CARRASCO PONS S.L.')
 >>> cur.execute('''
SELECT id_proveedor, nombre
   FROM Proveedor
  WHERE id_Proveedor between :1 and :2''', [15, 18])
 >>> for row in cur.fetchall(): print '%d %s' % row
15 Dyal
16 J. Bogart
17 Carrasco
18 IDESA
 >>>

 > Casi seguro que daría mejor resultado usar adodbapi o mxOdbc, pero

Probé también con las dos extensiones que me
sugería Marcos. Las dos ofrecen más funcionalidad, pero
el tema de la licencia no libre de mxOdbc[2] me condujo
a adodbapi[3], que además es DB-API 2.0 100%[4].

En adodbapi, además de tener muchas más funcionalidad
que el ``difunto'' ODBC de las extensiones para
windows (Transacciones, por ejemplo, que me vienen
muy bien), permite el paso de parámetros mediante
secuencia, usando como marcador el signo de cierre
de interrogación (?).

Mejor con un ejemplo:

 >>> import adodbapi
 >>> db = adodbapi.connect('PERFUMERIA2')
 >>> cur = db.cursor()
 >>> cur.execute('''
SELECT id_proveedor, nombre
   FROM Proveedor
  WHERE id_Proveedor = ?''', [23])
 >>> print cur.fetchone()
(23, u'CARRASCO PONS S.L.')
 >>>

Por cierto, los módulos DB-API, para cumplir la
especificación 2.0, deben definir una variable
paramstyle que indica precisamente como se realiza
la inserción de parámetros en sql dinámico.

Los valore posibles de paramstyle son:

     'qmark'         Símbolo de cierre de interrogación,
                     por ejemplo: '...WHERE name=?'
     'numeric'       Numérico, por posición
                     por ejemplo: '...WHERE name=:1'
     'named'         por nombre,
                     por ejemplo: '...WHERE name=:name'
     'format'        códigos de formato del printf de C
                     por ejemplo: '...WHERE name=%s'
     'pyformat'      a lo Python
                     por ejemplo: '...WHERE name=%(name)s'

Por si alguien quiere probar los scripts de ejemplo
incluidos, aquí está la definición de la tabla usada:

CREATE TABLE PROVEEDOR (
       Id_proveedor INTEGER NOT NULL PRIMARY KEY
      , Nombre VARCHAR(220) NOT NULL UNIQUE
);

Sintaxis de Firebird[5]

Perdón por el rollete para los que no estén interesados y
un saludo a toda la lista :-)

Referencias
------------

[1] Mark Hammond's Python extensions for windows
     http://starship.python.net/crew/mhammond/win32/

[2] mxODBC - The Python ODBC Interface
     http://www.egenix.com/files/python/mxODBC.html

[3] ADODBAPI
     http://adodbapi.sourceforge.net/

[4] Python Database API Specification v2.0
     http://www.python.org/peps/pep-0249.html

[5] Firebird - Relational Database for the New Millenium
     http://firebird.sourceforge.net/




Más información sobre la lista de distribución Python-es