Pablo Espada Bueno www.programadorautonomo.net www.esbupa.com
Habitualmente me dedico a impartir formación y a labores de desarrollo y consultoría en .NET Si desea que colabore con usted impartiéndoles una formación o desarrollando algún proyecto, puede contactarme: Web www.programadorautonomo.net www.esbupa.com Email [email_address] [email_address] Espero que les guste la presentación
Nuevos Tipos de Datos Nuevas Características en Indices La palabra reservada OUTPUT Common Table Expressions Operaciones PIVOT y UNPIVOT El operador APPLY Clausula OVER Función RANK Función DENSE_RANK Función ROW_NUMBER Función NTILE Gestión Estructurada de Excepciones
Creacíon de campos varchar,nvarchar o varbinary con tamaño máximo de hasta 2^31 Bytes El nuevo tipo “xml” permite almacenar documentos de hasta 2 GB CREATE TABLE mySchema.LargeTable (varcharCol varchar(max)) CREATE TABLE mySchema.XMLTable (idCol int, xmlCol xml)
La sentencia ALTER INDEX nos permitirá realizar un conjunto de operaciones básicas sobre índices Deshabilitar un índice. Para rehabilitarlo habrá que recompilarlo o eliminarlo Recompilar un índice Recompilar todos los índices de una tabla ALTER INDEX IX_CustDOB ON Sales.Customer DISABLE ALTER INDEX PK_CustId ON Sales.Customer REBUILD ALTER INDEX ALL ON Sales.Customer REBUILD
Reorganizar (defragmentar) un índice Cambiar cualquier valor establecido en la sentencia CREATE INDEX SQL Server 2005 permite crear índices no agrupados que incluyan campos que no sean clave ALTER INDEX PK_CustId ON Sales.Customer REORGANIZE CREATE NONCLUSTERED INDEX IX_CustomerPostalCode  ON Sales.Customer (PostalCode)  INCLUDE (AddressLine1, AddressLine2, City)
OUTPUT permite volcar los resultados de la ejecución de cualquier sentencia SQL en una variable de tipo “tabla” Esta palabra clave podrá utilizarse en cualquier sentencia DML excepto: INSERT que vayan a insertar datos en vistas Operaciones con tablas/vistas remotas Operaciones en vistas particionadas
Suponiendo una tabla Stock.ProductList con campos ProductID IDENTITY int ProductName nvarchar(100) Price money Veamos algunos ejemplos del uso de OUTPUT con sentencias INSERT, UPDATE y DELETE
DECLARE @InsertDetails TABLE ( ProductID int, InsertedBy sysname )  INSERT INTO Stock.ProductList  OUTPUT INSERTED.ProductID, suser_name() INTO @InsertDetails  VALUES ('Racing Bike', 412.99)  SELECT * FROM @InsertDetails  DECLARE @PriceChangeDetails TABLE ( ProductID int, OldPrice money, NewPrice money, UpdatedBy sysname )  UPDATE Stock.ProductList SET Price = 3.99  OUTPUT INSERTED.ProductID, DELETED.Price, INSERTED.Price, suser_name() INTO @PriceChangeDetails  WHERE ProductID = 1  SELECT * FROM @PriceChangeDetails  DECLARE @DeleteDetails TABLE ( ProductID int, DeletedBy sysname ) DELETE Stock.ProductList  OUTPUT DELETED.ProductID, suser_name() INTO @DeleteDetails  WHERE ProductID = 2  SELECT * FROM @DeleteDetails
Las CTE’s permiten crear consultas que trabajan con datos recursivos Consultas más entendibles Implementación de algoritmos recursivos WITH TopSales (SalesPersonID, NumSales)  AS  (  SELECT SalesPersonID, Count(*)  FROM Sales.SalesOrderHeader  GROUP BY SalesPersonId  )  --Select simple SELECT * FROM TopSales  WHERE SalesPersonID IS NOT NULL  ORDER BY NumSales DESC  --Ejemplo de Join SELECT ts.SalesPersonID, sp.SalesYTD, ts.NumSales  FROM Sales.SalesPerson sp INNER JOIN TopSales ts ON ts.SalesPersonID = sp.SalesPersonID  ORDER BY NumSales DESC
Las operaciones PIVOT y UNPIVOT están indicadas para la creación de consultas cuyo resultado debe ser una matriz Por cada línea de los resultados, tendremos un conjunto variable de columnas que nos mostrarán valores calculados con una función de agregado La operación PIVOT nos permite convertir los resultados de una consulta en columnas, mientras que UNPIVOT nos convierte las columnas en resultados
Ejemplo de PIVOT Creamos una tabla de Pedidos Añadimos los siguientes valores CREATE TABLE Sales.[Order]  (  Customer varchar(8),  Product varchar(5),  Quantity int  )  Customer Product Quantity Mike  Bike  3 Mike  Chain  2 Mike  Bike  5 Lisa  Bike  3 Lisa  Chain  3 Lisa  Chain  4
Vamos a realizar una operación de PIVOT sobre la tabla El resultado sería SELECT * FROM Sales.[Order]  PIVOT (SUM(Quantity) FOR Product IN ([Bike],[Chain])) AS PVT Customer Bike Chain Lisa  3 7 Mike  8 2 Lisa  3 7 Mike  8 2 Lisa  3 7 Mike  8 2
Si realizamos una operación UNPIVOT sobre la tabla Sales.PivotedOrder El resultado sería SELECT Customer, Product, Quantity FROM Sales.PivotedOrder UNPIVOT (Quantity FOR Product IN ([Bike],[Chain])) AS UnPVT  Customer Product Quantity Mike  Bike  8 Mike  Chain  2 Lisa  Bike  3 Lisa  Chain  7
Este operador permite aplicar una función que devuelva una tabla por cada fila de una tabla obtenida por JOIN Tenemos 2 tipos de operadores APPLY CROSS APPLY Sólo se incluirán filas del JOIN que produzcan un resultado en la llamada a la función que devuelve una tabla OUTER APPLY Se incluirán todas las filas del JOIN Normalmente lo que haremos será aplicar una función que tome como parámetros valores de la fila y nos devuelva una nueva tabla
Veamos un ejemplo de uso Crearemos una función que nos devuelva los 3 últimos pedidos de un cliente Utilizando CROSS APPLY obtendremos el nombre del cliente (y los detalles de los pedidos) sólo de los clientes que hayan realizado algún pedido CREATE FUNCTION Sales.MostRecentOrders(@CustID int) RETURNS TABLE AS  RETURN  SELECT TOP (3) SalesOrderID, OrderDate  FROM Sales.SalesOrderHeader  WHERE CustomerID = @CustID  ORDER BY OrderDate DESC SELECT Name Customer, MR.*  FROM Sales.Store  CROSS APPLY Sales.MostRecentOrders(CustomerID) AS MR
Utilizando OUTER APPLY obtendremos el nombre del cliente (y los detalles de los pedidos) de todos los clientes SELECT Name AS Customer, MR.*  FROM Sales.Store  OUTER APPLY Sales.MostRecentOrders(CustomerID) AS MR
SQL Server 2005 nos proporciona 4 nuevas funciones de ordenación/ranking: RANK, DENSE_RANK,NTILE y ROW_NUMBER Para todas ellas podremos aplicar la cláusula OVER para particionar y ordenar las filas de resultados La cláusula PARTITION BY determina el criterio de agrupación mientras que ORDER BY determina el criterio de ordenación OVER ( [ PARTITION BY < value_expression > , ... [ n ] ]  ORDER BY <column> [ ASC | DESC ] [, ...[ n ] ] )
La función RANK nos permite obtener el número de orden de cada fila, dentro de una determinada partición SELECT P.Name Product, P.ListPrice, PSC.Name Category, RANK() OVER(PARTITION BY PSC.Name ORDER BY P.ListPrice DESC) AS PriceRank FROM Production.Product P JOIN Production.ProductSubCategory PSC ON P.ProductSubCategoryID = PSC.ProductSubCategoryID
La función DENSE_RANK es similar a la de RANK, pero no deja “huecos” a la hora de elaborar el ranking SELECT P.Name Product, P.ListPrice, PSC.Name Category, DENSE_RANK() OVER(PARTITION BY PSC.Name ORDER BY P.ListPrice DESC) AS PriceRank FROM Production.Product P JOIN Production.ProductSubCategory PSC ON P.ProductSubCategoryID = PSC.ProductSubCategoryID
Esta función permite obtener el número de cada fila dentro de un conjunto de resultados SELECT ROW_NUMBER() OVER(PARTITION BY PC.Name ORDER BY ListPrice) AS Row, PC.Name Category, P.Name Product, P.ListPrice FROM Production.Product P JOIN Production.ProductSubCategory PSC ON P.ProductSubCategoryID = PSC.ProductSubCategoryID JOIN Production.ProductCategory PC ON PSC.ProductCategoryID = PC.ProductCategoryID
Esta función permite crear grupos de resultados numerados, a partir de las filas del conjunto de resultados SELECT NTILE(3) OVER(PARTITION BY PC.Name ORDER BY ListPrice) AS PriceBand, PC.Name Category, P.Name Product, P.ListPrice FROM Production.Product P JOIN Production.ProductSubCategory PSC ON P.ProductSubCategoryID = PSC.ProductSubCategoryID JOIN Production.ProductCategory PC ON PSC.ProductCategoryID = PC.ProductCategoryID
SQL Server 2005 incluye la posibilidad de realizar una gestión de excepciones de forma estructurada Esto simplifica muchísimo el desarrollo del código La gestión de las excepciones se realizará en bloques TRY-CATCH Dentro del bloque TRY incluiremos el código que potencialmente puede generar errores Dentro del bloque CATCH realizaremos la captura de los posibles errores y su tratamiento adecuado
Sintaxis: Elimina la necesidad de utilizar la variable global @@error Si vamos a utilizar esta gestión de excepciones, será necesario activar una opción que indica que los errores producidos en el TRY, automáticamente aborten la transacción actual: SET XACT_ABORT ON BEGIN TRY { sql_statement | statement_block } END TRY BEGIN CATCH TRAN_ABORT { sql_statement | statement_block } END CATCH
Para asegurarnos de que transacciones que hayan podido quedar en estado “fantasma” se cierren adecuadamente, debemos incluir en el bloque CATCH, una sentencia ROLLBACK TRANSACTION Si queremos consultar la variable @@error, debemos hacerlo en la primera línea del CATCH Si necesitamos levantar una excepción “de aplicación” lo haremos usando RAISERROR:WITH TRAN_ABORT
CREATE TABLE dbo.DataTable (ColA int PRIMARY KEY, ColB int) CREATE TABLE dbo.ErrorLog (ColA int, ColB int, error int, date datetime) GO CREATE PROCEDURE dbo.AddData @a int, @b int AS SET XACT_ABORT ON BEGIN TRY BEGIN TRAN INSERT INTO dbo.DataTable VALUES (@a, @b) COMMIT TRAN END TRY BEGIN CATCH TRAN_ABORT DECLARE @err int SET @err = @@error --trap the error number ROLLBACK TRAN INSERT INTO dbo.ErrorLog VALUES (@a, @b, @err, GETDATE()) END CATCH GO EXEC dbo.AddData 1, 1 EXEC dbo.AddData 2, 2 EXEC dbo.AddData 1, 3 --violates the primary key

Mejoras en T-SQL para SQL Server 2005

  • 1.
    Pablo Espada Buenowww.programadorautonomo.net www.esbupa.com
  • 2.
    Habitualmente me dedicoa impartir formación y a labores de desarrollo y consultoría en .NET Si desea que colabore con usted impartiéndoles una formación o desarrollando algún proyecto, puede contactarme: Web www.programadorautonomo.net www.esbupa.com Email [email_address] [email_address] Espero que les guste la presentación
  • 3.
    Nuevos Tipos deDatos Nuevas Características en Indices La palabra reservada OUTPUT Common Table Expressions Operaciones PIVOT y UNPIVOT El operador APPLY Clausula OVER Función RANK Función DENSE_RANK Función ROW_NUMBER Función NTILE Gestión Estructurada de Excepciones
  • 4.
    Creacíon de camposvarchar,nvarchar o varbinary con tamaño máximo de hasta 2^31 Bytes El nuevo tipo “xml” permite almacenar documentos de hasta 2 GB CREATE TABLE mySchema.LargeTable (varcharCol varchar(max)) CREATE TABLE mySchema.XMLTable (idCol int, xmlCol xml)
  • 5.
    La sentencia ALTERINDEX nos permitirá realizar un conjunto de operaciones básicas sobre índices Deshabilitar un índice. Para rehabilitarlo habrá que recompilarlo o eliminarlo Recompilar un índice Recompilar todos los índices de una tabla ALTER INDEX IX_CustDOB ON Sales.Customer DISABLE ALTER INDEX PK_CustId ON Sales.Customer REBUILD ALTER INDEX ALL ON Sales.Customer REBUILD
  • 6.
    Reorganizar (defragmentar) uníndice Cambiar cualquier valor establecido en la sentencia CREATE INDEX SQL Server 2005 permite crear índices no agrupados que incluyan campos que no sean clave ALTER INDEX PK_CustId ON Sales.Customer REORGANIZE CREATE NONCLUSTERED INDEX IX_CustomerPostalCode ON Sales.Customer (PostalCode) INCLUDE (AddressLine1, AddressLine2, City)
  • 7.
    OUTPUT permite volcarlos resultados de la ejecución de cualquier sentencia SQL en una variable de tipo “tabla” Esta palabra clave podrá utilizarse en cualquier sentencia DML excepto: INSERT que vayan a insertar datos en vistas Operaciones con tablas/vistas remotas Operaciones en vistas particionadas
  • 8.
    Suponiendo una tablaStock.ProductList con campos ProductID IDENTITY int ProductName nvarchar(100) Price money Veamos algunos ejemplos del uso de OUTPUT con sentencias INSERT, UPDATE y DELETE
  • 9.
    DECLARE @InsertDetails TABLE( ProductID int, InsertedBy sysname ) INSERT INTO Stock.ProductList OUTPUT INSERTED.ProductID, suser_name() INTO @InsertDetails VALUES ('Racing Bike', 412.99) SELECT * FROM @InsertDetails DECLARE @PriceChangeDetails TABLE ( ProductID int, OldPrice money, NewPrice money, UpdatedBy sysname ) UPDATE Stock.ProductList SET Price = 3.99 OUTPUT INSERTED.ProductID, DELETED.Price, INSERTED.Price, suser_name() INTO @PriceChangeDetails WHERE ProductID = 1 SELECT * FROM @PriceChangeDetails DECLARE @DeleteDetails TABLE ( ProductID int, DeletedBy sysname ) DELETE Stock.ProductList OUTPUT DELETED.ProductID, suser_name() INTO @DeleteDetails WHERE ProductID = 2 SELECT * FROM @DeleteDetails
  • 10.
    Las CTE’s permitencrear consultas que trabajan con datos recursivos Consultas más entendibles Implementación de algoritmos recursivos WITH TopSales (SalesPersonID, NumSales) AS ( SELECT SalesPersonID, Count(*) FROM Sales.SalesOrderHeader GROUP BY SalesPersonId ) --Select simple SELECT * FROM TopSales WHERE SalesPersonID IS NOT NULL ORDER BY NumSales DESC --Ejemplo de Join SELECT ts.SalesPersonID, sp.SalesYTD, ts.NumSales FROM Sales.SalesPerson sp INNER JOIN TopSales ts ON ts.SalesPersonID = sp.SalesPersonID ORDER BY NumSales DESC
  • 11.
    Las operaciones PIVOTy UNPIVOT están indicadas para la creación de consultas cuyo resultado debe ser una matriz Por cada línea de los resultados, tendremos un conjunto variable de columnas que nos mostrarán valores calculados con una función de agregado La operación PIVOT nos permite convertir los resultados de una consulta en columnas, mientras que UNPIVOT nos convierte las columnas en resultados
  • 12.
    Ejemplo de PIVOTCreamos una tabla de Pedidos Añadimos los siguientes valores CREATE TABLE Sales.[Order] ( Customer varchar(8), Product varchar(5), Quantity int ) Customer Product Quantity Mike Bike 3 Mike Chain 2 Mike Bike 5 Lisa Bike 3 Lisa Chain 3 Lisa Chain 4
  • 13.
    Vamos a realizaruna operación de PIVOT sobre la tabla El resultado sería SELECT * FROM Sales.[Order] PIVOT (SUM(Quantity) FOR Product IN ([Bike],[Chain])) AS PVT Customer Bike Chain Lisa 3 7 Mike 8 2 Lisa 3 7 Mike 8 2 Lisa 3 7 Mike 8 2
  • 14.
    Si realizamos unaoperación UNPIVOT sobre la tabla Sales.PivotedOrder El resultado sería SELECT Customer, Product, Quantity FROM Sales.PivotedOrder UNPIVOT (Quantity FOR Product IN ([Bike],[Chain])) AS UnPVT Customer Product Quantity Mike Bike 8 Mike Chain 2 Lisa Bike 3 Lisa Chain 7
  • 15.
    Este operador permiteaplicar una función que devuelva una tabla por cada fila de una tabla obtenida por JOIN Tenemos 2 tipos de operadores APPLY CROSS APPLY Sólo se incluirán filas del JOIN que produzcan un resultado en la llamada a la función que devuelve una tabla OUTER APPLY Se incluirán todas las filas del JOIN Normalmente lo que haremos será aplicar una función que tome como parámetros valores de la fila y nos devuelva una nueva tabla
  • 16.
    Veamos un ejemplode uso Crearemos una función que nos devuelva los 3 últimos pedidos de un cliente Utilizando CROSS APPLY obtendremos el nombre del cliente (y los detalles de los pedidos) sólo de los clientes que hayan realizado algún pedido CREATE FUNCTION Sales.MostRecentOrders(@CustID int) RETURNS TABLE AS RETURN SELECT TOP (3) SalesOrderID, OrderDate FROM Sales.SalesOrderHeader WHERE CustomerID = @CustID ORDER BY OrderDate DESC SELECT Name Customer, MR.* FROM Sales.Store CROSS APPLY Sales.MostRecentOrders(CustomerID) AS MR
  • 17.
    Utilizando OUTER APPLYobtendremos el nombre del cliente (y los detalles de los pedidos) de todos los clientes SELECT Name AS Customer, MR.* FROM Sales.Store OUTER APPLY Sales.MostRecentOrders(CustomerID) AS MR
  • 18.
    SQL Server 2005nos proporciona 4 nuevas funciones de ordenación/ranking: RANK, DENSE_RANK,NTILE y ROW_NUMBER Para todas ellas podremos aplicar la cláusula OVER para particionar y ordenar las filas de resultados La cláusula PARTITION BY determina el criterio de agrupación mientras que ORDER BY determina el criterio de ordenación OVER ( [ PARTITION BY < value_expression > , ... [ n ] ] ORDER BY <column> [ ASC | DESC ] [, ...[ n ] ] )
  • 19.
    La función RANKnos permite obtener el número de orden de cada fila, dentro de una determinada partición SELECT P.Name Product, P.ListPrice, PSC.Name Category, RANK() OVER(PARTITION BY PSC.Name ORDER BY P.ListPrice DESC) AS PriceRank FROM Production.Product P JOIN Production.ProductSubCategory PSC ON P.ProductSubCategoryID = PSC.ProductSubCategoryID
  • 20.
    La función DENSE_RANKes similar a la de RANK, pero no deja “huecos” a la hora de elaborar el ranking SELECT P.Name Product, P.ListPrice, PSC.Name Category, DENSE_RANK() OVER(PARTITION BY PSC.Name ORDER BY P.ListPrice DESC) AS PriceRank FROM Production.Product P JOIN Production.ProductSubCategory PSC ON P.ProductSubCategoryID = PSC.ProductSubCategoryID
  • 21.
    Esta función permiteobtener el número de cada fila dentro de un conjunto de resultados SELECT ROW_NUMBER() OVER(PARTITION BY PC.Name ORDER BY ListPrice) AS Row, PC.Name Category, P.Name Product, P.ListPrice FROM Production.Product P JOIN Production.ProductSubCategory PSC ON P.ProductSubCategoryID = PSC.ProductSubCategoryID JOIN Production.ProductCategory PC ON PSC.ProductCategoryID = PC.ProductCategoryID
  • 22.
    Esta función permitecrear grupos de resultados numerados, a partir de las filas del conjunto de resultados SELECT NTILE(3) OVER(PARTITION BY PC.Name ORDER BY ListPrice) AS PriceBand, PC.Name Category, P.Name Product, P.ListPrice FROM Production.Product P JOIN Production.ProductSubCategory PSC ON P.ProductSubCategoryID = PSC.ProductSubCategoryID JOIN Production.ProductCategory PC ON PSC.ProductCategoryID = PC.ProductCategoryID
  • 23.
    SQL Server 2005incluye la posibilidad de realizar una gestión de excepciones de forma estructurada Esto simplifica muchísimo el desarrollo del código La gestión de las excepciones se realizará en bloques TRY-CATCH Dentro del bloque TRY incluiremos el código que potencialmente puede generar errores Dentro del bloque CATCH realizaremos la captura de los posibles errores y su tratamiento adecuado
  • 24.
    Sintaxis: Elimina lanecesidad de utilizar la variable global @@error Si vamos a utilizar esta gestión de excepciones, será necesario activar una opción que indica que los errores producidos en el TRY, automáticamente aborten la transacción actual: SET XACT_ABORT ON BEGIN TRY { sql_statement | statement_block } END TRY BEGIN CATCH TRAN_ABORT { sql_statement | statement_block } END CATCH
  • 25.
    Para asegurarnos deque transacciones que hayan podido quedar en estado “fantasma” se cierren adecuadamente, debemos incluir en el bloque CATCH, una sentencia ROLLBACK TRANSACTION Si queremos consultar la variable @@error, debemos hacerlo en la primera línea del CATCH Si necesitamos levantar una excepción “de aplicación” lo haremos usando RAISERROR:WITH TRAN_ABORT
  • 26.
    CREATE TABLE dbo.DataTable(ColA int PRIMARY KEY, ColB int) CREATE TABLE dbo.ErrorLog (ColA int, ColB int, error int, date datetime) GO CREATE PROCEDURE dbo.AddData @a int, @b int AS SET XACT_ABORT ON BEGIN TRY BEGIN TRAN INSERT INTO dbo.DataTable VALUES (@a, @b) COMMIT TRAN END TRY BEGIN CATCH TRAN_ABORT DECLARE @err int SET @err = @@error --trap the error number ROLLBACK TRAN INSERT INTO dbo.ErrorLog VALUES (@a, @b, @err, GETDATE()) END CATCH GO EXEC dbo.AddData 1, 1 EXEC dbo.AddData 2, 2 EXEC dbo.AddData 1, 3 --violates the primary key