Insertar datos en Transact SQL Insercin individual de filas. Para realizar la insercin individual de filas SQL posee la instruccin INSERT INTO. La insercin individual de filas es la que ms comnmente utilizaremos. Su sintaxis es la siguiente: INSERT INTO <nombre_tabla> [(<campo1>[,<campo2>,...])] values (<valor1>,<valor2>,...); El siguiente ejemplo muestra la insercin de un registro en la tabla PRECIOS. INSERT INTO PRECIOS (PRECIO, FX_INICIO, FX_FIN, CO_PRODUCTO) VALUES (10, getdate(),getdate()+30, 1) Insercin mltiple de filas. Tambin es posible insertar en una tabla el resultado de una consulta SELECT. De este modo se insertarn tantas filas como haya devuelto la consulta SELECT. El siguiente ejemplo muestra la insercin multiple de filas. INSERT INTO PRECIOS (PRECIO, FX_INICIO, FX_FIN, CO_PRODUCTO) SELECT PRECIO_UNIDAD, getdate(), getdate() + 30, CO_PRODUCTO FROM DETALLE_PEDIDO UNDAC SBD I Ing. Williams A. Muoz Robles 2 Insercin de valores por defecto. Tambin podemos forzar a que la inserccin se realice con los datos por defecto establecidos para la tabla (o null si no tienen valores por defecto). INSERT INTO PRECIOS DEFAULT VALUES En SQL Sever podemos marcar un campo de una tabla como autonumrico (identity), cuando insertamos un registro en dicha tabla el valor del campo se genera automaticamente. Para recuperar el valor generado disponemos de varios mtodos: Utilizar la funcion @@identity, que devuelve el ltimo valor identidad insertado por la transaccion: DECLARE @Codigo int INSERT INTO PRECIOS (PRECIO, FX_INICIO, FX_FIN, CO_PRODUCTO) VALUES (10, getdate(),getdate()+30, 1) set @Codigo = @@Identity PRINT @Codigo El uso de @@Identity no siempre es vlido, ya que al devolver el litmo valor identidad insertado por la transaccin, no nos garantiza que el valor haya sido insertado en la tabla que nos interesa (por ejemplo la tabla podra tener un trigger que insertara datos en otra tabla con campos identidad). En este tipo de escenarios debemos utilizar la funcin, SCOPE_IDENTITY. DECLARE @Codigo int UNDAC SBD I Ing. Williams A. Muoz Robles 3 INSERT INTO PRECIOS (PRECIO, FX_INICIO, FX_FIN, CO_PRODUCTO) VALUES (10, getdate(),getdate()+30, 1) SET @Codigo = SCOPE_IDENTITY() PRINT @Codigo Clausula OUTPUT A partir de la versin de SQL Server 2005 disponemos de la clausula OUTPUT para recuperar los valores que hemos insertado. Al igual que en un trigger disponemos de las tablas lgicas INSERTEDy DELETED. Las columnas con prefijo DELETED reflejan el valor antes de que se complete la instruccin UPDATE o DELETE. Es decir, son una copia de los datos "antes" del cambio. DELETED no se puede utilizar con la clusula OUTPUT en la instruccin INSERT. Las columnas con prefijo INSERTED reflejan el valor despus de que se complete la instruccin UPDATE o INSERT, pero antes de que se ejecuten los desencadenadores. Es decir, son una copia de los datos "despues" del cambio. INSERTEDno se puede utilizar con la clusula OUTPUT en la instruccin DELETE. DECLARE @FILAS_INSERTADAS TABLE ( CO_PRECIO int, PRECIO decimal, FX_INICIO datetime, FX_FIN datetime, CO_PRODUCTO int ) INSERT INTO PRECIOS (PRECIO, FX_INICIO, FX_FIN, CO_PRODUCTO) UNDAC SBD I Ing. Williams A. Muoz Robles 4 OUTPUT INSERTED.* INTO @FILAS_INSERTADAS VALUES (10, getdate(),getdate()+30, 1) SELECT * FROM @FILAS_INSERTADAS UNDAC SBD I Ing. Williams A. Muoz Robles 5 Actualizar datos en Transact SQL Update Para la actualizacin de datos Transact SQL dispone de la sentencia UPDATE. La sentencia UPDATE permite la actualizacin de uno o varios registros de una nica tabla. La sintaxis de la sentencia UPDATE es la siguiente UPDATE <nombre_tabla> SET <campo1> = <valor1> {[,<campo2> = <valor2>,...,<campoN> = <valorN>]} [ WHERE <condicion>]; El siguiente ejemplo muestra el uso de UPDATE. UPDATE CLIENTES SET NOMBRE = 'Devjoker', APELLIDO1 = 'Herrarte', APELLIDO2 = 'Snchez' WHERE CO_CLIENTE = 10 Un aspecto a tener en cuenta, sobre todo si has trabajado con ORACLE, es que SQL graba los cambios inmediatamente sin necesidad de hacer COMMIT. Por supuesto podemos gestionar nosostros las transacciones pero es algo que hay que hacer de forma explicita con la instruccion BEGIN TRANy que se ver en capitulos posteriores de este tutorial. Update INNER J OIN En ocasiones queremos actualizar los datos de una tabla con los datos de otra (muy comn para desnormalizar un modelo de datos). UNDAC SBD I Ing. Williams A. Muoz Robles 6 Habitualmente, usamos subconsultas para este proposito, pero Transact SQL permite la utilizacin de la sentencia UPDATE INNER J OIN. UPDATE CLIENTES SET NOMBRE = FICHERO_CLIENTES.NOMBRE, APELLIDO1 = FICHERO_CLIENTES.APELLIDO1, APELLIDO2 = FICHERO_CLIENTES.APELLIDO2 FROM CLIENTES INNER JOIN FICHERO_CLIENTES ON FICHERO_CLIENTES.CO_CLIENTE = CLIENTES.CO_CLIENTE Clausula OUTPUT A partir de la version de SQL Server 2005 disponemos de la clausula OUTPUT para recuperar los valores que hemos insertado. Al igual que en un trigger disponemos de las tablas lgicas INSERTED y DELETED. Las columnas con prefijo DELETED reflejan el valor antes de que se complete la instruccin UPDATE o DELETE. Es decir, son una copia de los datos "antes" del cambio. DELETED no se puede utilizar con la clusula OUTPUT en la instruccin INSERT. DECLARE @FILAS_ACTUALIZADAS TABLE ( CO_CLIENTE int , NOMBRE varchar(100), APELLIDO1 varchar(100), APELLIDO2 varchar(100) ) UNDAC SBD I Ing. Williams A. Muoz Robles 7 UPDATE CLIENTES SET NOMBRE = 'Devjoker', APELLIDO1 = 'Herrarte', APELLIDO2 = 'Snchez' OUTPUT DELETED.* INTO @FILAS_ACTUALIZADAS WHERE CO_CLIENTE IN (10, 11, 12) SELECT * FROM @FILAS_ACTUALIZADAS Las columnas con prefijo INSERTED reflejan el valor despus de que se complete la instruccin UPDATE o INSERT, pero antes de que se ejecuten los desencadenadores. Es decir, son una copia de los datos "despus" del cambio. INSERTEDno se puede utilizar con la clusula OUTPUT en la instruccin DELETE. DECLARE @FILAS_ACTUALIZADAS TABLE ( CO_CLIENTE int , NOMBRE varchar(100), APELLIDO1 varchar(100), APELLIDO2 varchar(100) ) UPDATE CLIENTES SET NOMBRE = 'Devjoker', APELLIDO1 = 'Herrarte', APELLIDO2 = 'Snchez' OUTPUT INSERTED.* INTO @FILAS_ACTUALIZADAS WHERE CO_CLIENTE IN (10, 11, 12) SELECT * FROM @FILAS_ACTUALIZADAS UNDAC SBD I Ing. Williams A. Muoz Robles 8 Borrar datos en Transact SQL Delete Para borrar datos de una tabla debemos utilizar la sentencia DELETE. Para ejecutar los ejemplos de este apartado debemos ejecutar el siguiente script, que crea la tabla "DATOS" y carga registros en ella. CREATE TABLE DATOS ( Id int identity not null, dato varchar(100), fx_alta datetime, constraint PK_DATOS PRIMARY KEY (Id) ) GO DECLARE @i int, @dato varchar(100) set @i = 0 WHILE (@i <100) BEGIN SET @i = @i +1 set @dato = 'Dato:' + cast(@i as varchar) INSERT INTO DATOS (dato, fx_alta) VALUES (@dato, getdate()) END GO SELECT * from DATOS Para borrar los registros de la tabla "DATOS" ejecutaremos la siguiente instruccin. Notese que no se especifica ninguna condicin WHERE por lo que se borran todos los datos de la tabla. UNDAC SBD I Ing. Williams A. Muoz Robles 9 DELETE FROM DATOS Lgicamente podemos especicar que registros queremos borrar a travs de la clausula WHERE. DELETE FROM DATOS WHERE Id=12 Cuando borramos datos de una tabla, podemos obtener el nmero de filas que han sido afectadas por la instruccin a travs de la variable @@RowCount. El siguiente ejemplo ilustra el uso de @@RowCount. DELETE FROM DATOS WHERE Id=17 SELECT @@ROWCOUNT Clausula OUTPUT A partir de la version de SQL Server 2005 disponemos de la clausula OUTPUT para recuperar los valores que hemos insertado. Al igual que en un trigger disponemos de las tablas lgicas INSERTED y DELETED. Las columnas con prefijo DELETED reflejan el valor antes de que se complete la instruccin UPDATE o DELETE. Es decir, son una copia de los datos "antes" del cambio. DELETED no se puede utilizar con la clusula OUTPUT en la instruccin INSERT. UNDAC SBD I Ing. Williams A. Muoz Robles 10 DECLARE @FILAS_BORRADAS TABLE ( Id int, dato varchar(100), fx_alta datetime ) DELETE FROM DATOS OUTPUT DELETED.* INTO @FILAS_BORRADAS WHERE Id=17 SELECT * from @FILAS_BORRADAS Truncate Table Para borrar datos de forma masiva disponemos de la instruccin TRUNCATE TABLE, que borra todos los datos de una tabla. TRUNCATE TABLE DATOS Cuando trabajamos con TRUNCATE TABLE debemos tener en cuenta las siguientes consideraciones: TRUNCATE TABLE no admite la clausula WHERE. No podemos ejecutar TRUNCATE TABLE sobre tablas que sean "padres" en foreign keys. UNDAC SBD I Ing. Williams A. Muoz Robles 11 Consultar datos en Transact SQL SENTENCI A SELECT La sentencia SELECT nos permite consultar los datos almacenados en una tabla de la base de datos. El formato de la sentencia select es: SELECT [ALL | DISTINCT ][ TOP expression [ PERCENT ] [ WITH TIES ] ] <nombre_campos> FROM <nombre_tabla> [ INNER | LEFT [OUTER]| RIGHT [OUTER] | CROSS] [JOIN ] <nombre_tabla> ON <condicion_join>[ AND|OR <condicion>] [WHERE <condicion> [ AND|OR <condicion>]] [GROUP BY <nombre_campos>] [HAVING <condicion>[ AND|OR <condicion>]] [ORDER BY <nombre_campo> [ASC | DESC] El siguiente ejemplo muestra una consulta sencilla que obtiene el cdigo y la "familia" de una tabla llamada familias (representara familias de productos por ejemplo). SELECT CO_FAMILIA, FAMILIA FROM FAMILIAS El uso del asterisco indica que queremos que la consulta devuelva todos los campos que existen en la tabla. SELECT * FROM FAMILIAS UNDAC SBD I Ing. Williams A. Muoz Robles 12 Ahora vamos a realizar una consulta obteniendo adems de los datos de familias, los datos de las categorias y los productos. SELECT * FROM FAMILIAS INNER JOIN CATEGORIAS ON CATEGORIAS.CO_FAMILIA = FAMILIAS.CO_FAMILIA INNER JOIN PRODUCTOS ON PRODUCTOS.CO_CATEGORIA = CATEGORIAS.CO_CATEGORIA La combinacin se realiza a travs de la clausula INNER J OI N, que es una clasula exclusiva, es decir las familias que no tengan categorias y productos asociados no se devolveran. Si queremos realizar la consulta para que no sea exclusiva, tenemos que utilizar LEFT J OIN. El uso de la palabra reservada OUTER es opcional. SELECT * FROM FAMILIAS LEFT OUTER JOIN CATEGORIAS ON CATEGORIAS.CO_FAMILIA = FAMILIAS.CO_FAMILIA LEFT OUTER JOIN PRODUCTOS ON PRODUCTOS.CO_CATEGORIA = CATEGORIAS.CO_CATEGORIA Los registros que no tengan datos relacionados en una consulta LEFT J OIN devolveran en valor null en los campos que correspondan a las tablas en las que no tienen dato. Tambin podemos forzar un producto cartesiano (todos con todos) a travs de CROSS J OIN. SELECT * FROM FAMILIAS CROSS JOIN CATEGORIAS UNDAC SBD I Ing. Williams A. Muoz Robles 13 La clusula WHERE La clusula WHERE es la instruccin que nos permite filtrar el resultado de una sentencia SELECT. SELECT CO_FAMILIA, FAMILIA FROM FAMILIAS WHERE CO_FAMILIA = 1 Por supuesto, podemos especificar varias condiciones para el WHERE: SELECT * FROM FAMILIAS WHERE CO_FAMILIA = 1 OR CO_FAMILIA = 2 Podemos agrupar varias valores para una condicion en la clausula IN: SELECT * FROM FAMILIAS WHERE CO_FAMILIA IN ( 1 , 2) La clausula WHERE se puede utilizar conjuntamente con INNER J OIN, LEFT J OIN ... SELECT FAMILIAS.CO_FAMILIA, FAMILIAS.FAMILIA FROM FAMILIAS INNER JOIN CATEGORIAS ON CATEGORIAS.CO_FAMILIA = FAMILIAS.CO_FAMILIA WHERE FAMILIAS.CO_FAMILIA > 1 UNDAC SBD I Ing. Williams A. Muoz Robles 14 Siempre que incluyamos un valor alfanumerico para un campo en la condicin WHERE este debe ir entre comillas simples: SELECT * FROM FAMILIAS WHERE FAMILIA = 'FAMILIA 1' Para consultar campos alfanumericos, es decir, campos de texto podemos utilizar el operador LIKE conjuntamente con comodines. SELECT * FROM FAMILIAS WHERE FAMILIA LIKE 'FAM%' Los comodines que podemos utilizar en son los siguientes: % , representa cualquier cadena de texto de cero o ms caracteres de cualquier longitud. _ , representa un carcter. [a-d], representa cualquier carcter del intervalo a-d. [abcd], representa cualquier carcter del grupo abcd. [^a-d], representa cualquier carcter diferente del intervalo a-d. [^abcd], representa cualquier carcter distinto del grupo abcd. Tambin podemos obtener los valores distintos utilizando DISTINCT. SELECT DISTINCT FAMILIA -- Devuelve los distintos valores de FAMILIA FROM FAMILIAS Podemos limitar el nmero de registros que devuelve la consulta a travs de la clausula TOP. La clausula TOP admite como parmetros un valor numrico entero o un porcentaje (slo a partir de la version 2005) UNDAC SBD I Ing. Williams A. Muoz Robles 15 SELECT TOP 10 * -- Devuelve 10 registros FROM FAMILIAS SELECT TOP 50 PERCENT * -- Devuelve el 50% de los registros FROM FAMILIAS La clausula TOPse puede combinar con WITH TIES en consultas agregadas. La clusula ORDER BY Podemos especificar el orden en el que sern devueltos los datos a travs de la clusula ORDER BY. SELECT CO_FAMILIA, FAMILIA FROM FAMILIAS ORDER BY FAMILIA DESC Tambin podemos indicar el ndice del campo en la lista de seleccin en lugar de su nombre: SELECT CO_FAMILIA, FAMILIA FROM FAMILIAS ORDER BY 2 DESC -- Ordena por FAMILIA UNDAC SBD I Ing. Williams A. Muoz Robles 16 Consultas agregadas La clusula GROUP BY La clausula GROUP BY combina los registros devueltos por una consulta SELECT obteniendo uno o varios valores agregados(suma, valor mnimo y mximo ...). Para cada registro se puede crear un valor agregado si se incluye una funcin SQL agregada, como por ejemplo Sum o Count, en la instruccin SELECT. Su sintaxis es: SELECT [ALL | DISTINCT ] [TOP <n> [WITH TIES]] <nombre_campo> [{,<nombre_campo>}] [{,<funcion_agregado>}] FROM <nombre_tabla>|<nombre_vista> [{,<nombre_tabla>|<nombre_vista>}] [WHERE <condicion> [{ AND|OR <condicion>}]] [GROUP BY <nombre_campo> [{,<nombre_campo >}]] [HAVING <condicion>[{ AND|OR <condicion>}]] [ORDER BY <nombre_campo>|<indice_campo> [ASC | DESC] [{,<nombre_campo>|<indice_campo> [ASC | DESC ]}]] Si se utiliza GROUP BY pero no existe una funcin SQL agregada en la instruccin SELECT se obtiene el mismo resultado que con una consulta SELECT DISTINCT. Los valores Null en los campos GROUP BY se agrupan y no se omiten. No obstante, los valores Null no se evalan en ninguna de las funciones SQL agregadas. Todos los campos de la lista de campos de SELECT deben incluirse en la clusula GROUP BY o como argumentos de una funcin SQL agregada. El siguiente ejemplo realiza una "cuenta" de los datos que hay en la tabla PRODUCTOS. UNDAC SBD I Ing. Williams A. Muoz Robles 17 SELECT COUNT(*) FROM PRODUCTOS Este otro ejemplo, muestra la suma del PRECIO de cada uno de los productos que componen un pedido, para calcular el total del pedido agrupados por los datos del cliente. SELECT CLIENTES.NOMBRE, CLIENTES.APELLIDO1, CLIENTES.APELLIDO2, SUM(PRECIO) -- Total del pedido FROM DETALLE_PEDIDO INNER JOIN PEDIDOS ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO INNER JOIN CLIENTES ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE GROUP BY CLIENTES.NOMBRE, CLIENTES.APELLIDO1, CLIENTES.APELLIDO2 Siempre que incluyamos una clausula WHERE en una consulta agregada esta se aplica antes de calcular el valor agregado. Es decir, si sumamos el valor de las ventas por producto, la suma se calcula despues de haber aplicado el filtro impuesto por la clausula WHERE. SELECT CLIENTES.NOMBRE, CLIENTES.APELLIDO1, CLIENTES.APELLIDO2, SUM(PRECIO) -- Total del pedido FROM DETALLE_PEDIDO INNER JOIN PEDIDOS ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO INNER JOIN CLIENTES ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE UNDAC SBD I Ing. Williams A. Muoz Robles 18 -- La clausula WHERE se aplica antes de realizar el calculo WHERE CLIENTES.NOMBRE != 'UN NOMBRE' GROUP BY CLIENTES.NOMBRE, CLIENTES.APELLIDO1, CLIENTES.APELLIDO2 La clusula HAVING Es posible que necesitemos calcular un agregado, pero que no necesitemos obtener todos los datos, solo los que cumplan una condicin del agregado. Por ejemplo, podemos calcular el valor de las ventas por producto, pero que solo queramos ver los datos de los productos que hayan vendido ms o menos de una determinada cantidad. En estos casos debemos utilizar la clusula HAVING. Una vez que GROUP BY ha combinado los registros, HAVING muestra cualquier registro agrupado por la clusula GROUP BY que satisfaga las condiciones de la clusula HAVING. Se utiliza la clusula WHERE para excluir aquellas filas que no desea agrupar, y la clusula HAVING para filtrar los registros una vez agrupados. HAVING es similar a WHERE, determina qu registros se seleccionan pero despus de calcular el agregado. Una vez que los registros se han agrupado utilizando GROUP BY, HAVING determina cuales de ellos se van a mostrar. HAVING permite el uso de funciones agregadas. SELECT CLIENTES.NOMBRE, CLIENTES.APELLIDO1, CLIENTES.APELLIDO2, SUM(PRECIO) -- Total del pedido FROM DETALLE_PEDIDO INNER JOIN PEDIDOS ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO INNER JOIN CLIENTES ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE UNDAC SBD I Ing. Williams A. Muoz Robles 19 -- La clausula WHERE se aplica antes de realizar el calculo WHERE CLIENTES.NOMBRE != 'UN NOMBRE' GROUP BY CLIENTES.NOMBRE, CLIENTES.APELLIDO1, CLIENTES.APELLIDO2 HAVING SUM(PRECIO) > 100 Funciones agregadas. Transact SQL pone a nuestra disposicin multiples funciones agregadas, las ms comunes son: MAX MIN COUNT SUM AVG AVG Calcula la media aritmtica de un conjunto de valores contenidos en un campo especificado de una consulta. Su sintaxis es la siguiente AVG(<expr>) En donde expr representa el campo que contiene los datos numricos para los que se desea calcular la media o una expresin que realiza un clculo utilizando los datos de dicho campo. La media calculada por Avg es la media aritmtica (la suma de los valores dividido por el nmero de valores). La funcin Avg no incluye ningn campo Null en el clculo. UNDAC SBD I Ing. Williams A. Muoz Robles 20 SELECT CLIENTES.NOMBRE, CLIENTES.APELLIDO1, CLIENTES.APELLIDO2, AVG(PRECIO) -- Promedio del pedido FROM DETALLE_PEDIDO INNER JOIN PEDIDOS ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO INNER JOIN CLIENTES ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE GROUP BY CLIENTES.NOMBRE, CLIENTES.APELLIDO1, CLIENTES.APELLIDO2 Count Calcula el nmero de registros devueltos por una consulta. Su sintaxis es la siguiente: COUNT(<expr>) En donde expr contiene el nombre del campo que desea contar. Los operandos de expr pueden incluir el nombre de un campo de una tabla, una constante o una funcin (la cual puede ser intrnseca o definida por el usuario pero no otras de las funciones agregadas de SQL). Puede contar cualquier tipo de datos incluso texto. Aunque expr puede realizar un clculo sobre un campo, Count simplemente cuenta el nmero de registros sin tener en cuenta qu valores se almacenan en los registros. La funcin Count no cuenta los registros que tienen campos null a menos que expr sea el carcter comodn asterisco (*). Si utiliza un asterisco, Count calcula el nmero total de registros, incluyendo aquellos que contienen campos null. Count(*) es considerablemente ms rpida que Count(Campo). UNDAC SBD I Ing. Williams A. Muoz Robles 21 SELECT COUNT(*) FROM PEDIDOS SELECT CLIENTES.NOMBRE, COUNT(*) FROM PEDIDOS INNER JOIN CLIENTES ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE GROUP BY CLIENTES.NOMBRE Max, Min Devuelven el mnimo o el mximo de un conjunto de valores contenidos en un campo especifico de una consulta. Su sintaxis es: MIN(<expr>) MAX(<expr>) En donde expr es el campo sobre el que se desea realizar el clculo. Expr pueden incluir el nombre de un campo de una tabla, una constante o una funcin (la cual puede ser intrnseca o definida por el usuario pero no otras de las funciones agregadas de SQL). SELECT CLIENTES.NOMBRE, MIN(PEDIDOS.FX_ALTA), MAX(PEDIDOS.FX_ALTA) FROM PEDIDOS INNER JOIN CLIENTES ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE GROUP BY CLIENTES.NOMBRE UNDAC SBD I Ing. Williams A. Muoz Robles 22 Sum Devuelve la suma del conjunto de valores contenido en un campo especifico de una consulta. Su sintaxis es: SUM(<expr>) En donde expr respresenta el nombre del campo que contiene los datos que desean sumarse o una expresin que realiza un clculo utilizando los datos de dichos campos. Los operandos de expr pueden incluir el nombre de un campo de una tabla, una constante o una funcin (la cual puede ser intrnseca o definida por el usuario pero no otras de las funciones agregadas de SQL). SELECT CLIENTES.NOMBRE, SUM(PEDIDOS.TOTAL_PEDIDO) FROM PEDIDOS INNER JOIN CLIENTES ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE GROUP BY CLIENTES.NOMBRE Uso de Select TOP con consultas agregadas. Podemos utilizar SELECT TOP con consultas agregadas como con cualquier otra instruccin Transact SQL. En estos casos, la clusula TOP se aplica despus de calcular el agregado, devolviendo las N filas indicadas. En este escenario es posible que queramos obtener los N valores que satisfagan una condicin. Por ejemplo, queremos si queremos obtener los tres primeros clientes con mayores pedidos, usaremos una consulta parecida a esta: UNDAC SBD I Ing. Williams A. Muoz Robles 23 SELECT TOP 3 CLIENTES.NOMBRE, SUM(DETALLE_PEDIDO.PRECIO) FROM DETALLE_PEDIDO INNER JOIN PEDIDOS ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO INNER JOIN CLIENTES ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE GROUP BY CLIENTES.NOMBRE ORDER BY 2 -- SUM(DETALLE_PEDIDO.PRECIO_UNIDAD) Sin embargo, puede darse el caso, de que el cuarto cliente devuelto por la consulta tenga un valor agregado idntico al tercero, (es decir, estn empatados). El uso de TOP 3 discriminara el cuarto registro. Para evitar este comportamiento, y que la consulta devuelva tambin al cuarto cliente utilizamos la clusula WITH TIES. SELECT TOP 3 WITH TIES CLIENTES.NOMBRE, SUM(DETALLE_PEDIDO.PRECIO) FROM DETALLE_PEDIDO INNER JOIN PEDIDOS ON DETALLE_PEDIDO.CO_PEDIDO = PEDIDOS.CO_PEDIDO INNER JOIN CLIENTES ON PEDIDOS.CO_CLIENTE = CLIENTES.CO_CLIENTE GROUP BY CLIENTES.NOMBRE ORDER BY 2 -- SUM(DETALLE_PEDIDO.PRECIO_UNIDAD) UNDAC SBD I Ing. Williams A. Muoz Robles 24 Subconsultas Definicin de subconsultas. Una subconsulta es una sentencia SELECT que aparece dentro de otra sentencia SELECT. Normalmente se utilizan para filtrar una clausula WHERE o HAVING con el conjunto de resultados de la subconsulta, aunque tambin pueden utilizarse en la lista de seleccin. Por ejemplo podriamos consultar el alquirer ltimo de un cliente. SELECT CO_CLIENTE, NOMBRE, MARCA, MODDELO FROM ALQUILERES WHERE CO_CLIENTE = 1 AND FECHA_ALQUILER = (SELECT MAX(FECHA_ALQUILER) FROM ALQUILERES WHERE CO_CLIENTE = 1) En este caso, la subconsulta se ejecuta en primer lugar, obteniendo el valor de la mxima fecha de alquier, y posteriormente se obtienen los datos de la consulta principal. Una subconsulta tiene la misma sintaxis que una sentencia SELECT normal exceptuando que aparece encerrada entre parntesis. La subconsulta se puede encontrar en la lista de seleccin, en la clusula WHERE o en la clusula HAVING de la consulta principal. Tiene las siguientes reestricciones: No puede contener la clusula ORDER BY No puede ser la UNION de varias sentencias SELECT Si la subconsulta aparece en la lista de seleccin,o esta asociada a un operador igual "=" solo puede devolver un nico registro. UNDAC SBD I Ing. Williams A. Muoz Robles 25 Referencias externas A menudo, es necesario, dentro del cuerpo de una subconsulta, hacer referencia al valor de una columna de la fila actual en la consulta principal, ese nombre de columna se denomina referencia externa. Una referencia externa es un campo que aparece en la subconsulta pero se refiere a la una de las tablas designadas en la consulta principal. Cuando se ejecuta una consulta que contiene una subconsulta con referencias externas, la subconsulta se ejecuta por cada fila de la consulta principal. En este ejemplo la subconsulta aparece en la lista de seleccin, ejecutandose una vez por cada fila que devuelve la consulta principal. SELECT CO_EMPLEADO, NOMBRE, (SELECT MI N(FECHA_NOMINA) FROM NOMINAS WHERE CO_EMPLEADO = EMPLEADOS.CO_EMPLEADO) PRIMERA_NOMINA FROM EMPLEADOS; Anidar subconsultas Las subconsultas pueden anidarse de forma que una subconsulta aparezca en la clusula WHERE (por ejemplo) de otra subconsulta que a su vez forma parte de otra consulta principal. SELECT CO_EMPLEADO, EMPLEADOS FROM EMPLEADOS WHERE CO_EMPLEADO IN (SELECT CO_EMPLEADO FROM NOMINAS WHERE ESTADO I N ( SELECT ESTADO UNDAC SBD I Ing. Williams A. Muoz Robles 26 FROM ESTADOS_NOMINAS WHERE EMITIDO = 'S' AND PAGADO = ' N' ) ) Los resultados que se obtienen con subconsultas normalmente pueden conseguirse a travs de consultas combinadas ( J OIN ). SELECT CO_EMPLEADO, NOMBRE FROM EMPLEADOS WHERE ESTADO IN (SELECT ESTADO FROM ESTADOS WHERE ACTIVO = 'S') Podr escribirse como : SELECT CO_EMPLEADO, NOMBRE FROM EMPLEADOS, ESTADOS WHERE EMPLEADOS.ESTADO = ESTADOS.ESTADO AND ESTADOS.ACTIVO = 'S' Normalmente es ms rpido utilizar un J OIN en lugar de una subconsulta, aunque esto depende sobre todo del diseo de la base de datos y del volumen de datos que tenga. La funcin EXISTS EXISTS es una funcin SQL que devuelve veradero cuando una subconsulta retorna al menos una fila. UNDAC SBD I Ing. Williams A. Muoz Robles 27 SELECT CO_CLIENTE, NOMBRE FROM CLIENTES WHERE EXISTS ( SELECT * FROM MOROSOS WHERE CO_CLIENTE = CLIENTES.CO_CLIENTE AND PAGADO = 'N') La funcin EXISTS puede ser utilizada en cualquier sentencia SQL vida, SELECT, UPDATE, INSERT o DELETE. UNDAC SBD I Ing. Williams A. Muoz Robles 28 Select FOR XML Clausula FOR XML. A partir de la version 2000 SQL Server incluye la clausula FOR XML para la consultas. Sin embargo, es a partir de la versin 2005 cuando se integra XML como tipo de dato nativo. Cuando especificamos la clausula FOR XML el resultado de la consulta es devuelto en formato XML. La clausula FOR XML admite los siguientes modos que representan el formato en el que el XML es devuelto: XML AUTO, el modo AUTO emplea los campos en la declaracin SELECT para formar una jerarqua simple XML. XML RAW, el modo RAW genera elementos nicos, los cuales se denominan row, por cada fila retornada. EXPLICIT, el modo EXPLICIT requiere un formato especfico que puede ser mapeado en casi cualquier forma XML, y al mismo tiempo ser formulado por una sola consulta SQL. Adicionalmente, disponemos de dos opciones ms TYPE y ELEMENTS que determinan el formato del XML resultante. Los vemos con ejemplos. Un ejemplo de XML AUTO. SELECT CO_FAMILIA, FAMILIA FROM FAMILIAS ORDER BY FAMILIA FOR XML AUTO, TYPE Obtendremos el siguiente resultado: UNDAC SBD I Ing. Williams A. Muoz Robles 29 <FAMILIAS CO_FAMILIA="1" FAMILIA="FAMILIA 1" /> <FAMILIAS CO_FAMILIA="2" FAMILIA="FAMILIA 2" /> <FAMILIAS CO_FAMILIA="3" FAMILIA="FAMILIA 3" /> <FAMILIAS CO_FAMILIA="4" FAMILIA="FAMILIA 4" /> Podemos obtener el resultado como elementos de la siguiente forma: SELECT CO_FAMILIA, FAMILIA FROM FAMILIAS FOR XML AUTO, ELEMENTS Obtendremos el siguiente resultado: <FAMILIAS> <CO_FAMILIA>1</CO_FAMILIA> <FAMILIA>FAMILIA 1</FAMILIA> </FAMILIAS> <FAMILIAS> <CO_FAMILIA>2</CO_FAMILIA> <FAMILIA>FAMILIA 2</FAMILIA> </FAMILIAS> <FAMILIAS> <CO_FAMILIA>3</CO_FAMILIA> <FAMILIA>FAMILIA 3</FAMILIA> </FAMILIAS> <FAMILIAS> <CO_FAMILIA>4</CO_FAMILIA> <FAMILIA>FAMILIA 4</FAMILIA> </FAMILIAS> Ahora un ejemplo de XML RAW: UNDAC SBD I Ing. Williams A. Muoz Robles 30 SELECT CO_FAMILIA, FAMILIA FROM FAMILIAS ORDER BY FAMILIA FOR XML RAW , TYPE Obtenemos el siguiente resultado: <row CO_FAMILIA="1" FAMILIA="FAMILIA 1" /> <row CO_FAMILIA="2" FAMILIA="FAMILIA 2" /> <row CO_FAMILIA="3" FAMILIA="FAMILIA 3" /> <row CO_FAMILIA="4" FAMILIA="FAMILIA 4" /> Podemos obtener el resultado como elementos de la siguiente forma: <row> <CO_FAMILIA>1</CO_FAMILIA> <FAMILIA>FAMILIA 1</FAMILIA> </row> <row> <CO_FAMILIA>2</CO_FAMILIA> <FAMILIA>FAMILIA 2</FAMILIA> </row> <row> <CO_FAMILIA>3</CO_FAMILIA> <FAMILIA>FAMILIA 3</FAMILIA> </row> <row> <CO_FAMILIA>4</CO_FAMILIA> <FAMILIA>FAMILIA 4</FAMILIA> </row> Tambin es posible especificar el nodo que queremos que muestre: UNDAC SBD I Ing. Williams A. Muoz Robles 31 SELECT CO_FAMILIA, FAMILIA FROM FAMILIAS ORDER BY FAMILIA FOR XML RAW ('FamiliasDeProductos') , TYPE Devuelve el siguiente resultado: <FamiliasDeProductos CO_FAMILIA="1" FAMILIA="FAMILIA 1" /> <FamiliasDeProductos CO_FAMILIA="2" FAMILIA="FAMILIA 2" /> <FamiliasDeProductos CO_FAMILIA="3" FAMILIA="FAMILIA 3" /> <FamiliasDeProductos CO_FAMILIA="4" FAMILIA="FAMILIA 4" /> Del mismo modo con la opcin ELEMENTS: SELECT CO_FAMILIA, FAMILIA FROM FAMILIAS ORDER BY FAMILIA FOR XML RAW ('FamiliasDeProductos') , ELEMENTS Obtendremos el siguiente resultado: <FamiliasDeProductos> <CO_FAMILIA>1</CO_FAMILIA> <FAMILIA>FAMILIA 1</FAMILIA> </FamiliasDeProductos> <FamiliasDeProductos> <CO_FAMILIA>2</CO_FAMILIA> <FAMILIA>FAMILIA 2</FAMILIA> </FamiliasDeProductos> <FamiliasDeProductos> <CO_FAMILIA>3</CO_FAMILIA> <FAMILIA>FAMILIA 3</FAMILIA> UNDAC SBD I Ing. Williams A. Muoz Robles 32 </FamiliasDeProductos> <FamiliasDeProductos> <CO_FAMILIA>4</CO_FAMILIA> <FAMILIA>FAMILIA 4</FAMILIA> </FamiliasDeProductos> Ahora un ejemplo con el formato XML EXPLICIT. SELECT 1 AS TAG, -- La primera columna debe tener el alias TAG NULL AS PARENT, -- La segunda columna debe tener el alias PARENT -- El resto de columnas deben tener el alias en el formato: -- <NombreNodo>!<nodo>!<atributo> CO_FAMILIA as "FamiliaDeProductos!1!CODIGO_FAMILIA", FAMILIA as "FamiliaDeProductos!1!DESCRIPCION" FROM FAMILIAS ORDER BY FAMILIA FOR XML EXPLICIT Obtenemos el siguiente resultado: <FamiliaDeProductos CODIGO_FAMILIA="1" DESCRIPCION="FAMILIA 1" /> <FamiliaDeProductos CODIGO_FAMILIA="2" DESCRIPCION="FAMILIA 2" /> <FamiliaDeProductos CODIGO_FAMILIA="3" DESCRIPCION="FAMILIA 3" /> <FamiliaDeProductos CODIGO_FAMILIA="4" DESCRIPCION="FAMILIA 4" /> Campos y variables XML. Dado que XML es un tipo nativo de XML podemos definir tablas con campos de tipo XML, variables ... El siguiente ejemplo muestra como trabajar con campos y variables XML. UNDAC SBD I Ing. Williams A. Muoz Robles 33 -- Primero creamos una tabla con un campo XML CREATE TABLE tablaXML ( ID int not null identity, DOC xml null, constraint PK_tablaXML PRIMARY KEY (ID) ) GO DECLARE @xml xml -- Variable de tipo XML -- Leemos los datos de la tabla FAMILIAS SET @xml = (SELECT CO_FAMILIA, FAMILIA FROM FAMILIAS FOR XML AUTO) -- y los guardamos en nuestra tabla INSERT INTO tablaXML (DOC) VALUES (@xml) -- Hacemos lo mismo con los productos SET @xml = (SELECT * FROM PRODUCTOS FOR XML AUTO) INSERT INTO tablaXML (DOC) VALUES (@xml) -- Consultamos la tabla y vemos el resultado SELECT * FROM tablaXML Cuando consultemos la tabla tendremos la siguiente informacin (en mi caso claro!): UNDAC SBD I Ing. Williams A. Muoz Robles 34 <!--Registro de la tabla familias--> <FAMILIAS CO_FAMILIA="1" FAMILIA="FAMILIA 1" /> <FAMILIAS CO_FAMILIA="2" FAMILIA="FAMILIA 2" /> <FAMILIAS CO_FAMILIA="3" FAMILIA="FAMILIA 3" /> <FAMILIAS CO_FAMILIA="4" FAMILIA="FAMILIA 4" /> <!--Registro de la tabla Productos--> <PRODUCTOS CO_PRODUCTO="1" CO_CATEGORIA="1" PRODUCTO="PRODUCTO 1" /> <PRODUCTOS CO_PRODUCTO="2" CO_CATEGORIA="1" PRODUCTO="PRODUCTO 2" /> <PRODUCTOS CO_PRODUCTO="3" CO_CATEGORIA="2" PRODUCTO="PRODUCTO 3" />