Transact-SQL (T-SQL) es
el lenguaje principal utilizado para gestionar y manipular datos en Microsoft
SQL Server. Este post describe las raíces de este lenguaje, la terminología y la
mentalidad que necesita adoptar cuando escribe código T-SQL.
Entendiendo los Fundamentos
de T-SQL
Muchos
aspectos de computación, como los lenguajes de programación, evolucionan basados
en la intuición y la tendencia actual. Sin bases sólidas, su vida útil podría
ser muy corta, y si sobreviven, a menudo los cambios son muy rápidos, debido a
los cambios en las tendencias. T-SQL es diferente, principalmente porque tiene sólidos
fundamentos, matemáticos. No necesita ser un matemático para escribir buen código
SQL, pero siempre y cuando entienda cuales son los fundamentos, y algunos de
sus principios claves, entenderá mejor de lo que trata el lenguaje. Sin estos
fundamentos, todavía se puede escribir código T-SQL, incluso código que se
ejecute exitosamente, pero sería como tomar la sopa con un tenedor!
Evolución de T-SQL
Como se ha mencionado, a
diferencia de muchos otros aspectos de la computación, el T-SQL está basado en
sólidos fundamentos matemáticos. Comprender algunos de los principios claves de
estos fundamentos, puede ayudar a entender mejor el lenguaje con el que está
tratando. Entonces pensará en términos de T-SQL al codificar en T-SQL; en lugar
de codificar con T-SQL, mientras piensa en términos de procedimientos.
La Figura siguiente
ilustra la evolución de T-SQL de sus fundamentos matemáticos principales.
T-SQL es el lenguaje principal utilizado para gestionar y
manipular datos en el Sistema de Gestión de Base de Datos Relacional (RDBMS)
principal, de SQL Server; ya sea en las instalaciones o en la nube (Microsoft Windows
Azure SQL Database). SQL Server también soporta otros lenguajes, como Microsoft
Visual C# y Microsoft Visual Basic, pero T-SQL es usualmente el lenguaje
preferido para la gestión y la manipulación de datos.
T-SQL es un dialecto del
SQL estándar. SQL es un estándar tanto de la Organización Internacional de Estandarización
(ISO) y del Instituto de Estándares Nacionales Americano (ANSI). Los dos estándares
para SQL son básicamente lo mismo. El estándar SQL sigue evolucionando con el
tiempo. A continuación se presenta una lista de las principales revisiones del
estándar hasta el momento:
·
SQL-86
·
SQL-89
·
SQL-92
·
SQL:1999
·
SQL:2003
·
SQL:2006
·
SQL:2008
·
SQL:2011
Todos los vendors líderes
de bases de datos, incluyendo Microsoft, implementan un dialecto de SQL como el
principal lenguaje para gestionar y manipular datos en sus plataformas de bases
de datos. Por lo tanto, los elementos de lenguaje principales son similares.
Sin embargo, cada vendor decide qué característica implementar y cual no.
Además, el estándar algunas veces deja algunos aspectos, como una opción de implementación.
Usualmente cada vendor también implementa extensiones al estándar, en los casos
en donde el vendor sienta que una característica importante no está cubierta
por el estándar.
Escribir en una forma
estándar es considerada una buena práctica. Cuando así lo hace, el código es
más portable. Su conocimiento es más portable, también, porque le resulta más fácil
comenzar a trabajar con nuevas plataformas. Cuando el dialecto que está
trabajando, soporta tanto una forma estándar y no estándar de hacer algo,
siempre debe preferir la forma estándar, como su elección predeterminada. Debe
considerar una opción no estándar sólo cuando obtiene beneficios importantes, y
que no están previstos por la alternativa estándar.
Como un ejemplo de
cuándo debe elegir la forma estándar, T-SQL soporta dos operadores "no es
igual a": <> y =!. El primero es estándar y el último no lo es. Este
caso es pan comido: ¡elige el estándar!
Como un ejemplo de
cuando la elección del estándar o del no estándar dependen de las
circunstancias, considere lo siguiente: T-SQL soporta varias funciones que
convierten un valor de origen a un tipo de destino. Entre ellos se encuentran
las funciones CAST y CONVERT. El primero es estándar y el último no lo es. La
función CONVERT no estándar tiene un argumento de estilo que CAST no soporta.
Debido a que CAST es estándar, debería considerarlo como su elección por
defecto, para conversiones. Debería considerar el uso de CONVERT sólo cuando
necesita confiar en el argumento de estilo.
Otro ejemplo de la
elección de la forma estándar, está en la terminación de las sentencias T-SQL.
De acuerdo al SQL estándar, debe terminar sus sentencias con un punto y coma.
Actualmente en T-SQL no es un requisito para todas las sentencias, sólo en los
casos donde de otro modo, se presenta ambigüedad de elementos de código, tales
como en la cláusula WITH de una Expresión de Tabla Común (CTE). Aún debería
seguir el estándar y terminar todas sus sentencias, incluso cuando en la
actualidad no es requerida.
El SQL estándar está
basado en el modelo relacional, el
cual es un modelo matemático para la gestión y la manipulación de datos. El
modelo relacional fue inicialmente creado y propuesto por Edgar F. Codd en
1969. Desde entonces, ha sido explicado y desarrollado por Chris Date, Hugh Darwen,
y otros.
Un concepto erróneo común
es que el nombre "relacional" tiene que ver con las relaciones entre
las tablas (es decir, las llaves foráneas). Actualmente, el origen verdadero para
el nombre del modelo es el concepto matemático de relación.
Una relación en el
modelo relacional es lo que SQL llama una tabla.
Los dos no son sinónimos. Se podría decir que una tabla es un intento por parte
de SQL para representar una relación (en adición a una variable de relación,
pero no necesariamente obtiene eso aquí). Algunos podrían decir que no es un intento
muy exitoso. Aunque el SQL está basado en el modelo relacional, se desvía de este,
en muchas formas. Pero es importante notar que así como entienda los principios
del modelo, podrá utilizar SQL, o más precisamente, el dialecto que esté
utilizando, en una forma relacional.
Regresando a una
relación, el cual es lo que SQL intenta representar con una tabla: una relación
tiene una cabecera y un cuerpo. La cabecera es un conjunto de atributos (que
SQL intenta representar con columnas), cada uno de un tipo dado. Un atributo es
identificado por el nombre y el tipo del nombre. El cuerpo es un conjunto de
tuplas (qué SQL intenta representar con filas). Cada cabecera de tupla es la
cabecera de la relación. Cada valor de cada atributo de tupla, es de su tipo
respectivo.
Algunos de los
principios más importantes a entender acerca de T-SQL, parte de los fundamentos
principales del modelo relacional, la teoría de conjuntos y la lógica de
predicado.
Recuerde que la cabecera
de una relación es un conjunto de atributos, y el cuerpo un conjunto de tuplas.
Por tanto, ¿Qué es un conjunto? De acuerdo con el creador de la teoría
matemática de conjuntos, Georg Cantor, un conjunto
es descrito de la siguiente manera:
Por un "conjunto" nos
referimos a cualquier colección M en un todo definido, de objetos distintos m
(que son llamados los "elementos" de M) de nuestra percepción o de
nuestro pensamiento.
—George
Cantor, en “Georg Cantor” por Joseph W. Dauben
(Princeton University Press, 1990)
Hay un número de
principios muy importantes en esta definición que, si lo entendió, debería
tener una repercusión directa en sus prácticas de codificación de T-SQL. Por un
lado, note el término todo. Un
conjunto debe ser considerado como un todo. Esto significa que no interactúa
con los elementos individuales del conjunto, sino con el conjunto como un todo.
Note el término distinto, un conjunto no tiene
duplicados. Codd comentó una vez sobre los aspectos de no duplicados: "Si
algo es cierto, entonces decirlo dos veces no lo hará más cierto". Por
ejemplo, el conjunto {a, b, c} es considerado igual al conjunto {a, a, b, c,
c, c}.
Otro aspecto crítico de
un conjunto no aparece explícitamente en la definición antes mencionada por
Cantor, sino más bien está implícito, es que no hay relevancia en el orden de
los elementos de un conjunto. Por el contrario, una secuencia (que es un
conjunto ordenado), por ejemplo,
tiene un orden de sus elementos. Combinando los aspectos de no duplicado y de
no relevancia del orden, significa que el conjunto {a, b, c} es igual al
conjunto {b, a ,c ,c ,a, c} .
La otra rama de las
matemáticas del que está basado el modelo relacional, es llamada la lógica de
predicado. Un predicado es una
expresión que cuando se le atribuye a algún objeto, hace que una preposición
sea Verdadera o Falsa. Por ejemplo, "salario mayor a S/. 5,000" es un
predicado. Puede evaluar este predicado para un empleado específico, en cuyo
caso se tiene una preposición. Por ejemplo, suponga que para un empleado en
particular, su salario es de S/. 6,000. Cuando evalúa la preposición para ese
empleado, se obtiene una preposición Verdadera. En otras palabras, un predicado
es una preposición parametrizada.
El modelo relacional
utiliza predicados como uno de sus elementos centrales. Puede forzar la
integridad de datos por utilizar predicados. Puede filtrar los datos por
utilizar predicados. Puede incluso utilizar los predicados para definir el
modelo de datos. En primer lugar, identifica las preposiciones que necesita que
sean almacenadas en la base de datos. He aquí una preposición de ejemplo: un pedido
con IDPedido de 10248, fue colocado el 12 de febrero del 2012, por el cliente
con IDCliente de 7, y manejado por el empleado con IDEmpleado de 3. Entonces,
crea predicados de las preposiciones para eliminación de datos y mantenimiento
de la cabecera. Recuerde, la cabecera es un conjunto de atributos, cada uno
identificado por el nombre y el nombre del tipo.
Usando T-SQL en una Manera Relacional
Como se mencionó, T-SQL está
basada en SQL, que a su vez es basada en el modelo relacional. Sin embargo, hay
un número de maneras en la cual SQL; y por lo tanto, T-SQL, se desvía del
modelo relacional. Pero el lenguaje le da las herramientas suficientes para
que, si comprende el modelo relacional, pueda utilizar el lenguaje de una manera
relacional, y por lo tanto escribir código más eficiente.
Recuerde que una
relación tiene una cabecera y un cuerpo. La cabecera es un conjunto de
atributos y el cuerpo es un conjunto de tuplas. Recuerde de la definición de
conjunto, que un conjunto es supuestamente considerado como un todo. Lo que
traducido a T-SQL, es que supuestamente escribe consultas que interactúan con
las tablas como un todo. Debe tratar de evitar usar construcciones iterativas como
cursores y bucles que iteran a través de las filas de una en una. También debería
tratar de evitar pensar en términos iterativos, porque este tipo de pensamiento
es lo que conduce a las soluciones iterativas.
Para las personas con antecedentes
de programación por procedimientos, la forma natural de interactuar con los datos
(en un archivo, recordset, o datareader) es con iteraciones. Así que usar los
cursores y otras construcciones iterativas en T-SQL es, en cierto modo, una
extensión de lo que ya conocen. Sin embargo, la forma correcta desde la
perspectiva del modelo relacional, es no interactuar con las filas de una en
una; más bien, utilizar las operaciones relacionales y retornar un resultado
relacional. Esto, en T-SQL, se traduce a escribir consultas.
Recuerde también que un
conjunto no tiene duplicados. En T-SQL no siempre se impone esta regla. Por
ejemplo, puede crear una tabla sin una llave. En tal caso, se le ha permitido
tener filas duplicadas en la tabla. Para seguir la teoría relacional, necesita imponer
la unicidad en sus tablas; por ejemplo, por utilizar una llave primaria o una
restricción unique.
Aun cuando la tabla no
permite las filas duplicadas, una consulta sobre la tabla puede aún retornar filas
duplicadas en su resultado, aquí hay un ejemplo para fines de ilustración. Examine
la siguiente consulta.
USE TSQL2012;
SELECT
country
FROM HR.Employees;
La consulta es aplicada sobre
la base de datos de ejemplo TSQL2012 (http://1drv.ms/1KoMdxI). Retorna el atributo country de los
empleados almacenado en la tabla HR.Employees. De acuerdo al modelo relacional,
una operación relacional sobre una relación supuestamente retornará una
relación. En este caso, esto debería traducirse para retornar el conjunto de
países donde hay empleados, con énfasis en conjuntos, como en no duplicados.
Sin embargo, T-SQL no intenta eliminar los duplicados por defecto.
Aquí está la salida de
esta consulta.
Country
---------------
USA
USA
USA
USA
UK
UK
UK
USA
UK
De hecho, T-SQL es basado
más en la teoría de multiconjuntos que en la teoría de conjuntos. Un multiconjunto (también conocido como un
bag o un superconjunto) en muchos aspectos es similar a un conjunto, pero puede
tener duplicados. Como se ha mencionado,
el lenguaje T-SQL le da las herramientas suficientes para que si quiere
seguir la teoría relacional, puede hacerlo. Por ejemplo, el lenguaje le
proporciona una cláusula DISTINCT para eliminar los duplicados. Aquí está la
consulta revisada.
SELECT DISTINCT country
FROM HR.Employees;
Aquí está la salida de la consulta revisada.
Country
---------------
UK
USA
Otro
aspecto fundamental de un conjunto, es que no tiene relevancia el orden de los
elementos. Por esta razón, las filas en una tabla no tienen algún orden en
particular, conceptualmente. Así que cuando emite una consulta sobre una tabla
y no indica explícitamente en qué orden de presentación en particular, quiere
retornar las filas, el resultado se supone que sea relacional. Por lo tanto, no
debe asumir algún orden específico para las filas en el resultado, sin importar
lo que sabe acerca de la representación física de los datos, por ejemplo,
cuando los datos son indexados.
Como ejemplo, considere la siguiente consulta.
SELECT
empid, lastname
FROM
HR.Employees;
Cuando esta consulta fue ejecutada en un sistema, retorna
la siguiente salida, que luce como si fuera ordenada por la columna lastname.
empid lastname
------ -------------
5 Buck
8 Cameron
1 Davis
9 Dolgopyatova
2 Funk
7 King
3
Lew
4
Peled
6
Suurs
Incluso si las filas fueran retornadas
en un orden diferente, el resultado aún tendría que ser considerado correcto.
SQL Server puede elegir entre diferentes métodos de acceso físico para procesar
la consulta, conociendo que no necesita garantizar el orden en el resultado.
Por ejemplo, SQL Server podría decidir paralelizar la consulta o explorar los
datos en el orden de archivo (en lugar del orden de índice).
Si necesita garantizar un orden de presentación específico
a las filas en el resultado, necesita agregar una cláusula ORDER BY a la
consulta, de la siguiente manera.
SELECT
empid, lastname
FROM
HR.Employees
ORDER BY empid;
Esta vez, el resultado no es relacional, es lo que el SQL
estándar llama un cursor. El orden de
la filas en la salida está garantizada, basada en el atributo empid. Aquí está
la salida de esta consulta.
empid
lastname
------
-------------
1
Davis
2
Funk
3 Lew
4 Peled
5 Buck
6 Suurs
7 King
8 Cameron
9
Dolgopyatova
La cabecera de una relación es un conjunto de atributos,
que se supone debe ser identificado por el nombre y el tipo del nombre. No hay un
orden a los atributos. A la inversa, T-SQL mantiene un seguimiento de las posiciones
ordinales de las columnas basadas en su orden de aparición en la definición de
la tabla. Cuándo emite una consulta con SELECT *, está garantizando obtener las
columnas en el resultado basados en el orden de definición. Además, T-SQL
permite referirse a las posiciones ordinales de columnas del resultado en la
cláusula ORDER BY, de la siguiente manera.
SELECT
empid, lastname
FROM
HR.Employees
ORDER BY 1;
Más allá del hecho de que esta práctica no es relacional,
piense en la posibilidad de error, si en algún momento cambia la lista SELECT y
olvida cambiar la lista ORDER BY consecuentemente. Por lo tanto, la
recomendación es siempre indicar el nombre de los atributos que necesita
ordenar.
T-SQL tiene otra
desviación del modelo relacional, en que permite definir los resultados de columnas
basadas en una expresión sin asignar un nombre a la columna de destino. Por
ejemplo, la siguiente consulta es válida en T-SQL.
SELECT
empid, firstname +
' ' + lastname
FROM HR.Employees;
Esta consulta genera la siguiente salida.
empid
------ ------------------
1 Sara Davis
2 Don Funk
3 Judy Lew
4 Yael Peled
5 Sven Buck
6 Paul Suurs
7 Russell King
8
Maria Cameron
9
Zoya Dolgopyatova
Pero de acuerdo al modelo relacional, todos los atributos
deben tener nombres. Para que la consulta sea relacional, necesita asignar un
alias al atributo de destino. Puede hacerlo utilizando la cláusula AS, de la
siguiente manera.
SELECT
empid, firstname +
' ' + lastname AS fullname
FROM HR.Employees;
Además, T-SQL permite que una consulta retorne varias columnas
de resultado con el mismo nombre. Por ejemplo, considere una unión entre dos
tablas, T1 y T2, ambas con una columna llamada keycol. T-SQL permite una lista
SELECT parecida a la siguiente.
SELECT
T1.keycol, T2.keycol ...
Para que el resultado sea relacional, todos los atributos
deben tener nombres únicos, por lo que podría necesitar utilizar diferentes
alias para los atributos de resultado, así como el siguiente.
SELECT
T1.keycol AS
clave1, T2.keycol
AS clave2 ...
En cuanto a los predicados, siguiendo la ley del medio excluido en la lógica
matemática, un predicado puede evaluarse como Verdadero o Falso. En otras
palabras, los predicados se supone que utilizan la lógica de dos valores. Sin
embargo, Codd ha querido reflejar la posibilidad de valores que faltan en su
modelo. El hace referencia a dos tipos de valores faltantes: faltantes, pero
aplicables y faltantes, pero inaplicables. Tome el atributo teléfono móvil de
un empleado como ejemplo. Un valor faltante pero aplicable sería si un empleado
tiene un teléfono móvil, pero no ha querido facilitar esta información, por
ejemplo, por razones de privacidad. Un valor faltante, pero inaplicable, podría
ser cuando el empleado simplemente no tiene un teléfono móvil. Según Codd, un
lenguaje basado en su modelo debe proporcionar dos marcas diferentes para los
dos casos. T-SQL, de nuevo, basado en el estándar SQL, implementa solo una
marca de propósito general llamada NULL para cualquier tipo de valor faltante.
Esto conduce a la lógica de predicados de tres valores. Es decir, cuando un
predicado compara dos valores, por ejemplo, el mobilephone = '(425) 555-0136',
si ambos están presentes, el resultado se evalúa como Verdadero o Falso. Pero
si uno de ellos es NULL, el resultado se evalúa como un tercer valor lógico, Desconocido.
Note
que algunos creen que un modelo relacional válido debería seguir la lógica de
dos valores, y oponerse fuertemente al concepto de NULLs en SQL. Pero como se
mencionó, el creador del modelo relacional creía en la idea de soportar los
valores faltantes, y los predicados que se extienden más allá de la lógica de
dos valores. Lo que es importante desde la perspectiva de la codificación con
T-SQL es entender que si la base de datos que está consultando soporta NULLs,
su tratamiento está lejos de ser trivial. Es decir, necesita entender
cuidadosamente lo que sucede cuando están involucrados NULLs en los datos, que
está manipulando con diversas construcciones de consulta, como filtrado,
clasificación, agrupación, uniones, o intersecciones. Por lo tanto, con cada
pedazo de código que escribe con T-SQL, debe preguntarse si los NULLs son
posibles en los datos con los que está interactuando. Si la respuesta es sí, querrá
asegurarse de que entiende el tratamiento de NULLs en su consulta, y garantizar
que sus pruebas abordan el tratamiento de NULLs específicamente.
Usando la Terminología Correcta
El uso de la terminología
refleja su conocimiento. Por lo tanto, debe hacer un esfuerzo para comprender y
utilizar la terminología correcta. Cuando se habla de temas relacionados con
T-SQL, la gente a menudo usa términos incorrectos. Y si eso no es suficiente,
incluso cuando se dan cuenta de cuáles son los términos correctos, también
necesitan entender las diferencias entre los términos en T-SQL y en el modelo
relacional.
Como un ejemplo de
términos incorrectos en T-SQL, la gente frecuentemente usa los términos
"campo" y "registro" para referirse a lo que T-SQL llama
"columna" y "fila", respectivamente. Los campos y los
registros son físicos. Los campos son lo que tiene en las interfaces de usuario
en aplicaciones cliente, y los registros son lo que tiene en los archivos y
cursores. Las tablas son lógicas, y tienen filas y columnas lógicas.
Otro ejemplo de un
término incorrecto se refiere a "los valores NULL". Un NULL es una
marca para un valor faltante, no es un valor en sí. Por lo tanto, el uso
correcto del término es "marca NULL" o simplemente "NULL".
Además
de utilizar la terminología T-SQL correcta, también es importante comprender
las diferencias entre los términos de T-SQL y de su contraparte relacional.
Recuerde de la sección anterior que T-SQL intenta representar una relación con
una tabla, una tupla con una fila, y un atributo con una columna; pero los
conceptos de T-SQL y su contraparte relacional difieren en varias maneras.
Siempre y cuando sea consciente de esas diferencias, puede, y debe, esforzarse
por utilizar T-SQL de una manera relacional.
Ejercicio 1: Identificar Elementos No Relacionales en una Consulta
En este ejercicio, se le
da una consulta. Su tarea es identificar los elementos no relacionales en la
consulta.
1. Abra el SQL Server Management Studio
(SSMS) y conéctese a la base de datos de ejemplo TSQL2012.
2. Escriba la consulta siguiente en la
ventana de consulta y ejecútela.
SELECT custid, YEAR(orderdate)
FROM Sales.Orders
ORDER BY
1, 2;
Se obtiene el resultado siguiente, que
se muestra en forma abreviada.
custid
-----------
-----------
1 2007
1 2007
1 2007
1 2008
1 2008
1 2008
2 2006
2 2007
2 2007
2 2008
...
3.
Revise
el código y su salida. La consulta se supone retorna para cada cliente y año de
pedido, el ID Cliente (custid) y el año de pedido (YEAR(orderdate)). Note que
no hay un requerimiento de orden de presentación de la consulta. ¿Puede
identificar qué aspectos son no relacionales en la consulta?
Respuesta: La consulta no tiene ALIAS en
la expresión YEAR(orderdate), así que no hay un nombre para el atributo de
resultado. La consulta puede retornar duplicados. La consulta obliga a cierto orden
de presentación al resultado y utiliza posiciones ordinales en la cláusula
ORDER BY.
Ejercicio 2: Convertir la Consulta No Relacional a Relacional
En este ejercicio,
trabajará con la consulta proporcionada en el ejercicio 1, como su punto de
partida. Después identificará los elementos no relacionales en la consulta,
necesita aplicar las revisiones apropiadas para que sea relacional.
·
En
el paso 3 del ejercicio 1, ha identificado elementos no relacionales en la
última consulta. Aplicar revisiones a la consulta para hacerla relacional.
Se requiere un número de revisiones
para hacer la consulta relacional.
·
Defina
un nombre de atributo por asignar un alias a la expresión YEAR(orderdate).
·
Agregue
una cláusula DISTINCT para eliminar duplicados.
·
También,
eliminar la cláusula ORDER BY para retornar un resultado relacional.
·
Incluso
si hubiera un requerimiento de ordenamiento de presentación (no en este caso),
no debería utilizar las posiciones ordinales; en cambio, use nombres de
atributos. El código debería ser similar al siguiente.
SELECT DISTINCT custid, YEAR(orderdate) AS añopedido
FROM
Sales.Orders;
Este post nos muestra los fundamentos del lenguaje Transact-SQL, en su parte 1.
ResponderBorrar