Si es posible, no hagas esto.
Esa es la respuesta: es un anti-patrón. Si el cliente conoce la tabla de la que quiere datos, entonces SELECT FROM ThatTable
. Si una base de datos está diseñada de manera que esto sea necesario, parece estar diseñada de manera subóptima. Si una capa de acceso a datos necesita saber si existe un valor en una tabla, es fácil componer SQL en ese código y no es bueno insertar este código en la base de datos.
Para mí, esto parece como instalar un dispositivo dentro de un ascensor donde se puede ingresar el número del piso deseado. Después de presionar el botón Ir, mueve una mano mecánica al botón correcto para el piso deseado y lo presiona. Esto introduce muchos problemas potenciales.
Tenga en cuenta: no hay intención de burla, aquí. Mi tonto ejemplo de ascensor fue * el mejor dispositivo que pude imaginar * para señalar de manera sucinta problemas con esta técnica. Agrega una capa inútil de indirección, moviendo la elección del nombre de la tabla desde un espacio de llamada (usando un DSL, SQL robusto y bien entendido) a un híbrido usando código SQL del lado del servidor oscuro / extraño.
Tal división de responsabilidades mediante el movimiento de la lógica de construcción de consultas en SQL dinámico hace que el código sea más difícil de entender. Viola una convención estándar y confiable (cómo una consulta SQL elige qué seleccionar) en el nombre del código personalizado plagado de posibles errores.
A continuación, se detallan algunos de los problemas potenciales con este enfoque:
El SQL dinámico ofrece la posibilidad de una inyección de SQL que es difícil de reconocer en el código del front-end o solo en el código del back-end (se deben inspeccionar juntos para ver esto).
Los procedimientos y funciones almacenados pueden acceder a los recursos a los que el propietario de la función / SP tiene derechos, pero el que llama no. Por lo que tengo entendido, sin un cuidado especial, entonces, de forma predeterminada, cuando usa código que produce SQL dinámico y lo ejecuta, la base de datos ejecuta el SQL dinámico bajo los derechos de la persona que llama. Esto significa que no podrá utilizar objetos con privilegios en absoluto o tendrá que abrirlos a todos los clientes, lo que aumentará la superficie de posible ataque a los datos privilegiados. Configurar la función SP / en el momento de la creación para que siempre se ejecute como un usuario en particular (en SQL Server EXECUTE AS
) puede resolver ese problema, pero complica las cosas. Esto agrava el riesgo de inyección de SQL mencionado en el punto anterior, al hacer del SQL dinámico un vector de ataque muy atractivo.
Cuando un desarrollador debe comprender qué está haciendo el código de la aplicación para modificarlo o corregir un error, le resultará muy difícil conseguir que se ejecute la consulta SQL exacta. Se puede usar el generador de perfiles SQL, pero esto requiere privilegios especiales y puede tener efectos negativos en el rendimiento de los sistemas de producción. El SP puede registrar la consulta ejecutada, pero esto aumenta la complejidad para un beneficio cuestionable (que requiere acomodar nuevas tablas, depurar datos antiguos, etc.) y no es bastante obvio. De hecho, algunas aplicaciones están diseñadas de tal manera que el desarrollador no tiene credenciales de base de datos, por lo que le resulta casi imposible ver la consulta que se envía.
Cuando se produce un error, como cuando intenta seleccionar una tabla que no existe, obtendrá un mensaje en la línea de "nombre de objeto no válido" de la base de datos. Eso sucederá exactamente igual si está componiendo el SQL en el back-end o en la base de datos, pero la diferencia es que algún desarrollador pobre que está tratando de solucionar problemas del sistema tiene que escribir un nivel más profundo en otra cueva debajo de la que está existe un problema, profundizar en el procedimiento maravilloso que lo hace todo para tratar de averiguar cuál es el problema. Los registros no mostrarán "Error en GetWidget", mostrará "Error en OneProcedureToRuleThemAllRunner". Esta abstracción por lo general hacer un sistema peor .
Un ejemplo en pseudo-C # de cambiar nombres de tablas según un parámetro:
string sql = $"SELECT * FROM {EscapeSqlIdentifier(tableName)};"
results = connection.Execute(sql);
Si bien esto no elimina todos los problemas posibles imaginables, los defectos que describí con la otra técnica están ausentes en este ejemplo.