Quiero preguntar cómo otros programadores están produciendo cadenas de SQL dinámico para la ejecución como el Texto de comando de un objeto SQLCommand.¿Existe un enfoque estándar para generar SQL dinámicamente?
Estoy produciendo consultas parametrizadas que contienen cláusulas "WHERE" generadas por el usuario y campos SELECT. Algunas veces las consultas son complejas y necesito mucho control sobre cómo se construyen las diferentes partes.
Actualmente, estoy usando muchos bucles y declaraciones de interruptor para producir los fragmentos de código SQL necesarios y para crear los parámetros de SQL necesarios. Este método es difícil de seguir y hace que el mantenimiento sea una tarea ardua.
¿Hay una manera más limpia y más estable de hacer esto?
¿Alguna sugerencia?
EDIT: para añadir detalles a mi post anterior:
1. No puedo realmente la plantilla de mi consulta debido a los requisitos. Simplemente cambia demasiado.
- Tengo que permitir funciones agregadas, como Count(). Esto tiene consecuencias para la cláusula Group By/Having. también causa sentencias SELECT anidadas. Esto a su vez afecta el nombre de columna utilizado por
- Algunos datos de contacto se almacenan en una columna XML. Los usuarios pueden consultar estos datos ASÍ COMO AS y las otras columnas relacionales juntas. Las consecuencias son que las columnas xml no pueden aparecer en cláusulas Group By [sintaxis sql].
- Estoy utilizando una técnica de paginación eficiente que utiliza Row_Number() Función de SQL. Las consecuencias son que tengo que usar una tabla Temp y luego obtener @@ rowcount, antes de seleccionar mi subconjunto, para evitar una segunda consulta.
voy a mostrar algo de código (el horror!) Para que ustedes tienen una idea de lo que estoy tratando.
sqlCmd.CommandText = "DECLARE @t Table(ContactId int, ROWRANK int" + declare
+ ")INSERT INTO @t(ContactId, ROWRANK" + insertFields + ")"//Insert as few cols a possible
+ "Select ContactID, ROW_NUMBER() OVER (ORDER BY " + sortExpression + " "
+ sortDirection + ") as ROWRANK" // generates a rowrank for each row
+ outerFields
+ " FROM (SELECT c.id AS ContactID"
+ coreFields
+ from // sometimes different tables are required
+ where + ") T " // user input goes here.
+ groupBy+ " "
+ havingClause //can be empty
+ ";"
+ "select @@rowcount as rCount;" // return 2 recordsets, avoids second query
+ " SELECT " + fields + ",field1,field2" // join onto the other cols n the table
+" FROM @t t INNER JOIN contacts c on t.ContactID = c.id"
+" WHERE ROWRANK BETWEEN " + ((pageIndex * pageSize) + 1) + " AND "
+ ((pageIndex + 1) * pageSize); // here I select the pages I want
En este ejemplo. Estaría consultando datos XML. Para datos puramente relacionales, la consulta es mucho más simple. Cada una de las variables de sección son StringBuilders. Donde se construyen las cláusulas de este modo:
//Add Parameter to SQL Command
AddParamToSQLCmd(sqlCmd, "@p" + z.ToString(), SqlDbType.VarChar, 50, ParameterDirection.Input, qc.FieldValue);
// Create SQL code Fragment
where.AppendFormat(" {0} {1} {2} @p{3}", qc.BooleanOperator, qc.FieldName, qc.ComparisonOperator, z);
Puede que realmente no tenga una opción aquí, pero conserve en mis bases de datos como Oracle hará un análisis exhaustivo de estas sentencias SQL cada vez que las encuentre, lo que ralentizará el procesamiento. Peor aún, empujan los planes explicados en caché de la pila impactando a otros usuarios de la misma manera. – ScottCher