Common Table Expressions CTE

Common Table Expressions – CTE

Una expresión de tabla común (CTE) es un conjunto de resultados temporal definido en la ejecución de una instrucción SELECT, INSERT, UPDATE,  DELETE o CREATE VIEW. Es como asignar un nombre a una consulta pero sin almacenarla en la base de datos como el caso de las vistas. (Ver Vistas)

Una CTE es similar a una tabla derivada en que no se almacena como un objeto y dura sólo el tiempo que dura la consulta. A diferencia de una tabla derivada, una CTE puede hacer referencia a sí misma y se puede hacer referencia a ella varias veces en la misma consulta.

Una CTE se puede usar para:

  • Crear una consulta recursiva.
  • Sustituir la creación de una vista cuando el uso de una vista no sea necesario; es decir, cuando no se tenga que almacenar la definición de la vista en la base de datos.
  • Hacer referencia a la tabla resultante varias veces en la misma instrucción.
  • Las CTE tiene ventajas de legibilidad mejorada y facilidad de mantenimiento de consultas complejas.
  • Las CTE se pueden definir en rutinas definidas por el usuario, como funciones, procedimientos almacenados, desencadenadores o vistas.

Estructura de una CTE

Las CTE tienen un nombre de expresión que representa la CTE, una lista de columnas opcional y una consulta que define la CTE.
Después de definir una CTE, se puede hacer referencia a ella como una tabla o vista en una instrucción SELECT, INSERT, UPDATE o DELETE.

La estructura de las CTE es:

WITH NombreCTE [ ( NombreColumna [,…n] ) ]
AS
( Consulta compleja )
Select <column_list> FROM NombreCTE

 

Ejercicios

Usando Northwind
use Northwind
go

Ejercicio 01

Mostrar los productos, su categoría y su proveedor. Mostrar los que no están descontinuados ordenados por precio descendentemente. Para entender las relaciones entre las tablas Ver Joins en SQL

— La consulta sin CTE es como sigue

select P.ProductID, P.ProductName, P.UnitPrice, P.UnitsInStock,
C.CategoryName, S.CompanyName
from Products As P
join Categories As C on P.CategoryID = C.CategoryID
join Suppliers As S on P.SupplierID = S.SupplierID
where P.Discontinued = 0
order by P.UnitPrice desc
go




— Usando CTE

with ListaProductos (Codigo, Descripción, Precio, Stock, Categoría, Proveedor) As
(select P.ProductID, P.ProductName, P.UnitPrice, P.UnitsInStock,
C.CategoryName, S.CompanyName
from Products As P
join Categories As C on P.CategoryID = C.CategoryID
join Suppliers As S on P.SupplierID = S.SupplierID
where P.Discontinued = 0 )
Select * from ListaProductos order by Precio
go

La imagen muestra el resultado

— En la orden anterior se pueden presentar solamente algunos campos

with ListaProductos (Codigo, Descripción, Precio, Stock, Categoría, Proveedor) As
(select P.ProductID, P.ProductName, P.UnitPrice, P.UnitsInStock,
C.CategoryName, S.CompanyName
from Products As P
join Categories As C on P.CategoryID = C.CategoryID
join Suppliers As S on P.SupplierID = S.SupplierID
where P.Discontinued = 0 )
Select Codigo, Descripción, Categoría from ListaProductos order by Precio
go

La imagen muestra únicamente el Codigo, la Descripción y la Categoría.

 

Ejercicio 02

Mostrar los empleados y las órdenes generadas.

Es conveniente que la consulta tenga sus alias correctos. Ver Alias

La consulta sin CTE

select E.EmployeeID As ‘Codigo’, E.LastName As ‘Apellido’ , E.FirstName As ‘Nombre’,
O.OrderID As ‘Nº Orden’, Format(O.OrderDate,’dd/MMM/yyyy’) As ‘Fecha’
from Employees As E
join Orders As O on E.EmployeeID = O.EmployeeID
go

— Asignando la CTE

with OrdenesEmpleados As
(select E.EmployeeID As ‘Codigo’, E.LastName As ‘Apellido’ ,
E.FirstName As ‘Nombre’, O.OrderID As ‘Nº Orden’,
Format(O.OrderDate,’dd/MMM/yyyy’) As ‘Fecha’
from Employees As E
join Orders As O on E.EmployeeID = O.EmployeeID)
select * from OrdenesEmpleados
go

— Usando la CTE con una consulta diferente, incluye el total de órdenes. Ver agrupamientos

with OrdenesEmpleados As
(select E.EmployeeID As ‘Codigo’, E.LastName As ‘Apellido’ ,
E.FirstName As ‘Nombre’, O.OrderID As ‘Nº Orden’,
Format(O.OrderDate,’dd/MMM/yyyy’) As ‘Fecha’
from Employees As E
join Orders As O on E.EmployeeID = O.EmployeeID)

select Codigo, Apellido, Nombre, COUNT([Nº Orden]) As ‘Total Órdenes’
from OrdenesEmpleados group by Codigo, Apellido, Nombre
go

 

Ejercicio 03

Mostrando los datos de una relación recursiva. En la tabla Empleados (Employees)  existe en campo ReportsTo que indica que un empleado debe reportar su trabajo al que se indica en ese campo.

— Visualizar los datos
select E.EmployeeID, E.FirstName, E.LastName, E.ReportsTo from Employees As E
go

En la imagen se puede mostrar que el empleado Nancy Davolio debe reportar al empleado
con código 2 que es Andrew Fuller.

— Para un listado de los empleados y sus jefes podemos usar la siguiente instrucción. 

with Jefe As
(select EmployeeID, LastName, FirstName from Employees)
Select J.EmployeeID As ‘Cód. Jefe’, [Empleado Jefe] = J.LastName + Space(1) + J.FirstName,
E.EmployeeID As ‘Cód. Empleado’, Subordinado = E.LastName + Space(1) + E.FirstName
from Jefe As J
join Employees As E on J.EmployeeID = E.ReportsTo
go