Ir al contenido principal

Procedimientos Almacenados (store procedures – sp)

Este post lo hago para ayuda de memoria y también para los que necesiten una mano sobre Transact-SQL.

Puede crear procedimientos almacenados mediante la instrucción CREATE PROCEDURE de Transact-SQL.

Cuando cree un procedimiento almacenado, deberá especificar lo siguiente:
  • Todos los parámetros de entrada y de salida del lote o del procedimiento que realiza la llamada. 
  • Las instrucciones de programación que realicen operaciones en la base de datos, incluidas las llamadas a otros procedimientos. 

No es recomendable utilizar el prefijo sp_ para crear procedimientos almacenados. SQL Server siempre busca procedimientos almacenados que empiezan con sp_ siguiendo este orden:
  1. El procedimiento almacenado en la base de datos master
  2. El procedimiento almacenado basándose en cualquiera de los calificadores especificados (nombre o propietario de la base de datos. 
  3. El procedimiento almacenado mediante el propietario dbo, si no se especifica otro. 

Por lo tanto, aunque en la base de datos actual pueda haber un procedimiento almacenado creado por el usuario y que empiece por sp_, en primer lugar se comprueba siempre la base de datos master incluso cuando el procedimiento esté calificado con el nombre de la base de datos.

Si algún procedimiento almacenado creado por un usuario tiene el mismo nombre que un procedimiento almacenado del sistema, el que haya creado el usuario no llegará a ejecutarse

los procedimientos almacenados temporales, tanto privados como globales, se pueden crear agregando los prefijos # y ## delante del nombre del procedimiento. # denota un procedimiento almacenado temporal local; ## denota un procedimiento almacenado temporal global. Estos procedimientos dejan de existir cuando se cierra SQL Server.


(Similar notación se utiliza para las tablas temporales: #nomb_tabla_local , ##nomb_tabla_global)

Declare


Las variables se declaran en el cuerpo de un proceso por lotes o procedimiento con la instrucción DECLARE, y se les asignan valores con una instrucción SET o SELECT. Después de su declaración, todas las variables se inicializan con NULL (nulo). @var_local , @@var_global

DECLARE @nombre varchar(30)
  SET @nombre = 'Maria'

CREATE PROCEDURE  ver_articulos  AS
  SELECT  descripcion, cantidad, precio_compra  
  FROM articulos      
  WHERE cantidad < 100
GO
 
CREATE PROCEDURE  #busco_articulo 
  @cod_art INT 
AS
  SELECT
  FROM articulos
  WHERE codigo_articulo = @cod_art
GO

EXEC #busco_articulo @cod_art = 2
GO

Para mostrar el texto utilizado para crear el procedimiento, ejecute sp_helptext en la base de datos en que existe el procedimiento, con el nombre del procedimiento como parámetro. sp_helptext   ver_articulos



Palabras claves de Transact-SQL

BEGIN...END

Encierra un conjunto de instrucciones Transact-SQL de forma que se pueda ejecutar. BEGIN y END son palabras clave del lenguaje de control de flujo.

IF...ELSE

Impone condiciones en la ejecución de una instrucción Transact-SQL. La instrucción Transact-SQL que sigue a una palabra clave IF y a su condición se ejecuta si la condición se satisface (cuando la expresión booleana devuelve TRUE). La palabra clave opcional ELSE introduce una instrucción Transact-SQL alternativa que se ejecuta cuando la condición IF no se satisface (cuando la expresión booleana devuelve FALSE).


CREATE PROCEDURE #busco_art 

   @cod_art INT 
AS 
   IF(SELECT AVG(precio_compra) 
       FROM articulos 
       WHERE codigo_articulo < @cod_art) < 15
   BEGIN
       PRINT 'Los siguientes articulos en oferta:'
       PRINT ' '
       SELECT SUBSTRING(descripcion, 1, 10)
AS Articulo,precio_venta
      FROM articulos
      WHERE codigo_articulo < @cod_art
   END

exec #busco_art @cod_art = 5

 

WHILE

Establece una condición para la ejecución repetida de una instrucción o bloque de instrucciones de SQL. Las instrucciones se ejecutan repetidamente mientras la condición especificada sea verdadera. Se puede controlar la ejecución de instrucciones en el bucle WHILE con las palabras clave BREAK y CONTINUE.

BREAK
Hace que se salga del bloque WHILE más interno. Se ejecutan las instrucciones que aparecen después de la palabra clave END, que marca el final del bucle.
CONTINUE
Hace que se reinicie el bucle WHILE y omite las instrucciones que haya después de la palabra clave CONTINUE.
Observaciones
Si dos o más bucles WHILE están anidados, la instrucción BREAK interna sale al siguiente bucle más externo. Primero se ejecutan todas las instrucciones que haya después del final del bucle interno y, a continuación, se reinicia el siguiente bucle más externo.

WHILE (SELECT AVG(precio_venta) FROM articulos) < 10
BEGIN
   UPDATE articulos
      SET precio_compra = precio_compra * 2
      SELECT MAX(precio_venta)AS maximo 
      FROM articulos
      IF (SELECT MAX(precio_venta) FROM articulos) > 35
        BREAK
      ELSE
       CONTINUE
END




20 tips para escribir stored procedures en SQL Server


Esta es una breve lista de recomendaciones básicas que ayudan mucho al momento de trabajar con stored procedures en SQL Server.

Como últimamente he utilizado mucho SQL Server 2008 R2 puede haber alguna sugerencia que solo aplique a dicha versión.

1) Para facilitar la lectura utilice una identación adecuada.

2) Agregue comentarios en la lógica compleja y utilice el wizard de creación de objetos (stored procedures en este caso) para completar los campos sugeridos (autor, fecha de creación, breve descripción).  Recuerde utilizar Ctrl+Shift+M para especificar los valores del template.

3) Es buena práctica escribir las palabras reservadas en mayúsculas (por ej. SELECT, RTRIM, FROM, DELETE, etc..) porque facilitan mucho la lectura del código.

4) Escriba el nombre del stored procedure de forma correctamente calificada ( por ej. [dbo]. EmployeeSalaryCalc )

5) En lo posible siempre declarar e inicializar las variables al comienzo del código del stored procedure, tratar de usar la cantidad de variables mínimas necesarias.

6) No escriba el nombre del stored procedure comenzando con el prefijo “sp_”, esto es reservado para los sotred procedures de sistema de SQL Server. Cuando se hace la solicitud de un stored procedure que comienza con ese prefijo el motor de base de datos intenta buscar primero en la base de datos “master” y luego en las demas.

7) Agregue la opción de SET NOCOUNT ON al inicio del procedimiento para evitar el mensaje innecesario de número de filas afectadas.

8) Utilice tablas temporales solamente cuando es necesario. Los stored procedure suelen utilizar un plan de ejecución, almacenado en caché, para aumentar el rendimiento, cuando se utilizan tablas temporales se requiere hacer la compilación en cada ejecución y no se puede aprovechar el plan de ejecución.

9) Trate de devolver siempre las columnas necesarias, es muy recomendable evitar sentencias del tipo “SELECT * FROM”.

10) Utilice cursores solo cuando es necesario. Los cursores requieren más memoria y por tanto se degrada el rendimiento del stored procedure. En algunos casos se puede utilizar la variable de tabla y el bucle  WHILE para iterar sobre un el conjunto de resultados.

11) Es buena práctica asignar el valor por defecto para cada parámetro y siempre establecer el tamaño correcto de las variables (tanto de retorno como internas). Por ejemplo si en la tabla un campo determinado tiene largo 100 (Username (varchar(100)) y en el procedimiento se utiliza como varchar(200) se puede producir un error en tiempo de ejecución del tipo "error de cadena truncada" si se está frente a un INSERT o UPDATE de dicho campo.

12) Utilice la sentencia Try para capturar adecuadamente los errores en tiempo de ejecución dentro del stored procedure y hacer un manejo acorde en dicha situación.

13) Ante consultas complejas y que se utilizan en varias ocasiones, tenga en cuenta crear vistas para un manejo más adecuado.

14) Evite utilizar sub-consultas (SELECT A.column1 FROM (SELECT data1 FROM) as A …), utilice la sentencia INNER JOIN siempre que sea posible.

15) Trate de evitar la condición de filtrado en la cláusula WHERE si puede ser escrito al momento de utilizar la sentencia de JOIN.

16) Utilice la sentencia SELECT TOP 1 para la comprobación/obtención de un dato en base a una condición.
Ej. en lugar de : SELECT @ name = nombre FROM Empleados WHERE nombre LIKE '%Rob%'
Si se devuelven múltiples registros ocasiona un error en momento de ejecución.
SELECT TOP 1 @ name = nombre FROM Empleados WHERE nombre LIKE '%Rob%'

17) En los caso donde se puede aplicar una instrucción CASE es mejor que el anidamiento de sentencias IF-ELSE.

18) Consultas Dinámicas: trate de reducir al mínimo el uso de las consultas dinámicas.
Si está utilizando una consulta dinámica similar a “SELECT * FROM mydb.dbo.emp WHERE empid = @ EmpId”, entonces no hay problema. En este caso se proporciona un valor para el parámetro @EmpId y el motor no tiene que generar o recargar un nuevo plan de ejecución. En cambio si se utiliza una consulta del tipo @query = “SELECT * FROM emp donde empid =” + @ EmpId esto por defecto  no admite un plan de ejecución predeterminado y cargado en el motor de base de datos.

19) Utilice las instrucciones ORDER BY y DISTINCT solo cuando se requieran. Caso contrario el motor de SQL Server obtendrá el primer resultado y lo hará de nuevo si requiere utilizar algunas de estas instrucciones.

20) Utilice los índices correctos en las columnas de cada tabla. No es buena práctica crear índices en las columnas que no se utilizan en las cláusulas WHERE. Cuando se crean índices extras se puede requerir un ida y vuelta extra del motor de base de datos para consultar el resultado

Comentarios

Entradas populares de este blog

Llenar un dropdownlist de mes con C#

Buenas, acá dejo un ejemplo de como llenar un dropdownlist. Lo publico como para tenerlo de referencia, tal vez a alguien le sirva también. Código en C# (code behind)        private void CargarMes()        {            //valor por default            ddlMes.Items.Add("Seleccione mes");            List<string> nombreMes = DateTimeFormatInfo.CurrentInfo.MonthNames.Take(12).ToList();            var listaMesesSeleccionados = nombreMes.Select(m => new            {                Id = nombreMes.IndexOf(m) + 1,                Name = m            });            foreach (var mes in listaMesesSeleccionados)            {  ...

Borrar carpetas .svn en Windows

Cuando se empieza a usar  Subversion  (SVN), para tener un control de los archivos de nuestro proyectos, en ocasiones usaremos clases, librerías, frameworks o carpetas de un repositorio de un tercero. Cuando unimos estas carpetas nuevas, a nuestro repositorio cliente, esta no los interpreta bien porque ya vienen con otras carpetas .SVN con archivos específicos para su repositorio de origen. La solución aquí es eliminar todas las carpetas .SVN de lo que queramos implementar para que nuestro repositorio cliente lo interprete como nuevos archivos y podamos agregarlas al proyecto. Con esto se eliminarán las carpetas .SVN de forma recursiva. Pero escribir toda esa línea no es muy cómodo que digamos en nuestro trabajo del día a día, por eso vamos a automatizar este proceso. En Windows Crearemos un archivo que llamaremos "borrar carpetas SVN.reg" y contendrá lo siguiente: Código : Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\Directory\shell\DeleteSVNFolders] ...

Recursividad

1.1.  Introducción . El concepto de recursividad va ligado al de repetición. Son recursivos aquellos algoritmos que, estando encapsulados dentro de una función, son llamados desde ella misma una y otra vez, en contraposición a los algoritmos iterativos, que hacen uso de bucles while, do-while, for, etc. 1.2.  Definición . Algo es recursivo si se define en términos de sí mismo (cuando para definirse hace mención a sí mismo). Para que una definición recursiva sea válida, la referencia a sí misma debe ser relativamente más sencilla que el caso considerado. 1.3. Elementos de la Recursión  1.3. 1.  Axioma  Es un caso donde el problema puede resolverse sin tener que hacer uso de una nueva llamada a sí mismo. Evita la continuación indefinida de las partes recursivas. 1.3.2.  Formula recursiva Relaciona el resultado del algoritmo con resultados de casos más simples. Se hacen nuevas llamadas a la función, pero están más próximas al caso base. Por eje...