2010-05-05 11 views
5

Esta es una pregunta muy abierta, pero creo que puede ser muy beneficioso para la legibilidad de SQL.¿Cómo se hace legible el SQL largo invocado desde otro código?

Así que tiene un programa Java, y está tratando de llamar a una declaración SQL monstruosa desde allí, con muchas subconsultas y combinaciones. El punto de partida de mi pregunta es una constante como esta cadena:

static string MONSTER_STATEMENT = 
    "SELECT " + 
    " fields" + 
    "WHERE "+ 
    " fieldA = (SELECT a FROM TableC) " + 
    "AND fieldB IN (%s)" + 
    "AND fieldC = %d " + 
    "FROM " 
    " tableA INNER JOIN tableB ON ..."; 

Más tarde se llena usando String.Format y ejecutado.

¿Cuáles son sus trucos para hacer que este tipo de cosas sean legibles? ¿Separe sus uniones internas? ¿Indenta el SQL mismo dentro de la cadena? ¿Dónde pones los comentarios? Por favor comparte todos los trucos en tu arsenal.

+0

Subjetivo y argumentativo. Además, esto debería ser Wiki de la comunidad – Seb

+0

Para preguntas subjetivas como esta, marque la casilla "wiki comunitario" (debería poder editar su pregunta y hacer eso ahora). –

+1

@Seb, aunque algo subjetivo (la belleza está en el ojo del espectador) No veo nada argumentativo al respecto. – Yishai

Respuesta

0

Dicho SQL complejo debe estar en una declaración preparada, no unida por un String.format para evitar problemas de inyección de SQL.

Realizo una de estas dos cosas: Envolverlo en una declaración invocable o ponerlo en un archivo de configuración/xml. Los archivos fuente de Java son un mal lugar para SQL complejo.

Dicho esto, IDEA tiene una característica de formato de idioma que formateará cadenas en Java para que parezcan un idioma diferente (según el método al que se las transfiere o se basa en una anotación), de modo que eso puede ser útil.

Editar: Dada su situación, acepto que las declaraciones invocables pueden no ser factibles. Las declaraciones preparadas aún lo valen, incluso para el desarrollo interno, solo porque un parámetro con un apóstrofo puede hacer explotar todo (incluso si no hay un atacante), por lo que aún vale la pena, IMO, hacer el esfuerzo adicional para crear la cadena. dinámicamente (String.format o cualquier otra cosa) en el código solo para las partes que no se pueden pasar como parámetros (tales como los nombres de tablas temporales como en su ejemplo), y luego usar eso como una declaración preparada que pasa los parámetros adecuados para el resto.

En cuanto a mantenerlo menos feo, parece que un archivo de configuración/tipo xml es lo que yo buscaría.

+0

Me encantaría usar sentencias preparadas/invocables, pero encontré estos problemas: 1) Son un gran problema para implementar: esto es para un panel interno y estamos usando la implementación continua. En un tema relacionado, son difíciles de editar. 2) Usan SQL preparado, y no es tan flexible. Necesito poder generar, por ejemplo, una tabla con un nombre nuevo (por ejemplo, INSERT INTO TableForExperiment _ $ {DATE}). 3) Las declaraciones que pueden llamarse no son mucho más fáciles de comentar o hacer legibles (por ejemplo, no tengo forma de poner una subconsulta en una cadena separada). – Artem

+0

@Artem: Aún puede usar un ad hoc 'PreparedStatement', ¿o no? Siempre que ** usted ** controle el texto que varía, las cosas no están mal. El verdadero problema es cuando los usuarios pueden inyectar su propio texto que se representa como sql en línea. –

+0

@Chris, ¿qué quiere decir exactamente con un PreparedStatement ad-hoc? ¿Estamos hablando de un procedimiento almacenado o algo más? No encuentro que la lógica de procedimientos almacenados sea más fácil de leer, y siempre he querido poder programar dentro del proceso del servidor. Programar el procedimiento de SQL es solo algo mejor que la programación en XML (ANT - yuck). – Artem

1

Mi inclinación es formatear mi declaración de SQL de la misma manera que me gustaría si me preguntara directamente sobre la base de datos usando una consola de administración como Management Studio. Por lo tanto, cuando construyo una declaración SQL, me tomo el tiempo de poner espacios y saltos de línea. El espacio adicional consumido es insignificante en comparación con el ahorro de tiempo de poder leer el SQL si debo imprimirlo o capturarlo usando algo SQL Profiler. Por lo tanto, me inclinaría a usar StringBuilder de montar mi SQL, así:

StringBuilder sql = new StringBuilder(); 
sql.append("Select ...."); 
sql.append("\t\n, AdditionalCol, ..."); 
sql.append("\nFrom ..."); 
sql.append("\n Inner Join ..."); 
sql.append("\n  On ColA = ..."); 
sql.append("\nWhere Col1 = ("); 
sql.append("\n   Select a"); 
sql.append("\n   From TableC"); 
sql.append("\n   "); 
sql.append("\n And ColB In(%s)"); 
sql.append("\n And ColC = %d"); 
+0

+1 para la legibilidad, pero también debe usar consultas parametrizadas para evitar la inyección de sql, y utilice un método similar a http://stackoverflow.com/questions/1254940/is-herehere-a-way-to-get-the- full-sql-text-back-from-sqlcommand-after-param-substitution/1255040 # 1255040 (en C#) para registrar el SQL con sus parámetros reales – ckarras

1

una clase de ayuda que Wrapps todo el proceso de construcción puede ayudarle. Eso podría ser uno: http://openhms.sourceforge.net/sqlbuilder/

De todos modos, siempre vaya con las declaraciones preparadas.

+0

Esta es una alternativa interesante. ¿Alguien ha utilizado con éxito declaraciones complejas? (ver más arriba mis problemas con las declaraciones preparadas) – Artem

+0

sqlbuilder fue escrito exactamente para este propósito, para hacer que las sentencias monstruosas de sql sean manejables, tanto estáticas como generadas dinámicamente. – jtahlborn

Cuestiones relacionadas