Está en la página 1de 3

Sql Dinmico.

Interesante artculo sobre sql dinmico de


Csar Manivesa sql@manivesa.com http://sql.manivesa.com

SQL Dinmico: Exec y sp_executeSql


La ejecucin dinmica de instrucciones SQL es algo a lo que tarde o temprano (ms bien temprano) tenemos que enfrentarnos. Y ya que tenemos que hacerlo ms vale saber como funciona y tener un poco de cuidado Por qu dinmico Hablamos de ejecucin dinmica porque la sentencia SQL que va a ejecutar nuestro servidor no esta escrita en ningn sitio, sino que se crea cada vez que tenemos que ejecutarla. Frente a esta forma de trabajar tenemos el SQL normal, donde la sentencia SQL esta previamente escrita y lo nico que hay que hacer es decidir cuando la ejecutamos. Tipos de SQL dinmico Siempre es difcil hacer una clasificacin, pero en este caso vamos a intentar diferenciar el SQL dinmico que se crea en el servidor y el que creamos en nuestras aplicaciones. Por ejemplo si trabajamos en Visual Basic NET y en nuestro cdigo tenemos algo como esto: Dim sSQL as string Dim entrada as string Dim miCon As New SqlConnection(cadena conexin) de alguna manera el usuario escribe una condicin y metemos ese valor en la variable entrada sSQL=SELECT * FROM Clientes WHERE Nombre = sSQL=sSQL + + entrada + ` Dim cmdProductos As New SqlCommand(sSQL, miCon) cmdProductos.CommandType = CommandType.Text miCon.Open() . . . =cmdProductos.ExecuteReader() y todo lo que haga falta para usar los datos devueltos . . . Esto sera SQL dinmico generado en el cliente. Pero no es esto lo que nos interesa. Nosotros vamos a centrarnos en el SQL generado en el servidor, generalmente dentro de un procedimiento almacenado. Primero veamos como podemos pasar el cdigo anterior a un procedimiento almacenado que recibe un parmetro: CREATE PROCEDURE VerProductos @Nombre varchar(50) AS SELECT * FROM Productos WHERE Nombre = @Nombre GO Ms o menos lo mismo no? Pues s, pero no. La diferencia est en que cuando creamos la sentencia desde el cliente podemos hacer prcticamente de todo para editar y construir esa sentencia. Y cuando lo hacemos un procedimiento almacenado tenemos limitaciones a la hora de utilizar variables para construir nuestra sentencia. Supongamos que necesitamos una sentencia SQL donde la parte dinmica es el nombre de la tabla. Parece lgico escribir algo as: CREATE PROCEDURE ElegirTabla @NombreTabla VarChar(128) AS SELECT * FROM @NombreTabla GO Pero si lo ejecutamos lo nico que obtenemos es un error. Incorrect syntax near '@NombreTalba'

No podemos utilizar variables en cualquier parte de una sentencia! Por ejemplo no podemos utilizarlas en la clusula FROM. Ejecutar SQL dinmico con EXEC Ahora es cuando ya tenemos que utilizar SQL dinmico de servidor propiamente dicho. Para solucionar el error de antes generaremos dentro de nuestro procedimiento almacenado una sentencia en una variable de texto como hacamos desde Visual Basic NET y luego le diremos al SQL Server que ejecute esa sentencia mediante el comando EXEC. CREATE PROCEDURE ElegirTabla @NombreTabla VarChar(128) AS DECLARE @sSQL VarChar(1000) --El truco esta en tener la sentencia dentro de una variable SELECT sSQL = 'SELECT * FROM ' SELECT @sSQL = @SQL + @NombreTabla --Y ejecutar ese texto contenido en nuestra variable EXEC ( @sSQL) GO Como vemos es sencillo, pero utilizar el SQL as dentro de un procedimiento almacenado nos ocasiona dos problemas. En primer lugar utilizar as los parmetros da lugar a problemas de seguridad porque estamos permitiendo que el usuario utilice trucos de inyeccin de cdigo y que nuestro procedimiento almacenado haga cosas para las que no fue creado. Un ejemplo de lo que alguien podra llegar a hacer es: EXEC ElegirTabla Clientes GO DROP TABLE Pedidos''' Que un usuario pueda ejecutar sentencias como esta no es algo muy deseable verdad. El segundo problema que nos plantea el uso de EXEC es de rendimiento. Como ya sabemos una de las ventajas de los procedimientos almacenados es que cuando se ejecuta la primera vez se compila, y no es necesario recompilarlo en ejecuciones sucesivas. Pero esto deja de ser cierto cuando usamos EXEC para ejecutar SQL dinmico porque cada ejecucin requiere una compilacin. Esto nos lleva al segundo modo de ejecutar SQL dinmico dentro de un procedimiento almacenado. SP_EXECUTESQL El procedimiento 'sp_executesql puede utilizarse como alternativa a los procedimientos almacenados para ejecutar varias veces una instruccin de Transact-SQL si la nica modificacin es que cambian los valores de los parmetros. Como dicen los BOL, al permanecer constante la propia instruccin SQL y variar slo los valores de los parmetros, es probable que el optimizador de consultas del SQL Server vuelva a utilizar el plan de ejecucin que genera para la primera ejecucin. El funcionamiento de sp_executesql es el siguiente: sp_executesql [@stmt =] stmt [ {, [@params =] N'@parameter_name data_type [,...n]' } {, [@param1 =] 'value1' [,...n] } ] Usar este procedimiento almacenado soluciona en gran parte los dos problemas que veamos con la ejecucin dinmica a travs de EXEC. Por un lado lo nico que se transmite a sp_executesql son los parmetros y eso evita la inyeccin de cdigo, y por otro lado se puede reutilizar el plan de ejecucin. Veamos un ejemplo de cmo utilizar este procedimiento. USE NorthWind DECLARE @sSQL nvarchar(1000) --la variabla que contiene la cadena a ejecutar debe ser unicode, por eso lo de nvarchar SET @sSQL = 'SELECT * FROM Products WHERE ProductName = @NombreProducto' EXEC sp_executesql @sSQL, N'@NombreProducto nvarchar(50)', @NombreProducto = 'chai' Como vemos el primer parmetro es la sentencia que queremos ejecutar, despus viene declarada la variable que vamos a usar y por ltimo le damos valor a esa variable.

Seguro que se os ocurren un par de utilidades para sp_executesql. Ms sobre SP_EXECUTESQL Sp_executesql tiene unas cuantas peculiaridades que conviene tener en cuenta. Para empezar la ejecucin de una sentencia a traves de sp_executesql se hace en un mbito propio. Esto quiere decir que las variables declaradas fuera no se pueden utilizar, que las declaradas dentro no se pueden leer desde fuera, que podemos cambiar la base de datos (utilizar USE) en la que trabajar dentro del sp_executesql, crear tablas temporales en el nuevo mbito, utilizar sentencias SET sin hacer cambios en la configuracin del procedimiento llamante, y por ltimo aunque no menos importante que si se produce un error y se aborta la instruccin tambin se aborta el procedimiento en el que se est ejecutando. En cuanto a los permisos recordar algo muy importante. La sentencia SQL se ejecuta dentro del contexto de seguridad del usuario, no del procedimiento que llama a esa sentencia. Un ejemplo de cmo usar y como no usar SQL dinmico Para concluir vamos a ver un ejemplo donde podemos usar SQL dinmico. A veces tenemos que crear una sentencia que ordene una tabla segn una columna que depender de algn parmetro que nos pasa el usuario. Eso lo podemos resolver utilizando un procedimiento almacenado y una sentencia como: CREATE PROCEDURE OrdenarPor @Columna varchar(50) AS DECLARE @sSQL varchar(50) SET @sSQL=SELECT * FROM MiTabla ORDER BY + @Columna EXEC @sSQL Esto est en la lnea de todo lo que hemos estado diciendo. Es una solucin sencilla pero que como no nos hemos cansado de repetir plantea varios problemas de seguridad y rendimiento. As que por que no pensamos un poco e intentamos crear un procedimiento almacenado que haga lo mismo? Creedme que pocas veces encontraremos una tarea que no se pueda resolver sin recurrir al SQL dinmico. Fijmonos en lo siguiente: CREATE PROCEDURE OrdenarPor @Columna varchar(50) AS SELECT * FROM miTabla ORDER BY CASE @Columna WHEN 'columna1' THEN columna1 WHEN 'columna2' THEN columna2 WHEN 'columna3' THEN columna3 END Cierto que es un poco ms complicado (se utiliza la funcin CASE), pero no hay inyeccin de cdigo posible y una vez calculado el plan de ejecucin se utilizar sin recompilar una y otra vez Como conclusin nos queda que el SQL dinmico es una herramienta potente pero peligrosa si no se trata con cuidado, y que la mayora de las veces no necesitamos recurrir a ella porque siempre podemos encontrar otra solucin. Csar Manivesa sql@manivesa.com http://sql.manivesa.com

También podría gustarte