Hay pocas guías de formatos relacionadas a formatear SQL y estilos de código, pero no hay un estándar universalmente aceptado para SQL Server. En este artículo, sin embargo, seguiremos las guías implícitas de:
- MSDN
- Documentación de Libros en Pantalla de SQL Server 2012
- Y la base de datos Adventure Works 2012 SQL Server
Veremos cómo podemos implementar estos estándares vía ApexSQL Refactor.
ApexSQL Refactor es un complemento gratis para SQL Server Management Studio and Visual Studio add-in and SQL Server Management Studio y Visual Studio y un formateador wSQL con cerca de 200 opciones de formato.
Use el terminador de sentencias
Estándar: Documentación de Libros en Pantalla de SQL Server 2012.
SQL Server requiere el punto y coma sólo en casos particulares:
- Para terminar la sentencia previa a una cláusula WITH definiendo una Expresión de Tabla Común (CTE, por sus siglas en inglés)
- Para terminar la sentencia previa a una sentencia de servicio SEND o RECEIVE
- Para terminar la sentencia MERGE
Por ejemplo, no usar punto y coma para terminar la sentencia MERGE resultará en un error:
Msg 10713, Level 15, State 1, Line 17
La documentación de Libros en Pantalla de SQL Server 2012 indica que no terminar sentencias T-SQL con un punto y coma es una característica deprecada, y que no será soportada en una versión futura de SQL Server.
ApexSQL Refactor tiene una opción para estilos de código SQL, que añade el punto y coma al final de cada sentencia. Debajo del menú ApexSQL Refactor, en el diálogo Formatting options debajo de la pestaña General, seleccione la opción Always use statemente terminator:
Esta opción terminará todas las sentencias con un punto y coma. Por ejemplo, el siguiente código:
CREATE FUNCTION [dbo].[ufnGetDocumentStatusText](@Status [tinyint]) RETURNS [nvarchar](16) AS BEGIN DECLARE @ret [nvarchar](16); SET @ret = CASE @Status WHEN 1 THEN N'Pending approval' WHEN 2 THEN N'Approved' WHEN 3 THEN N'Obsolete' ELSE N'** Invalid **' END RETURN @ret END
Será formateado con la terminación de sentencias:
CREATE FUNCTION [dbo].[ufnGetDocumentStatusText]( @Status [tinyint]) RETURNS [nvarchar](16) AS BEGIN DECLARE @ret [nvarchar](16); SET @ret = CASE @Status WHEN 1 THEN N'Pending approval' WHEN 2 THEN N'Approved' WHEN 3 THEN N'Obsolete' ELSE N'** Invalid **' END; RETURN @ret; END;
Sangría
Estándar: Documentación de Libros en Pantalla de SQL Server 2012 y base de datos Adventure Works 2012.
Aquí usaremos 4 espacios para la sangría siguiendo la sangría de la base de datos Adventure Works 2012.
Hay tres clases estilos diferentes de sangría de código SQL en SSMS, y también se puede especificar cuántos espacios componen una sola sangría o tabulación.
En SSMS, debajo del menú Tools, haga clic en Options. En la lista desplegable Text Editor elija Transact-SQL y Tabs:
Cuando la opción None está seleccionada, no se aplica la sangría a la nueva línea cuando se presiona ENTER.
Cuando la opción Block está seleccionada, se aplica automáticamente la sangría a la nueva línea creada al presionar ENTER, en la misma distancia de la línea previa. La opción Smart no está disponible para T-SQL.
La opción Tab size establece la distancia en espacios entre las paradas de tabulación. La opción Indent size establece el tamaño en espacios de una sangría automática.
La opción Insert spaces aplica sangría insertando sólo caracteres de espacio. Si el tamaño de la sangría es establecido a 4, entonces cuatro caracteres de espacio son insertados cuando la tecla TAB es presionada o se hace clic en el botón Increase Indent en la barra de herramientas en la ventana principal de SSMS.
Cuando la opción Keep tabs es seleccionada, la operación de sangría inserta para cada carácter tabulador el número de espacios especificado en Tab size.
En ApexSQL Refactor hay muchas opciones de estilo de código SQL para sangría. Debajo la pestaña General podemos establecer la regla de sangría general, así como la sangría de paréntesis de apertura y cierre. Estableceremos la opción Indent using tabs igual a 4 espacios:
Combinaciones
Estándar: Base de datos Adventure Works 2012
Un operador JOIN opera en tablas de dos entradas. Hay tres tipos fundamentales de combinaciones (joins en inglés) – combinaciones cruzadas, combinaciones internas y combinaciones externas. Cada tipo aplica a diferentes conjuntos de fases.
Una COMBINACIÓN CRUZADA aplica sólo a una fase – el Producto Cartesiano. Un producto Cartesiano es una operación matemática que retorna un conjunto de productos desde conjuntos múltiples. Para los conjuntos A y B, el producto Cartesiano A x B es un conjunto de todos los pares ordenados (a, b) donde a ∈ A y b ∈ B. Eso es, cada fila de una entrada es emparejada con todas las filas de la otra. Una tabla puede ser creada tomando el producto Cartesiano de un conjunto de filas y un conjunto de columnas.
Una COMBINACIÓN INTERNA aplica dos fases lógicas de procesamiento de la consulta – un producto Cartesiano entre las tablas de dos entradas como en una combinación cruzada, y luego filtra las filas en base en el predicado especificado en la cláusula ON.
Una COMBINACIÓN EXTERNA aplica tres fases – las dos fases de procesamiento lógico que las combinaciones internas aplican (producto Cartesiano y el filtro ON) y una fase de Añadir Filas Externas. La tercera fase identifica las filas desde la tabla preservada que no encontraron coincidencias en la otra tabla basado en el predicado ON y añade esas filas a la tabla resultado producida por las dos primeras fases de la combinación, y usa marcas NULL para los atributos del lado no preservado de la combinación.
Para lograr formatear el estilo siguiendo la base de datos SQL Adventure Works 2012, debajo del menú ApexSQL Refactor, en el diálogo Formatting options debajo de la pestaña Joins elegiremos las siguientes opciones:
Esto formateará el siguiente código SQL:
FROM [BOM_cte] cte INNER JOIN [Production].[BillOfMaterials] b ON b.[ProductAssemblyID] = cte.[ComponentID] INNER JOIN [Production].[Product] p ON b.[ComponentID] = p.[ProductID]
En código SQL justo como está en la base de datos Adventure Works 2012:
FROM [BOM_cte] AS cte INNER JOIN [Production].[BillOfMaterials] AS b ON b.[ProductAssemblyID] = cte.[ComponentID] INNER JOIN [Production].[Product] AS p ON b.[ComponentID] = p.[ProductID]
ApexSQL Refactor también tiene una opción para formatear la cláusula FROM. En el diálogo Formatting options, debajo de la pestaña Data statements elija la opción Move FROM clause to new line y establezca Indent a 0 espacios:
Establecer esta opción ayudará adicionalmente a lograr formatear la base de datos Adventure Works 2012 y la siguiente declaración SQL:
CREATE PROCEDURE [dbo].[uspGetAddressInfo] @City nvarchar(30) AS BEGIN SELECT * FROM AdventureWorks2012.Person.Address WHERE City = @City END GO
Será formateada por el estándar de Adventure Works 2012:
CREATE PROCEDURE [dbo].[uspGetAddressInfo] @City nvarchar(30) AS BEGIN SELECT * FROM AdventureWorks2012.Person.Address WHERE City = @City; END;
Elegiremos el mismo formato para la cláusula WHERE y formatearemos las sentencias SELECT anidadas.
Las listas de columnas en la base de datos SQL Adventure Works 2012 están formateadas colocando una lista de columnas en una nueva línea, y poniendo una coma antes de los nombres de las columnas para facilitar la conexión del código. En el menú ApexSQL Refactor, bajo la pestaña Data statements también configuraremos las reglas de formato para la opción Column lists, la cual formateará la siguiente sentencia SQL:
CREATE VIEW [Purchasing].[vVendorWithContacts] AS SELECT v.[BusinessEntityID],v.[Name],ct.[Name] AS [ContactType] ,p.[Title] ,p.[FirstName] ,p.[MiddleName] ,p.[LastName] ,p.[Suffix] ,pp.[PhoneNumber],pnt.[Name] AS [PhoneNumberType] ,ea.[EmailAddress] ,p.[EmailPromotion]
De acuerdo con el estándar de la base de datos SQL Adventure Works 2012:
CREATE VIEW [Purchasing].[vVendorWithContacts] AS SELECT v.[BusinessEntityID] ,v.[Name] ,ct.[Name] AS [ContactType] ,p.[Title] ,p.[FirstName] ,p.[MiddleName] ,p.[LastName] ,p.[Suffix] ,pp.[PhoneNumber] ,pnt.[Name] AS [PhoneNumberType] ,ea.[EmailAddress] ,p.[EmailPromotion]
Alias
Estándar: Sitio MSDN y la base de datos Adventure Works 2012
La legibilidad de una sentencia SELECT puede ser mejorada dando a una tabla un alias. Un alias de tabla puede ser asignado con o sin la palabra reservada AS. En la sentencia FROM un alias puede ser usado para distinguir una tabla o una vista en una combinación a sí misma o una sub consulta y usualmente es un nombre de tabla acortado. Si el mismo nombre de columna existe en más de una tabla en una sentencia JOIN, SQL Server requiere que el nombre de la columna sea calificado por un nombre de tabla, un nombre de vista o alias. Si un alias es definido el nombre de la tabla no puede ser usado.
Por ejemplo, en el siguiente alias de código SQL para la fuente de la tabla de la StateProvince es sp:
CREATE VIEW [dbo].[vw_NewYork] AS SELECT p.LastName, p.FirstName, e.JobTitle, a.City, sp.StateProvinceCode FROM HumanResources.Employee e INNER JOIN Person.Person p ON p.BusinessEntityID = e.BusinessEntityID INNER JOIN Person.BusinessEntityAddress bea ON bea.BusinessEntityID = e.BusinessEntityID INNER JOIN Person.Address a ON a.AddressID = bea.AddressID INNER JOIN Person.StateProvince sp ON sp.StateProvinceID = a.StateProvinceID WHERE a.City = 'Seattle'
Si en lugar de un alias intentamos ejecutar el código SQL usando el nombre real de la tabla Person:
CREATE VIEW [dbo].[vw_Seattle] AS SELECT p.LastName, p.FirstName, e.JobTitle, a.City, sp.StateProvinceCode FROM HumanResources.Employee e INNER JOIN Person.Person p ON p.BusinessEntityID = e.BusinessEntityID INNER JOIN Person.BusinessEntityAddress bea ON bea.BusinessEntityID = e.BusinessEntityID INNER JOIN Person.Address a ON a.AddressID = bea.AddressID INNER JOIN Person.StateProvince sp ON Person.StateProvinceID = a.StateProvinceID WHERE a.City = 'Seattle'
La ejecución de la consulta SQL resultará en un error:
Msg 4104, Level 16, State 1, Procedure vw_Seattle, Line 12
The multi-part identifier «Person.StateProvinceID» could not be bound.
En ApexSQL Refactor, la opción Alias puede ser establecida bajo la pestaña Data statements:
Y la sentencia SQL:
CREATE VIEW [Purchasing].[vVendorWithContacts] SELECT v.[BusinessEntityID],v.[Name],ct.[Name] [ContactType] ,p.[Title] ,p.[FirstName] ,p.[MiddleName] ,p.[LastName] ,p.[Suffix] ,pp.[PhoneNumber],pnt.[Name] [PhoneNumberType] ,ea.[EmailAddress] ,p.[EmailPromotion]
Será formateada por el estándar Adventure Works 2012:
CREATE VIEW [Purchasing].[vVendorWithContacts] SELECT v.[BusinessEntityID] , v.[Name] , ct.[Name] AS [ContactType] , p.[Title] , p.[FirstName] , p.[MiddleName] , p.[LastName] , p.[Suffix] , pp.[PhoneNumber] , pnt.[Name] AS [PhoneNumberType] , ea.[EmailAddress] , p.[EmailPromotion]
Mayúsculas y minúsculas
Estándar: Sitio MSDN
De acuerdo a las convenciones de sintaxis MSDN Transact-SQL, las MAYÚSCULAS deberían ser usadas para palabras reservadas de SQL y funciones incorporadas. Los tipos deberían estar en minúsculas:
Dejaremos el formato de identificadores y variables como están, pero note que no es una buena práctica usar palabras reservadas como identificadores, y que la consistencia en el nombramiento de objetos SQL debería ser preservada usando ya sea Proper case o Camel case y siempre usando identificadores regulares, por ejemplo, ContactType en lugar de “Contact Type”.
Sentencias de esquemas
Estándar: Base de datos Adventure Works 2012
Siguiendo el estándar de formato de la base de datos SQL Adventure Works 2012 en la creación de procedimientos almacenados, bajo el menú ApexSQL Refactor, en el diálogo Formatting options bajo la pestaña Schema statements dé formato a la opción Parameters:
Usando esta opción lograremos el estilo de formato de la base de datos Adventure Works 2012 para parámetros de procedimientos almacenados desde este código SQL:
CREATE PROCEDURE [dbo].[uspGetWhereUsedProductID] @StartProductID [int], @CheckDate [datetime] AS BEGIN
A una sentencia SQL apropiadamente formateada:
CREATE PROCEDURE [dbo].[uspGetWhereUsedProductID] @StartProductID [int], @CheckDate [datetime] AS BEGIN
Expresiones
Estándar: Sitio MSDN y base de datos Adventure Works 2012
ApexSQL Refactor ofrece opciones de formato SQL para operaciones lógicas, de comparación y aritméticas.
Operadores lógicos – verifican la veracidad de una condición y retornan un tipo de dato Booleano con un valor de TRUE, FALSE o UNKNOWN.
Operadores aritméticos – usados para realizar operaciones matemáticas en múltiples expresiones y pueden ser usados con tipos de datos numéricos.
Operadores de comparación – verifican si dos expresiones son lo mismo y pueden ser usados con todas las expresiones excepto los tipos de datos text, ntext o image.
Bajo la pestaña Expressions en el diálogo Formatting options establezca la opción Logical operations en Show operations on multiple lines siguiendo el formato de la base de datos Adventure Works 2012:
Esta opción dará formato al código SQL:
FROM [Production].[BillOfMaterials] b INNER JOIN [Production].[Product] p ON b.[ProductAssemblyID] = p.[ProductID] WHERE b.[ComponentID] = @StartProductID AND @CheckDate >= b.[StartDate] AND @CheckDate <= ISNULL(b.[EndDate], @CheckDate) UNION ALL
De acuerdo al estándar de la base de datos Adventure Works 2012:
FROM [Production].[BillOfMaterials] b INNER JOIN [Production].[Product] p ON b.[ProductAssemblyID] = p.[ProductID] WHERE b.[ComponentID] = @StartProductID AND @CheckDate >= b.[StartDate] AND @CheckDate <= ISNULL(b.[EndDate], @CheckDate) UNION ALL
Control de flujo
Estándar: Sitio MSDN
Indicar que una sentencia cubre más que una línea usando la combinación BEGIN/END hace al código más fácil de leer porque eso indica claramente el inicio y el final de la sentencia. Generalmente, las sentencias BEGIN/END son usadas en bucles WHILE, pero también son usados en procedimientos almacenados y sentencias IF según el estándar MSDN.
Para reforzar el envolvimiento de procedimientos almacenados con la combinación de las sentencias BEGIN/END en el diálogo Formatting options, bajo la pestaña Flow control seleccione las opciones Always use BEGIN and END in the IF statements y Always use BEGIN and END in stored procedures:
De esta manera todos los procedimientos almacenados serán formateados con la sentencia BEGIN/END, y escribir la sentencia CREATE PROCEDURE:
CREATE PROCEDURE [dbo].[uspGetAddressInfo] @City nvarchar(30) AS SELECT * FROM AdventureWorks2012.Person.Address WHERE City = @City GO
Envolverá la sentencia con las sentencias BEGIN/END:
CREATE PROCEDURE [dbo].[uspGetAddressInfo] @City nvarchar(30) AS BEGIN SELECT * FROM AdventureWorks2012.Person.Address WHERE City = @City; END; GO
Esto redondeará las opciones de formato. Para probar las configuraciones de formato formatearemos el siguiente código:
FROM Purchasing.Vendor v INNER JOIN Person.BusinessEntityContact bec ON bec.BusinessEntityID = v.BusinessEntityID INNER JOIN Person.ContactType ct ON ct.ContactTypeID = bec.ContactTypeID INNER JOIN Person.Person p ON p.BusinessEntityID = bec.PersonID LEFT OUTER JOIN Person.EmailAddress ea ON ea.BusinessEntityID = p.BusinessEntityID LEFT OUTER JOIN Person.PersonPhone pp ON pp.BusinessEntityID = p.BusinessEntityID LEFT OUTER JOIN Person.PhoneNumberType pnt ON pnt.PhoneNumberTypeID = pp.PhoneNumberTypeID;
Nuestras configuraciones de formato nos darán el siguiente estilo de código:
FROM Purchasing.Vendor AS v INNER JOIN Person.BusinessEntityContact AS bec ON bec.BusinessEntityID = v.BusinessEntityID INNER JOIN Person.ContactType AS ct ON ct.ContactTypeID = bec.ContactTypeID INNER JOIN Person.Person AS p ON p.BusinessEntityID = bec.PersonID LEFT OUTER JOIN Person.EmailAddress AS ea ON ea.BusinessEntityID = p.BusinessEntityID LEFT OUTER JOIN Person.PersonPhone AS pp ON pp.BusinessEntityID = p.BusinessEntityID LEFT OUTER JOIN Person.PhoneNumberType AS pnt ON pnt.PhoneNumberTypeID = pp.PhoneNumberTypeID;
Para usar estas configuraciones simplemente extraiga el código XML descargado.
En el diálogo Formatting options de ApexSQL Refactor haga clic en el botón Import e importe la plantilla de estilo de código SQL a ApexSQL Refactor. En el menú desplegable Formatting template nombre la nueva plantilla y seleccione la opción Use as default:
Recursos útiles:
Books Online for SQL Server 2012 – Deprecated Database Engine Features in SQL Server 2012
Books Online for SQL Server 2012 – Manage code formatting
Traductor: Daniel Calbimonte
noviembre 14, 2015