2010-09-12 8 views
10

Bounty update: Mark recibió una muy buena respuesta. Adaptado: = en: a continuación. Sin embargo, todavía estoy buscando esquemas similares además de DBIx. Solo estoy interesado en ser compatible con cualquier cosa.Marcadores de posición ampliados para SQL, p. Ej. DONDE id IN (??)


Necesito asesorar sobre la sintaxis que he elegido para los marcadores de posición "extendidos" en las sentencias de SQL parametrizadas. Debido a que construir algunos constructos (cláusulas IN) me estaba molestando, decidí usar algunos atajos de sintaxis que se expanden automáticamente a ordinarios. marcadores de posición.
Me gustan. Pero quiero empaquetarlo para distribución, y me pregunto si es fácil de entender.

Básicamente mis nuevos marcadores de posición son ?? y :? (params enumerados) y :& y :, y :| y :: (para los marcadores de posición con nombre) con la siguientes casos de uso:

-> db(" SELECT * FROM all WHERE id IN (??) ", [$a, $b, $c, $d, $e]) 

El ?? se expande en ?,?,?,?,?,... dependiendo del número de $ args a mi funcion db() Este es bastante claro, y su sintaxis ya está estandarizada. Perls DBIx :: Simple también lo usa. Así que estoy bastante seguro de que esta es una idea aceptable.

-> db(" SELECT :? FROM any WHERE id>0 ", ["title", "frog", "id"]); 
// Note: not actually parameterized attr, needs cleanup regex 

Admitir it. Solo me gustó el emoticón. Básicamente, este marcador de posición :? expande un $ args asociativo en nombres de columna simple. Se descarta cualquier valor de $ args de hecho. En realidad, es útil para INSERT junto con las cláusulas IN y, a veces, para IN. Pero aquí ya me pregunto si esta nueva sintaxis es sensata, o no solo un nombre inapropiado porque mezcla: ¿y? caracteres. Pero de alguna manera parece coincidir bien con el esquema de sintaxis.

-> db(" UPDATE some SET :, WHERE :& AND (:|) ", $row, $keys, $or); 

Aquí el mnemónico :, se expande en una lista de name=:name pares separados por , comas. Mientras que :& es una columna =: lista de columnas unidas por AND s. Para la paridad he agregado :|. Sin embargo, el: & tiene otros casos de uso fuera de los comandos de ACTUALIZACIÓN.
Pero mi pregunta no es acerca de la utilidad, pero si:, y: & parecen ser recordables?

-> db(" SELECT * FROM all WHERE name IN (::) ", $assoc); 

Después de algún pesar de que también se añaden :: para interpolar una :named,:value,:list muy parecido ?? expande a ?,?,?. Casos de uso similares, y sensato de tener para la uniformidad.

De todos modos, ¿alguien más ha implementado un esquema como ese? Diferentes marcadores de posición? ¿O cuál recomendarías por simplicidad? Actualización: Sé que la interfaz PHP Oracle OCI también puede vincular parámetros de matriz, pero no usa marcadores de posición específicos para ella. Y estoy buscando sintaxis de marcador de posición comparables.

+0

Creo que pensaste mucho en esto, pero ¿qué pasa con las cláusulas y subconsultas de 'GROUP BY',' HAVING' y 'ORDER BY'? ¿Qué pasa con el formato personalizado, como cuando necesita agrupar por fecha sin incluir la porción de tiempo? ¿Qué pasa con las funciones que necesitan configuración adicional, como COALESCE o cualquier cosa que use la cláusula OVER (suponiendo que sea compatible)? –

+0

@OMG Nah, no pensé mucho en eso. Me he concentrado en mis casos de uso más frecuentes. Y SQL dinámico específico todavía necesita trabajo manual. Especialmente expresiones. Pero por ejemplo:? podría usarse para las cláusulas ORDER y GROUP BY. Y para algunos constructos ya tengo el soporte {TOKEN} (que en esencia es la concatenación de SQL de nuevo). – mario

+0

@stereofrog: De hecho. Aunque el objetivo de backend es diferente y estaba más preocupado con tirar matrices en SQL. La metodología del marcador de posición es comparable. – mario

Respuesta

3

Es posible que desee evitar el uso de := como marcador de posición porque ya tiene has a usage en, por ejemplo, MySQL.

Ver por ejemplo this answer para un uso en el mundo real.

+0

Además, ':' en Oracle (y posiblemente en Postgres, tal vez otros) es la sintaxis de la variable BIND. Oracle también usa ': =' para la asignación de valores. –

+0

¡Buena captura! No pensé demasiado en los procedimientos almacenados. – mario

2

Muy limpio! Creo que los marcadores de posición están bien siempre que los documente bien y proporcione muchos ejemplos cuando los distribuya. Está bien que hayas inventado tus propios marcadores de posición; alguien tenía que pensar en usar ?, después de todo.

4

Me gusta la idea básica detrás de su propuesta, pero no me gusta el "nombre" de los marcadores de posición. Tengo básicamente dos objeciones:

  • Sus marcadores de posición START, ya sea con o : con ?. Debe elegir un formulario, por lo que un marcador de posición puede ser reconocido inmediatamente. Elegiría ? porque tiene menos colisiones posibles con SQL y es más común para denotar marcadores de posición.
  • Los marcadores de posición son difíciles de entender y difíciles de recordar. :& y :| me parecen plausibles, pero distinguir ??, :? y : es bastante difícil.

cambié DB class para apoyar un poco más marcadores de posición y ser más inteligente: DB_intelligent.php (. La parte del README sobre marcadores de posición no se aplica a esta clase es sólo para la clase normal.)

La clase DB tiene dos tipos de marcadores de posición: el marcador de posición multifuncional ? y el marcador de posición de matriz asociativa ?x (x pueden ser ,, & o |).

? marcador de posición: Este marcador de posición determina el tipo de inserción del tipo del argumento:

null    => 'NULL' 
'string'   => 'string' 
array('foo', 'bar') => ('foo','bar') 

?x marcador de posición: Cada elemento de la matriz se convierte en una estructura de `field`='value' y implosión con una delimitador. El delimitador está especificado por el componente x: , delimita por comas, & por AND y | por OR.

código Ejemplo:

DB::x(
    'UPDATE table SET ?, WHERE value IN ? AND ?&', 
    array('foo' => 'bar'), 
    array('foo', 'bar'), 
    array('hallo' => 'world', 'hi' => 'back') 
); 

// Results in this query: 
// UPDATE table SET `foo`='bar' WHERE value IN ('foo','bar') AND `hallo`='world' AND `hi`='back' 

Algunos pensamientos que tenía, mientras que el diseño de esta versión de la clase DB:

Un pensamiento obvio que pueda surgir: ¿Por qué no usar ? para todos tipos de datos, incluso matrices asociativas. Solo agregue ?& y ?| adicionalmente. Usar ? en una matriz asociativa sería lo mismo que usar ?, en el diseño actual. La razón por la que no hice esto es la seguridad. A menudo desea insertar datos de <select multiple> en la consulta (IN ?). Pero como HTML permite arrays (form[array]), los controles de formulario también pueden enviarse a una matriz asociativa con el mismo nombre. Por lo tanto, mi Query Compositor lo reconocería como una lista de campo => valor. Aunque esto probablemente no dañe la seguridad, resultaría en un error de SQL que es malo.

+0

Muy interesante. No deberías usar addslashes sin embargo. Es similar a lo que tiene stereofrog, los especificadores de tipo difieren y tu '?' Siempre deduce el sql del tipo php. Me gusta la interfaz DB :: x(), parece un ahorro de tiempo. (- Mi mezcla con '? *' Y ': *' se debe a la diferencia de? Enumerated y: named parameter placeholders. ":?" Es un poco de both.and smiley.) – mario

+0

¿Por qué no debería usar 'addslashes'? ¿Es menos seguro que 'self :: $ instance-> quote'? Si es así, lo cambiaré. – NikiC

+0

Es un problema muy hipotético, pero -> quote tiene en cuenta a UTF-8 mientras que las secuencias de codificación alternativas pueden deslizarse a través de addslashes. Depende del juego de caracteres y la base de datos. Por ej. SQLite no importaría. – mario

2

Si usted está dispuesto a pasar algún tiempo para aprender doctrine entonces usted podría hacer cosas increíbles como:

$q = Doctrine_Query::create() 
    ->select('u.id') 
    ->from('User u') 
    ->whereIn('u.id', array(1, 3, 4, 5)); 

echo $q->getSqlQuery(); 

lo que produciría una consulta así:

SELECT 
u.id AS u__id 
FROM user u 
WHERE u.id IN (?, 
?, 
?, 
?) 

Este ejemplo fue tomado de : doctrine dql documentation

+0

Gracias por la sugerencia. Sin embargo, Doctrine incurre en demasiada sobrecarga para mis usos. Los ORM son buenos para muchos casos de uso, pero básicamente equivalen a "procedimientos no almacenados". Y el generador de consultas de Doctrine requiere ambos, aprender otro idioma de dominio encima de SQL y también predefinir esquemas (YAML). Lo veo simplificando significativamente las bases de datos complejas. Para tablas singulares es un poco exagerado. Aunque tiene el manejo de matriz que estoy buscando hasta cierto punto. – mario

+0

YAML no es realmente necesario. Puedes vivir perfectamente sin él y escribir tus clases modelo tú mismo. YAML es simplemente una herramienta fácil para la creación automatizada de sus modelos. – ITroubs

+0

¿Qué pasa si pasa su matriz como esa implosión (',', $ array) a sus funciones? una matriz que se parece a esa matriz ("primero", "segundo", "tercero") se transformaría en "primero, segundo, tercero" – ITroubs

Cuestiones relacionadas