Buenas practicas de programación en SQL

Es muy recomendable seguir siempre las mismas convenciones de nomenclatura cuando se programa para hacer el código más entendible.

 Las razones por las que hay que seguir unas normas en la programación son las siguientes:
  • otros desarrolladores que sigan con los desarrollos lo tendrán más fácil en entender el código y podrán hacer modificaciones mucho más rápido.
  • es más fácil copiar, modificar y mantener el código
  • el código tiene un aspecto más coherente 


En otro artículo ya he explicado como crear plantillas en SQL Server. Las plantillas ayudarán a un grupo de desarrollores a seguir unas normas (Crear plantillas personalizada en SQL Server Management Studio).


Esto vale para todos los lenguajes de Programación. En este artículo voy a enseñar algunas buenas prácticas que deberéis seguir cuando programáis en SQL.

Comentarios

Hay dos tipos de comentarios:

-- esto es un comentario

/* esto es un comentario 
   con múltiples líneas
*/

Los comentarios con los marcadores /* ... */ se deben utilizar principalmente para las cabeceras de comentarios y para otras sección de cabeceras. Yo las utilizo por ejemplo en la cabecera de los procedimientos almacenados (Plantilla para crear un nuevo Procedimiento Almacenado en SQL Server). 

Los marcadores para comentarios de una sola "--" las utilizo para comentarios dentro del código. Los marcadores /* … */ se pueden utilizar dentro del código para comentar partes del código para hacer pruebas y debugging.

Upper- y Lower-Case

Todas las palabras claves de SQL se deben escribir en mayúscula para destacarlas mejor en el código.

Calificadores de campos

Al hacer referencia a campos en consultas, la referencia de campo debe estar siempre calificada con el nombre de tabla, el nombre de la vista, el alias de tabla u otro alias adecuado. Esto hace que el código sea más fácil de entender, ya que el campo se puede identificar de inmediato de que objeto proviene el campo.

Bien:

  SELECT
    Prod.ProdID,
    Prod.Title

  FROM
    vProduct Prod

  WHERE
    Prod.ProdID = 123


Mal:

  SELECT
    ProdID,
    Title

  FROM
    vProduct

  WHERE
    ProdID = 123


En el caso que se tenga que utilizar la misma tabla dos veces en la misma consulta, todas las apariciones de la tabla debe tener un alias, no sólo una de ellas. Esto hace que sea mucho más claro de identificar a cual de las dos tablas hace referencia el campo.

Bien:

  SELECT
    SubProdTitle = SubProd.Title,
    SuperProdTitle = SuperProd.Title

  FROM
    vProduct SubProd

    INNER JOIN vProduct SuperProd
      ON SubProd.ProdID = SuperProd.ProdID


Mal:
  SELECT
    SubProdTitle = vProduct.Title,
    SuperProdTitle = SuperProd.Title

  FROM
    vProduct

    INNER JOIN vProduct SuperProd
      ON vProduct.ProdID = SuperProd.ProdID



Alias de campos

Cuando se utiliza un alias para un campo se debe utilizar el operador "=" antes que la palabra clave "AS". Esto hace más fácil leer la consulta, ya que el nombre del campo que se devuelve se encuentra al principio y no al final que sería el caso si se utiliza "AS".

Bien:

  SELECT
    ConvertedPrice = Prod.Price * 1.234


Mal:
  SELECT
    Prod.Price * 1.234 AS ConvertedPrice 







Plantilla para crear nuevos Indices en SQL Server



-- Add non unique index for a single field
IF NOT EXISTS (SELECT * FROM sysindexes WHERE name = 'inu_TTTTT_FFFFFF')
   CREATE INDEX inu_TTTTT_FFFFFF ON TTTTT(FFFFFF)

--------------------------------------------------------------------------------------------------

-- Add clustered non unique index for a single field
IF NOT EXISTS (SELECT * FROM sysindexes WHERE name = 'inu_TTTTT_FFFFFF')
   CREATE CLUSTERED INDEX inu_TTTTT_FFFFFF ON TTTTT(FFFFFF)

--------------------------------------------------------------------------------------------------

-- Add unique index for a single field
IF NOT EXISTS (SELECT * FROM sysindexes WHERE name = 'iun_TTTTT_FFFFFF')
   CREATE UNIQUE INDEX iun_TTTTT_FFFFFF ON TTTTT(FFFFFF)

--------------------------------------------------------------------------------------------------

-- Add unique index for a combination of two fields
IF NOT EXISTS (SELECT * FROM sysindexes WHERE name = 'iun_TTTTT_FFFFFF_GGGGGG')
   CREATE UNIQUE INDEX iun_TTTTT_FFFFFF_GGGGGG ON TTTTT(FFFFFF, GGGGGG)

--------------------------------------------------------------------------------------------------

Plantilla para crear una Vista en SQL Server



IF EXISTS (SELECT *
           FROM INFORMATION_SCHEMA.VIEWS
           WHERE TABLE_NAME='vXXXXX'
           AND TABLE_SCHEMA='dbo'
          )
          DROP VIEW dbo.vXXXXX
GO

CREATE VIEW dbo.vXXXXX
AS
/*@@*_____________________________________________________________________

  (c) 2013 XXXXX

  Object:  dbo.vXXXXX
  Author:  ...
  Created: ...

  Purpose:

    ...
    ...
    ...


  Revision History:
    Author dd-mmm-yyyy Purpose

_____________________________________________________________________*@@*/


  SELECT
    ...
  FROM
    ...


Plantilla para crear un nuevo Procedimiento Almacenado en SQL Server



IF EXISTS (SELECT *
           FROM INFORMATION_SCHEMA.ROUTINES
           WHERE ROUTINE_NAME='pXXXXX'
           AND ROUTINE_SCHEMA='dbo'
           AND ROUTINE_TYPE='PROCEDURE'
          )
          DROP PROCEDURE dbo.pXXXXX
GO

CREATE PROC dbo.pXXXXX
  @vintCurUserID        INT,
  @vintCurSysLID        INT
AS
/*@@*_____________________________________________________________________

  (c) 2013 XXXXX

  Object:  pXXXXX
  Author:  ...
  Created: ...

  Purpose:

    ...
    ...
    ...


  Parameters:
    @vintCurUserID:  Current user context if available. NULL if unknown.
    @vintCurSysLID:  Language for translated text. NULL if unknown.

  Recordsets:

  Returns:
    0         - Success
    <>0       - Error occurred

  Revision History:
    Author dd-mmm-yyyy Purpose

_____________________________________________________________________*@@*/


/*______________________ CONSTANT DECLARATIONS _________________________*/

  DECLARE
    @cstrThisProc              NVARCHAR(128),
    @cintErrGeneral            INT

  SET @cstrThisProc            = N'pXXXXX'
  SET @cintErrGeneral          = 50000  -- General error. Used when an
                                        -- error has occurred and no other
                                        -- specific error condition is
                                        -- assigned.

/*______________________ VARIABLE DECLARATIONS _________________________*/

  DECLARE
    @intErrNo       INT,
    @strErrMsg      NVARCHAR(400),
    @intReturn      INT

/*_______________________________ INIT _________________________________*/

  -- Setting NOCOUNT ON prevents additional recordsets with the
  -- "number of records affected" from being returned, which is not
  -- handled the same by all providers, such as for OLEDB vs. ODBC.
  SET NOCOUNT ON

/*________________________ VALIDATE PARAMETERS _________________________*/


/*_______________________________ MAIN _________________________________*/



  -- Return value 0 indicates success
  SET @intReturn = 0

lblExit:

  RETURN @intReturn

/*___________________________ ERROR HANDLER ____________________________*/
lblError:
  -- An error has occurred.  On entering this section @intErrNo should
  -- already hold the error number

  -- By default, if there are any open transactions then roll them back
  IF (@@TRANCOUNT > 0) BEGIN
    ROLLBACK TRAN

  END

  -- If return value has not been explicitly set, then use the error
  -- number as return value to signify failure
  IF ((@intReturn IS NULL) OR (@intReturn = 0)) BEGIN
    SET @intReturn = @intErrNo

  END

 GOTO lblExit

Plantilla para crear nuevos campos en SQL Server



-- Add new int field
IF NOT EXISTS(SELECT [Name] FROM syscolumns WHERE Name = 'FFFFFF' AND ID = OBJECT_ID('dbo.TTTTT'))
   ALTER TABLE TTTTT ADD FFFFFF INT NULL

--------------------------------------------------------------------------------------------------

-- Add new nvarchar field
IF NOT EXISTS(SELECT [Name] FROM syscolumns WHERE Name = 'FFFFFF' AND ID = OBJECT_ID('dbo.TTTTT'))
   ALTER TABLE TTTTT ADD FFFFFF NVARCHAR(60) NULL

--------------------------------------------------------------------------------------------------

-- Add new decimal field
IF NOT EXISTS(SELECT [Name] FROM syscolumns WHERE Name = 'FFFFFF' AND ID = OBJECT_ID('dbo.TTTTT'))
   ALTER TABLE TTTTT ADD FFFFFF DECIMAL(28,9) NULL

--------------------------------------------------------------------------------------------------

-- Add new bit field (incl. update existing records with 0)
IF NOT EXISTS(SELECT [Name] FROM syscolumns WHERE Name = 'FFFFFF' AND ID = OBJECT_ID('dbo.TTTTT')) BEGIN
   ALTER TABLE TTTTT ADD FFFFFF BIT CONSTRAINT [rdf_TTTTT_FFFFFF] DEFAULT (0)
   EXEC ('UPDATE TTTTT SET FFFFFF = 0')
END

--------------------------------------------------------------------------------------------------

-- Add new ntext field
IF NOT EXISTS(SELECT [Name] FROM syscolumns WHERE Name = 'FFFFFF' AND ID = OBJECT_ID('dbo.TTTTT'))
   ALTER TABLE TTTTT ADD FFFFFF NTEXT NULL

--------------------------------------------------------------------------------------------------

Crear plantillas personalizada en SQL Server Management Studio

SQL Server tiene una variedad de plantillas que te ayudarán a crear objetos en tu base de datos. Si aún no ves el formulario de plantillas, puedes hacerlo visible en el menú "Ver" -> "Explorador de plantillas".

Las plantillas predeterminadas por el SQL Server no están mal pero muchas veces las empresas tienen sus propias normas, por ejemplo para la documentación del código. La utilización de plantillas en fundamental cuando se desarrolla en equipo y se quiere estandarizar los formatos. Esto garantiza que todos los desarrolladores sigan unas normas y así se consigue que se cumplan más fácilmente las políticas de desarrollo de la empresa.

Aparte de las plantillas que te ofrece el SQL Server puedes también crear tus propias plantillas personalizadas. Pincha sobre el primer nodo "Plantilla de SQL Server" y crea una nueva carpeta o directamente la plantilla.

2. Análisis de los requisitos

Al principio de cada proyecto hay que definir los requisitos y diseñar y planificar la aplicación. Por eso empezamos con la definición de los requisitos de la aplicación de ejemplo que vamos a crear.

Requisitos funcionales
  • Posibilidad de ampliar funcionalmente
  • Adaptable según nuevos requisitos
  • Posibilidad de dejar crecer la aplicación (instalación en varios servidores)

Requisitos técnicos:
  • Base de datos: MS SQL Server
  • Arquitectura multicapas
  • Implantación en .NET
  • Aplicación web en ASP.net 3.5


1. Crear una aplicación web en ASP.net

En este blog enseñare como crear desde cero una aplicación web en ASP.net en la versión 4.5. El objetivo es mostrar una arquitectura práctica y sencilla para páginas webs que te servirá para crear tu propio proyecto. La arquitectura te ayudará en la creación de proyectos pequeños y proyectos grandes.


No voy a limitarme en explicar cómo crear una arquitectura en la teoría con gráficos bonitos como lo encontraras en muchos sitios, sino lo que quiero hacer es mostrar a base de mi experiencia y sobre un proyecto de ejemplo paso a paso como realizar el proyecto de principio a fin y dar algunos consejos que puedes utilizar en la práctica. Aunque es un proyecto ficticio, vas a tener una buena impresión como se realiza realmente un proyecto profesional en la práctica. La arquitectura web que he diseñado no es muy complicada y por eso es apropiada para proyectos pequeños. También se puede aplicar para proyectos muy grandes. Como podrás comprobar la arquitectura nos permite dejar crecer el proyecto con el tiempo con los posibles cambios de requisitos que pueden surgir. 

La arquitectura dividirá la aplicación por capas. Con la separación de las diferentes capas conseguimos separar la lógica de negocios de la lógica de diseño y de la capa de datos. La aplicación web representará la capa de presentación al usuario.