Curso de SQL Server.docx

214
Curso de SQL Server. Índice del curso Í n d i c e d e t a l l a d o Unidad 1. El entorno gráfico SSMS 1.1. Introducción 1.2. Instalar SQL Server 2005 1.3. Entrada al SQL Server Management Studio Introducción a las bases de datos Ediciones de SQL Server 2005 1.4. Estructura interna de una base de datos 1.5. Crear una base de datos en SSMS 1.6. Adjuntar una base de datos 1.7. Conectar y Desconectar la base de datos 1.8. Crear una nueva tabla 1.9. Tipos de datos 1.10. Valores nulos 1.11. Columna con contador 1.12. Clave primaria 1.13. Añadir o eliminar columnas 1.14. Modificar la definición de una tabla 1.15. Insertar datos en la tabla 1.16. Modificar datos 1.17. Eliminar filas 1.18. Relacionar tablas 1.19. Abrir una nueva consulta 1.20. Escribir y ejecutar código TRANSACT-SQL 1.21. La base de datos predeterminada 1.22. El editor de texto 1.23. Configurar un esquema de colores personalizado 1.24. Las Vistas Unidad 5. Consultas de resumen 5.1. Introducción 5.2. Las funciones de agregado 5.3. La función COUNT 5.4. La función COUNT_BIG 5.5. La función MAX 5.6. La función MIN 5.7. La función SUM 5.8. La función AVG 5.9. La función VAR 5.10. La función VARP 5.11. La función STDEV 5.12. La función STDEVP 5.13. La función GROUPING 5.14. Agrupamiento de filas (cláusula GROUP BY). 5.15. Selección sobre grupos de filas, la cláusula HAVING Unidad 6. Las subconsultas 6.1. Introducción 6.2. Subconsultas de resultado único 6.3. Subconsultas de lista de valores 6.4. El operador IN con subconsulta 6.5. La comparación modificada (ANY, ALL) 6.6. Subconsultas con cualquier número de columnas (EXISTS) Unidad 7. Actualización de datos 7.1. Introducción 7.2. Insertar creando una 1

Transcript of Curso de SQL Server.docx

Page 1: Curso de SQL Server.docx

Curso de SQL Server. Índice del curso

Í n d i c e    d e t a l l a d o

Unidad 1. El entorno gráfico SSMS

1.1. Introducción 1.2. Instalar SQL Server 2005 1.3. Entrada al SQL Server

Management Studio Introducción a las bases de datos Ediciones de SQL Server 2005 1.4. Estructura interna de una base

de datos 1.5. Crear una base de datos en

SSMS 1.6. Adjuntar una base de datos 1.7. Conectar y Desconectar la base

de datos 1.8. Crear una nueva tabla 1.9. Tipos de datos 1.10. Valores nulos 1.11. Columna con contador 1.12. Clave primaria 1.13. Añadir o eliminar columnas 1.14. Modificar la definición de una

tabla 1.15. Insertar datos en la tabla 1.16. Modificar datos 1.17. Eliminar filas 1.18. Relacionar tablas 1.19. Abrir una nueva consulta 1.20. Escribir y ejecutar  código

TRANSACT-SQL 1.21. La base de datos

predeterminada 1.22. El editor de texto 1.23. Configurar un esquema de

colores personalizado 1.24. Las Vistas 1.25. El panel de diagrama 1.26. El panel de criterios 1.27. El panel SQL

Unidad 2. Introducción al SQL. Transact-SQL

2.1. Conceptos básicos de SQL 2.2. Introducción al TRANSACT-

SQL 2.3. Características generales del

lenguaje Transact-SQL 2.4. Reglas de formato de los

identificadores 2.5. Tipos de datos 2.6. Las constantes

Unidad 5. Consultas de resumen

5.1. Introducción 5.2. Las funciones de agregado 5.3. La función COUNT 5.4. La función COUNT_BIG 5.5. La función MAX 5.6. La función MIN 5.7. La función SUM 5.8. La función AVG 5.9. La función VAR 5.10. La función VARP 5.11.  La función STDEV 5.12. La función STDEVP 5.13. La función GROUPING 5.14. Agrupamiento de filas

(cláusula GROUP BY). 5.15. Selección sobre grupos de

filas, la cláusula HAVING

Unidad 6. Las subconsultas

6.1. Introducción 6.2. Subconsultas de resultado

único 6.3. Subconsultas de lista de valores 6.4. El operador IN con subconsulta 6.5. La comparación modificada

(ANY, ALL) 6.6. Subconsultas con cualquier

número de columnas (EXISTS)

Unidad 7. Actualización de datos

7.1. Introducción 7.2. Insertar creando una nueva

tabla 7.3. Insertar en una tabla existente 

INSERT INTO 7.4. Insertar una fila de valores 7.5. Inserción de varias filas 7.6. Insertar una fila de valores por

defecto 7.7. Modificar datos almacenados -

UPDATE 7.8. Eliminar filas - DELETE 7.9. Borrado masivo - TRUNCATE

Unidad 8. El DDL, Lenguaje de

1

Page 2: Curso de SQL Server.docx

Tipos de datos Definir constantes según el tipo de

dato 2.7. Las expresiones 2.8. Funciones 2.9. Las variables 2.10. Otros elementos del lenguaje

Unidad 3. Consultas simples

3.1. Introducción 3.2. Origen de datos FROM 3.3. La lista de selección 3.4. Columnas del origen de datos 3.5. Alias de columna 3.6. Funciones Funciones en Transact-SQL 3.7. Columnas calculadas 3.8. Utilización del asterisco * 3.9. Las palabras clave $IDENTITY

y $ROWGUID 3.10. Ordenación de las filas del

resultado ORDER BY 3.11. Eliminar filas duplicadas

DISTINCT/ALL 3.12. La cláusula TOP 3.13. Selección de filas WHERE 3.14. Predicados Los predicados CONTAINS y

FREETEXT 3.15. Condiciones de búsqueda

compuestas

Unidad 4. Consultas multitabla

4.1. Introducción 4.2. La unión de tablas UNION 4.3. La diferencia EXCEPT 4.4. La intersección INTERSECT 4.5. La composición de tablas 4.6. El producto cartesiano CROSS

JOIN 4.7. La composición interna INNER

JOIN 4.8. La Composición externa LEFT,

RIGHT y FULL OUTER JOIN 4.9. Combinar varias operaciones

Definición de Datos

8.1. Introducción 8.2. Definir una base de datos

CREATE DATABASE Intercalaciones COLLATE 8.3. Eliminar una base de datos

DROP DATABASE 8.4. Modificar las propiedades de

una BD ALTER DATABASE 8.5. Crear una tabla CREATE

TABLE Tipos de datos: precisión, escala,

longitud y prioridad 8.6. Eliminar una tabla DROP

TABLE 8.7. Modificar la definición de una

tabla ALTER TABLE 8.8. Crear una vista CREATE VIEW 8.9. Eliminar una vista DROP VIEW 8.10. Definición de índice 8.11. Tipos de índices 8.12. Ventajas e inconvenientes de

los índices 8.13. Definir un índice CREATE

INDEX 8.14. Eliminar un índice DROP

INDEX

Unidad 9. Programación en TRANSACT SQL

9.1. Introducción 9.2. Procedimientos almacenados

STORE PROCEDURE 9.3. Eliminar procedimientos

almacenados 9.4. Crear y ejecutar un

procedimiento 9.5. Instrucciones de control de flujo 9.6. IF…   ELSE 9.7. WHILE – BREAK- CONTINUE 9.8. WAITFOR 9.9. GOTO 9.10. TRY... CATCH 9.11. Desencadenadores o

TRIGGERS 9.12. CREATE TRIGGER 9.13. DISABLE TRIGGER 9.14. ENABLE TRIGGER 9.15. DROP TRIGGER

2

Page 3: Curso de SQL Server.docx

Unidad 1. El entorno gráfico SSMS (I)

1.1. Introducción

SQL Server 2005 es un sistema gestor de bases de datos relacionales de Microsoft Corporation orientado a sistemas medianos y grandes aunque también puede rodar en ordenadores personales. SQL Server Management Studio (SSMS) es la herramienta de SQL Server que permite definir y gestionar todas las bases de datos almacenadas en el servidor SQL Server 2005.

En este tema veremos cómo utilizar el SQL Server Management Studio para manejar las bases de datos del servidor y organizaremos el texto en los siguientes puntos:

Instalar SQL Server 2005.

Entrada al SQL Server Management Studio

Las bases de datos: Estructura interna, crear, adjuntar, conectar y desconectar.

Las tablas: crear tablas, definirlas, modificar su contenido, etc.

Relacionar tablas

Las Consultas

Las Vistas

Si no sabes lo que es una base de datos relacional o no tienes conocimientos previos acerca de las bases de datos, puedes leer una introducción a las bases de datos en el

siguiente básico

1.2. Instalar SQL Server 2005

Existen diferentes versiones (ediciones) del producto, por lo que es un producto muy versátil, que puede cumplir con las exigencias de cualquier empresa,  puede ser utilizado para gestionar bases de datos en un PC en modo local a gestionar todo el sistema de información de grandes empresas pasando por sistemas que requieran menos potencia y por sistemas móviles.

Actualmente se utiliza más en entornos Cliente/servidor con equipos medianos y grandes.

Para realizar este curso te recomendamos instalar la versión gratuita: Express. Puedes descargarla desde la página web de Microsoft, desde el enlace para iniciar descarga. Si quieres ver las diferentes ediciones y sus características principales visita el siguiente

avanzado

Si la instalación se realiza a partir del archivo descargado de Internet, la descarga se empaqueta como un único ejecutable mediante una tecnología de instalación de Microsoft llamada SFXCab. Al hacer doble clic en el .exe se inicia automáticamente el proceso de instalación.

Tan sólo deberemos seguir el asistente. Los puntos más importantes a tener en cuenta son:

Habilitar el SQL Server Management Studio en la instalación (si no lo está por defecto) cuando nos pregunte qué componentes deseamos instalar.

3

Page 4: Curso de SQL Server.docx

Indicar que se trata de una Instancia predeterminada.

Lo ideal es que en este punto instales el programa, para ir probando lo que vayas aprendiendo de aquí en adelante. Puedes realizar el siguiente Ejercicio Instalación de SQL Server 2005. El videotutorial práctico de instalación también te ayudará.

1.3. Entrada al SQL Server Management Studio

Aunque trabajemos en modo local, la entrada a la herramienta es la misma. Para

empezar entramos a través del acceso directo  o a través de Inicio, Programas, Microsoft SQL Server 2005, SQL Server Management Studio.

Lo primero que deberemos hacer es establecer la conexión con el servidor:

Seleccionamos el nombre del servidor y pulsamos el botón Conectar. Se abrirá la ventana inicial del SQL Server Management Studio (en adelante SSMS):

4

Page 5: Curso de SQL Server.docx

En la parte izquierda tenemos abierto el panel Explorador de Objetos en el que aparece debajo del nombre del servidor con el que estamos conectados una serie de carpetas y objetos que forman parte del servidor.

En el panel de la derecha se muestra la zona de trabajo, que varía según lo que tengamos seleccionado en el Explorador de objetos, en este caso vemos el contenido de la carpeta que representa el servidor ord01.

En la parte superior tenemos el menú de opciones y la barra de herramientas Estándar.

Con las siguientes opciones:

1. Nueva consulta6. Consulta de SQL Server Mobile

11. Resumen

2. Consulta de motor de Base de datos

7. Abrir archivo12. Explorador de Objetos

3. Consulta MDX de Analysis Services

8. Guardar13. Explorador de Plantillas

4. Consulta DMX de Analysis Services

9. Guardar todo14. Ventana de Propiedades

5. Consulta MXLA de Analysis Services

10. Servidores registrados

En caso de que utilices la versión Express, es posible que no dispongas de algunos de éstos botones.

Unidad 1. El entorno gráfico SSMS (II)

1.4. Estructura interna de una base de datos

Antes de empezar tenemos que tener claro cómo se organiza la información en una base de datos SQL Server 2005.

Las bases de datos de SQL Server 2005 utilizan tres tipos de archivos:

Archivos de datos principales

En una base de datos SQLServer los datos se pueden repartir en varios archivos para mejorar el rendimiento de la base de datos.El archivo de datos principal es el punto de partida de la base de datos y apunta a los otros archivos de datos de la base de datos. Cada base de datos tiene obligatoriamente un archivo de datos principal. La extensión recomendada para los nombres de archivos de datos principales es .mdf.

Archivos de datos secundarios

5

Page 6: Curso de SQL Server.docx

Los archivos de datos secundarios son todos los archivos de datos menos el archivo de datos principal. Puede que algunas bases de datos no tengan archivos de datos secundarios, mientras que otras pueden tener varios archivos de datos secundarios. La extensión de nombre de archivo recomendada para los archivos de datos secundarios es .ndf.

Además los archivos de datos se pueden agrupar en grupos de archivos. Para cada base de datos pueden especificarse hasta 32.767 archivos y 32.767 grupos de archivos.

Archivos de registro

Los archivos de registro (archivos de log) almacenan toda la información de registro que se utiliza para recuperar la base de datos, el también denominado registro de transacciones. Como mínimo, tiene que haber un archivo de registro por cada base de datos, aunque puede haber varios. La extensión recomendada para los nombres de archivos de registro es .ldf.

SQL Server 2005 no exige las extensiones de nombre de archivo .mdf, .ndf y .ldf, pero estas extensiones ayudan a identificar las distintas clases de archivos y su uso.

Cada base de datos tiene al menos 2 archivos (un archivo de datos principal y un archivo de registro) y opcionalmente un grupo de archivos.

Los archivos de datos y de registro de SQL Server se pueden colocar en sistemas de archivos FAT o NTFS. Se recomienda utilizar NTFS por los aspectos de seguridad que ofrece. No se pueden colocar grupos de archivos de datos de lectura y escritura, y archivos de registro, en un sistema de archivos NTFS comprimido. Sólo las bases de datos de sólo lectura y los grupos de archivos secundarios de sólo lectura se pueden colocar en un sistema de archivos NTFS comprimido.

1.5. Crear una base de datos en SSMS

En el Explorador de objetos, si desplegamos la carpeta Bases de datos nos aparecen Bases de datos del sistema y las bases de datos de usuario después de la carpeta Instantáneas...

Después de la instalación, en la carpeta Bases de datos del sistema se habrá creado una especial denominada master se utiliza como base de datos de usuario por defecto. Las demás bases de datos forman también parte del diccionario de datos y las utiliza el sistema para llevar a cabo su gestión.

6

Page 7: Curso de SQL Server.docx

Las bases de datos de los usuarios se deben crear preferentemente fuera de la carpeta Bases de datos del sistema.

Unidad 1. El entorno gráfico SSMS (III)

Para crear una nueva base de datos de usuario nos posicionamos sobre la carpeta Bases de datos y con el botón derecho del ratón desplegamos el menú contextual del que elegimos la opción Nueva base de datos…

Se abre a continuación el cuadro de diálogo donde definiremos la base de datos que queremos crear:

7

Page 8: Curso de SQL Server.docx

Lo mínimo a introducir será el campo Nombre de la base de datos, éste es el nombre de la base de datos lógica, la base de datos a la que nos referiremos dentro del SSMS, a nivel conceptual (en la imagen Mibase).

Esta base de datos está asociada a dos archivos físicos, en la parte inferior aparecen esos archivos. Para facilitarnos la tarea, al teclear el nombre de la bd lógica, se rellenan automáticamente los nombres de los archivos físicos, el de datos con el mismo nombre y el del archivo de registro con el mismo nombre seguido de _log. Estos nombres son los nombres que se asumen por defecto pero los podemos cambiar, posicionando el cursor en el nombre y cambiándolo.

Para cada archivo físico podemos definir una serie de parámetros como el tipo de archivo (si es de datos o de transacciones Registro) y su ocupación inicial (Tamaño inicial).

Si no indicamos ninguna ubicación podemos ver que los guarda en la carpeta del SQL Server/MSSQL.n/MSSQL/DATA.n representa un número que puede variar de una instalación a otra.

8

Page 9: Curso de SQL Server.docx

Estos son los archivos mínimos en los que se almacenará la base de datos, pero como ya vimos anteriormente se puede almacenar en más archivos, los tenemos que definir todos en esta ventana a continuación de los dos obligatorios.

Para añadir más archivos físicos disponemos del botón Agregar.

Al pulsar el botón Agregar se crea una nueva fila en la tabla de archivos físicos donde deberemos escribir el nombre del archivo, su tipo (desplegando la lista podemos elegir entre de datos o de registro) y demás parámetros.

Al agregar un nuevo archivo se activa el botón Quitar, siempre que estemos posicionados encima de un archivo secundario para poder así eliminarlo si lo queremos.

9

Page 10: Curso de SQL Server.docx

No podemos eliminar ni el de datos primario, ni el de registro inicial.

Unidad 1. El entorno gráfico SSMS (IV)

Si nos fijamos en la zona de la izquierda, vemos que nos encontramos en la pestaña General, podemos cambiar otros parámetros de la base de datos pulsando en Grupos de archivos o en Opciones:

Al final pulsamos en Aceptar y se creará la base de datos.

10

Page 11: Curso de SQL Server.docx

Aparecerá dentro de la carpeta Bases de datos. Si no se ve pulsa en el icono

Actualizar .

Desde el Explorador de Windows podemos ver que en la carpeta indicada se han creado los archivos físicos con los nombres que le hemos indicado.

Unidad 1. El entorno gráfico SSMS (V)

1.6. Adjuntar una base de datos

En ocasiones no necesitaremos crear la base de datos desde cero, porque ésta ya estará creada. Éste es el caso de los ejercicios del curso. Para realizarlos, deberás adjuntar una base de datos ya existente a tu servidor. Para ello, lo que tenemos que hacer es pegar los archivos en la ubicación que queramos, y luego indicar al SQL Server que vamos a utilizar esta base de datos, de la siguiente manera:En el Explorador de objetos, sobre la carpeta Bases de datos desplegar el menú contextual y elegir Adjuntar...

En la siguiente ventana elegimos la base de datos:

11

Page 12: Curso de SQL Server.docx

Pulsando en Agregar indicamos el archivo de datos primario en su ubicación y automáticamente se adjuntará la base de datos lógica asociada a este archivo.

Finalmente pulsamos en Aceptar y aparece la base de datos en nuestro servidor.

12

Page 13: Curso de SQL Server.docx

La opción Adjuntar sólo se utiliza la primera vez, cuando todavía no tenemos la base de datos en el disco.

Realiza el siguiente Ejercicio Adjuntar base de datos. En él adjuntarás las bases de datos que vas a utilizar en los ejercicios que se plantearán más adelante.

1.7. Conectar y Desconectar la base de datos

Una vez hemos creado la base de datos o la hemos adjuntado a nuestro servidor, nos daremos cuenta de que no podremos manipular los archivos de la base desde fuera del gestor SSMS, por ejemplo, desde el Explorador de Windows. Es decir, no podremos copiar, cortar, mover o eliminar los archivos fuente mdf, ndf y ldf. Si lo intentamos se mostrará un aviso de que la base de datos está en uso.

Esto es así porque SQL Server sigue en marcha, a pesar de que se cierre el gestor. Ten en cuenta que el servidor de base de datos normalmente se crea para que sirva información a diferentes programas, por eso sería absurdo que dejara de funcionar cuando cerramos el programa gestor, que sólo se utiliza para realizar modificaciones sobre la base.

Para poder realizar acciones sobre la base de datos, ésta debe estar desconectada. Para ello, desde el SSMS, desplegamos el menú contextual de la base de datos que nos interese manipular y seleccionaremos la opción Poner fuera de conexión:

Aparecerá un símbolo a la izquierda de la base de datos indicándonos que la base de datos  está desconectada, a partir de este momento Windows nos dejará manipular los archivos.

Para volver a conectar la base de datos y seguir trabajando con ella, accederemos al mismo menú contextual pero elegiremos la opción Poner en conexión:

13

Page 14: Curso de SQL Server.docx

El caso más inmediato en el que puedes necesitar conectar y desconectar la base de datos es copiar a un pendrive los archivos de las bases que utilizarás en los ejercicios para poder trabajar en diferentes ordenadores con ellos. Para aprender cómo hacerlo, visita el siguiente Ejercicio Trasladar una base de datos a otro equipo.

En caso de que tu versión de SQL Server no tenga las opciones Poner en conexión y Poner fuera de conexión, deberás utilizar la opción Separar... y luego volver a adjuntarla.

Unidad 1. El entorno gráfico SSMS (VI)

1.8. Crear una nueva tabla

Para crear una nueva tabla primero nos tenemos que posicionar en la base de datos donde queremos que se almacene la tabla, desplegar el menú contextual y seleccionar la opción Nueva tabla.

En la ventana que se abre debemos definir las columnas de la tabla:

14

Page 15: Curso de SQL Server.docx

A cada columna se le asigna un nombre, un tipo de datos, y opcionalmente una serie de propiedades, en este tema veremos las básicas y las demás las veremos con más detalle cuando veamos la instrucción SQL CREATE TABLE.

De momento no tenemos definida ninguna columna, al teclear un nombre se crea una primera entrada en esta tabla con la definición de la primera columna. En la columna Tipo de datos elegimos qué tipo de valores se podrán almacenar en la columna.

1.9. Tipos de datos

Podemos elegir entre todos los tipos que aparecen arriba.

Algunos tipos no necesitan más, como por ejemplo el tipo entero (int), y otros se pueden completar con una longitud, como los tipos alfanuméricos:

En este ejemplo hemos definido una columna (Codigo) de tipo Entero corto (Smallint), y una columna (Nombre) que almacenará hasta 20 caracteres alfanuméricos (nchar(20)),

15

Page 16: Curso de SQL Server.docx

en este caso la longitud la indicamos en la pestaña Propiedades de columna en la propiedad Longitud.

Las propiedades de la columna pueden variar dependiendo del tipo de datos de la columna seleccionada, por ejemplo los campos enteros no tienen la propiedad longitud, ya que el propio tipo define la longitud del campo, en cambio los campos de tipo numeric  o decimal no tiene la propiedad longitud pero sí las propiedades escala y precisión, los valores que permiten definir el tamaño del campo.

Unidad 1. El entorno gráfico SSMS (VII)

1.10. Valores nulos

También podemos indicar si la columna permitirá valores nulos o no, o bien cambiando la propiedad Permitir valores nulos que aparece debajo de la propiedad Longitud, o bien simplemente marcando o desmarcando la casilla de la columna Permitir valores nulos que se encuentra al lado de la columna Tipo de datos. Si la casilla está marcada, el usuario podrá no rellenar el campo cuando inserte una fila de datos en la tabla.

1.11. Columna con contador

En la mayoría de los sistemas gestores de bases de datos tenemos un tipo de datos de tipo contador, autonumérico, autoincremental, etc. Este tipo hace que el propio sistema es el encargado de rellenar el campo con un valor que va incrementando conforme se crean más filas de datos en la tabla.

Las columnas de este tipo se utilizan normalmente para numerar las filas de la tabla, como no habrán dos filas con el mismo valor (el sistema se encarga de incrementar el valor cada vez que se crea una nueva fila), estos campos se suelen utilizar como claves primarias.

En SQL Server 2005 no existe el tipo de datos Contador pero se consigue el mismo funcionamiento asignando a la columna un tipo de datos numérico y definiendo la columna como columna de identidad.

16

Page 17: Curso de SQL Server.docx

En las propiedades de la columna marcamos Sí en la propiedad (Identidad) y a continuación podemos indicar en qué valor queremos que empiece el contador (Inicialización de identidad) y en cuánto incrementará cada vez que se cree un nuevo registro (Incremento de identidad).

Aunque este tipo de columnas se utiliza frecuentemente como clave primaria, SQL Server no le asigna automáticamente esta función, la tenemos que definir nosotros mismos, pero sí fuerza a que sea una columna sin valores nulos. No se puede definir más de una columna de identidad por tabla.

1.12. Clave primaria

Para definir una columna como clave primaria, posicionamos el puntero del ratón sobre la columna, desplegamos el menú contextual y seleccionamos la opción Establecer Clave principal:

Aparecerá una llave a la izquierda del nombre, símbolo de las claves principales:

Para definir una clave primaria compuesta por varias columnas, seleccionamos las columnas manteniendo pulsada la tecla Ctrl y luego seleccionamos la opción.

Para quitar una clave principal, hacemos lo mismo pero en esta ocasión seleccionamos la opción Quitar clave principal.

También podemos utilizar el icono de la barra de herramientas.

Unidad 1. El entorno gráfico SSMS (VIII)

1.13. Añadir o eliminar columnas

Una vez definidas algunas columnas, si queremos añadir una nueva columna entre dos, nos posicionamos en la segunda y seleccionamos la opción Insertar columna del menú contextual.

17

Page 18: Curso de SQL Server.docx

La nueva columna se colocará delante:

Del mismo modo si queremos eliminar la definición de una columna, nos posicionamos en la columna a eliminar y seleccionamos la opción Eliminar columna:

 O simplemente hacemos clic en la zona a la izquierda del nombre y pulsamos la tecla Supr.

Finalmente guardamos la tabla, nos pedirá el nombre de la tabla:

La nueva tabla aparecerá en la lista de tablas de la base de datos:

1.14. Modificar la definición de una tabla

18

Page 19: Curso de SQL Server.docx

Para entrar a la ventana de definición de la tabla utilizamos la opción Modificar de su menú contextual (También es posible que se llame Diseño):

Se abrirá la ventana que ya conocemos para definir las columnas de la tabla.

Unidad 1. El entorno gráfico SSMS (IX)

1.15. Insertar datos en la tabla

Ahora que tenemos la tabla creada podemos rellenarla con datos. Para eso debemos abrir la tabla:

Se abrirá una ventana parecida a esta:

La primera columna sirve para indicarnos el estado de una fila, por ejemplo el * nos indica que es una nueva fila, esta fila realmente no está en la tabla, nos sirve de contenedor para los nuevos datos que queremos insertar.

Para insertar una nueva fila de datos sólo tenemos que rellenar los campos que aparecen en esa fila (la del *), al cambiar de fila los datos se guardarán automáticamente en la tabla a no ser que alguno infrinja alguna regla de integridad, en ese caso SQL Server nos devuelve un mensaje de error para que corrijamos el dato erróneo, si no lo podemos corregir entonces sólo podemos deshacer los cambios.

1.16. Modificar datos

Para modificar un valor que ya está en una fila de la tabla sólo tenemos que posicionarnos en el campo y rectificar el valor. En cuanto modificamos un valor, la fila aparece con un lápiz escribiendo (ver imagen), este lápiz nos indica que la fila se ha modificado y tiene nuevos datos por guardar. Al salir de la fila ésta se guardará automáticamente a no ser que el nuevo valor infrinja alguna regla de integridad. Si queremos salir de la fila sin guardar los cambios, tenemos que cancelar la actualización pulsando la tecla ESC.

19

Page 20: Curso de SQL Server.docx

1.17. Eliminar filas

Para eliminar una fila completa, la seleccionamos y pulsamos la tecla Supr o bien desplegamos su menú contextual y seleccionamos la opción Eliminar.

En cualquiera de los dos casos nos aparece un mensaje de confirmación.

1.18. Relacionar tablas

Como ya hemos visto, en una base de datos relacional, las relaciones entre las tablas se implementan mediante la definición de claves ajenas, que son campos que contienen valores que señalan a un registro en otra tabla, en esta relación así creada, la tabla referenciada se considera principal y la que contiene la clave ajena es la subordinada.

Desde el entorno gráfico del SSMS podemos definir claves ajenas entrando en el diseño de la tabla y desplegando el menú contextual del campo que va a ser clave ajena:

Seleccionamos la opción Relaciones y se abre la ventana:

20

Page 21: Curso de SQL Server.docx

Al pulsar el botón que se encuentra en la fila Especificación de tablas y columnas se abre el diálogo donde definiremos la relación:

Unidad 1. El entorno gráfico SSMS (X)

En la parte derecha tenemos la tabla en la que estamos y el campo que va a actuar como clave ajena, sólo nos queda elegir en el desplegable de la izquierda la tabla a la que hace referencia la clave y al seleccionar una tabla, a la izquierda del campo clave ajena podremos elegir el campo de la otra tabla por el que se relacionarán las tablas. En nuestro caso será:

De esta forma hemos definido una relación entre las tablas Facturas y Clientes. Para ver las relaciones existentes entre las diferentes tablas tenemos los diagramas.

21

Page 22: Curso de SQL Server.docx

Primero debemos definir el diagrama, para ello seleccionamos la opción correspondiente:

Si no tenemos todavía ningún diagrama creado, nos aparece un mensaje:

Elegimos Sí y se crea digamos el soporte donde se pintará el diagrama.

A continuación nos aparece el nuevo diagrama ahora si elegimos crear un nuevo diagrama nos preguntará las tablas a incluir en el diagrama:

Seleccionamos cada una y pulsamos Agregar, cuando hayamos agregado al diagrama todas las que queremos pulsamos en Cerrar y aparecerán en el diagrama las tablas con las relaciones que tengan definidas en ese momento:

22

Page 23: Curso de SQL Server.docx

La llave indica la tabla principal (padre) y el símbolo infinito señala la tabla que contiene la clave ajena.

En el examinador de objetos en la carpeta Diagramas de base de datos aparecen todos los diagramas definidos hasta el momento:

Hemos aprendido hasta ahora lo básico para poder crear una base de datos y rellenarla con tablas relacionadas entre sí y con datos, ahora veamos cómo recuperar esos datos.

Unidad 1. El entorno gráfico SSMS (XI)

1.19. Abrir una nueva consulta

Vamos a ver ahora cómo crear consultas SQL y ejecutarlas desde el entorno del SSMS.

Para ello debemos abrir la zona de trabajo de tipo Query, abriendo una nueva consulta,

seleccionando previamente el servidor y pulsando el botón  de la barra de botones o si queremos realizar la consulta sobre un servidor con el cual todavía no hemos establecido conexión, seleccionando de la barra de menús la opción Nuevo > Consulta de motor de base de datos:

23

Page 24: Curso de SQL Server.docx

.

En este último caso nos aparecerá el cuadro de diálogo para establecer la conexión (el mismo que vimos al principio del tema).

A continuación se abrirá una nueva pestaña donde podremos teclear las sentencias SQL:

Además aparece una nueva barra de botones que nos permitirá ejecutar los comandos más útiles del modo query.

1.20. Escribir y ejecutar  código TRANSACT-SQL

Sólo tenemos que teclear la sentencia a ejecutar, por ejemplo empezaremos por crear la base de datos.

Utilizaremos la sentencia CREATE DATABASE mínima:

CREATE DATABASE ventas;

Al pulsar el botón Ejecutar se ejecuta la sentencia y aparece en la parte inferior el resultado de la ejecución, en la pestaña Mensajes:

24

Page 25: Curso de SQL Server.docx

Si ahora desplegamos la carpeta Bases de Datos del Explorador de Objetos, observaremos la base de datos que hemos creado:

Si la ejecución de la sentencia produce un error, el sistema nos devolverá el mensaje de error escrito en rojo en la pestaña Mensajes.

Podemos incluir en una misma consulta varias sentencias SQL, cuando pulsamos Ejecutar se ejecutarán todas una detrás de otra. Si tenemos varias consultas y sólo queremos ejecutar una, la seleccionaremos antes de ejecutarla.

Unidad 1. El entorno gráfico SSMS (XII)

1.21. La base de datos predeterminada

Cuando ejecutamos consultas desde el editor, nos tenemos que fijar sobre qué base de datos se va a actuar.

25

Page 26: Curso de SQL Server.docx

Fijándonos en la pestaña de la consulta, en el nombre aparece el nombre del servidor seguido de un punto y el nombre de la base de datos sobre la que se va a actuar y luego un guión y el nombre de la consulta.

En la imagen anterior tenemos ord01.master – SQLQuery1.sql, lo que nos indica que la consulta se llama SQLQuery1.sql, y que se va a ejecutar sobre la base de datos master que se encuentra en el servidor ord01.

Cuando creamos una nueva consulta, ésta actuará sobre la base de datos activa en ese momento. Por defecto la base de datos activa es la predeterminada (master). Si queremos que la base de datos activa sea por ejemplo la base de datos ventas,  hacemos clic sobre su nombre en el Explorador de objetos, y ésta pasará a ser la base de datos activa. Si ahora creamos una nueva consulta, ésta actuará sobre la base de datos ventas.

Si  queremos crear una consulta que siempre actúe sobre una determinada base de datos y no nos queremos preocupar de qué base de datos tenemos activa podemos añadir al principio de la consulta la instrucción USE nombreBaseDatos; esto hará que todas las instrucciones que aparezcan después, se ejecuten sobre la base de datos indicada.Por ejemplo:

USE ventas;

SELECT * FROM pedidos;

Obtiene todos los datos de la tabla pedidos que se encuentra en la base de datos ventas.Si no utilizamos USE y almacenamos la consulta, al abrirla otra vez, cogerá como base de datos la predeterminada (no la activa) y se volverá a ejecutar sobre la base de datos master.

Normalmente utilizaremos como base de datos la nuestra y no la base de datos master, por lo que nos será útil cambiar el nombre de la base de datos por defecto, esto lo podemos hacer cambiando la base de datos por defecto en el id de sesión.

Para ello, cuando vamos a conectar con el servidor:

Pulsamos en el botón Opciones >>

26

Page 27: Curso de SQL Server.docx

En la pestaña Propiedades de conexión, en el cuadro Conectar con base de datos: Seleccionamos <Examinar servidor > para elegir la base de datos.

La elegimos y aceptamos. A partir de ese momento la base de datos elegida será la que SQL Server coja por defecto en todas las sesiones de ese usuario.

Unidad 1. El entorno gráfico SSMS (XIII)

1.22. El editor de texto

27

Page 28: Curso de SQL Server.docx

Para facilitarnos la redacción y corrección de las sentencias, el editor de SQL presenta las palabras de distintos colores según su categoría y podemos utilizar el panel Explorador de Objetos para arrastrar desde él los objetos sobre la zona de trabajo y así asegurarnos de que los nombres de los objetos (por ejemplo nombre de tabla, de columna, etc.) sean los correctos.

Como hemos dicho el texto que se escribe en este editor de código se colorea por categoría. Los colores son los mismos que se utilizan en todo el entorno SQL Server. En esta tabla aparecen los colores más comunes.

Color Categoría

Rojo Cadena de caracteres

Verde oscuro Comentario

Negro sobre fondo plateado Comando SQLCMD

Fucsia Función del sistema

Verde Tabla del sistema

Azul Palabra clave

Verde azulado Números de línea o parámetro de plantilla

Rojo oscuro Procedimiento almacenado de SQL Server

Gris oscuro Operadores

1.23. Configurar un esquema de colores personalizado

En el menú Herramientas > Opciones, desplegando la opción Entorno, Fuentes y colores, se puede ver la lista completa de colores y sus categorías, así como configurar un esquema de colores personalizado:

28

Page 29: Curso de SQL Server.docx

En la lista Mostrar valores para, seleccionamos el entorno que se verá afectado.

El botón  Usar predeterminados nos permite volver a la configuración predeterminada.

Ahora sólo nos queda aprender a redactar sentencias SQL, cosa que se verá en otro momento, mientras tanto podemos utilizar el Generador de Consulta que incluye SSMS y que veremos a continuación en el apartado sobre vistas.

1.24. Las Vistas

Las consultas que hemos visto hasta ahora son trozos de código SQL que podemos guardar en un archivo de texto y abrir y ejecutar cuando queramos, pero si queremos que nuestra consulta de recuperación de datos se guarde en la propia base de datos y se comporte como una tabla (algo parecido a una consulta almacenada de Access), la tenemos que definir como una vista. Esta vista tiene la ventaja entre otras de poder ser utilizada como si fuese una tabla en otras consultas. Realmente al ejecutarla obtenemos una tabla lógica almacenada en memoria y lo que se guarda en la base de datos es su definición, la instrucción SQL que permite recuperar los datos.

29

Page 30: Curso de SQL Server.docx

Para definir una vista en el Explorador de Objetos desplegamos la base de datos donde la guardaremos y elegimos la opción Nueva vista del menú contextual de la carpeta Vistas, se pondrá en funcionamiento el generador de consultas pidiéndonos las tablas en las que se basará la vista. Pulsamos sobre la tabla a añadir al diseño de la vista y pulsamos el botón Agregar, podemos añadir así cuántas tablas queramos.

Después de Cerrar, vemos a la derecha del Explorador de Objetos la pestaña con la definición de la vista que puede incluir varios paneles:

La aparición de estos paneles es configurable, en la barra de herramientas Diseñador de vistas los iconos remarcados en azul son los correspondientes a cada panel:

30

Page 31: Curso de SQL Server.docx

Unidad 1. El entorno gráfico SSMS (XIV)

Nosotros, a lo largo del curso, crearemos las vistas desde el panel SQL que veremos más adelante.

1.25. El panel de diagrama

 Es el primero que aparece, incluye una representación gráfica de las tablas con sus campos y de la forma en que se juntan en la vista. En este caso, como las tablas tienen relaciones definidas (claves ajenas), esta relación ha aparecido automáticamente al añadir la segunda tabla. Pero se puede cambiar el tipo de relación eligiendo la opción correspondiente en el menú contextual que aparece con el clic derecho sobre la relación:

Desde el panel diagrama podemos añadir cómodamente campos de las tablas a la consulta marcando la casilla correspondiente. En la imagen anterior la única casilla seleccionada es la del * en la tabla Libros por lo que se visualizarán todas las columnas de la tabla Libros y ninguna de la tabla Préstamos.

Conforme vamos marcando casillas de las tablas del panel diagrama, los cambios se ven reflejados en los demás paneles excepto en el panel de resultados que se actualiza ejecutando la consulta.

1.26. El panel de criterios

Es una rejilla en la que podemos definir las columnas del resultado de la consulta (las columnas de la vista).

31

Page 32: Curso de SQL Server.docx

En cada fila de la rejilla se define una columna del resultado o una columna que se utiliza para obtener el resultado.

En Columna tenemos el nombre de la columna de la se obtienen los datos o la expresión cuando se trata de una columna calculada.

En Alias escribimos el nombre que tendrá la columna en la vista, también corresponde con el encabezado de la columna en la rejilla de resultado. Si se deja el campo en blanco, por defecto se asume el mismo nombre que hay en Columna.

En Tabla tenemos el nombre de la tabla del origen de la consulta a la que pertenece la Columna, por ejemplo la primera columna del resultado se saca de la columna Codigo de la tabla LIBROS y se llamará CodLibro. La cuarta columna de la vista cogerá sus datos de la columna Usuario de la tabla Prestamos y se llamará Usuario (Alias se ha dejado en blanco por lo que asume el nombre que hay en Columna.

En la columna Resultados indicamos si queremos que la columna se visualice o no, las columnas con la casilla marcada se visualizan.

Las columnas Criterio de ordenación y Tipo de orden permiten ordenar las filas del resultado según una o más columnas. Se ordena por las columnas que tienen algo en Tipo de orden y cuando se ordena por varias columnas Criterio de ordenación indica que primero se ordena por la columna que lleva el nº 1 y después por la columna que lleva el nº 2 y así sucesivamente. En el ejemplo las filas del resultado se ordenarán primero por código de libro y después por código de préstamo, todas las filas dentro del mismo libro se ordenarán por código de préstamo.

Si queremos añadir unos criterios de selección tenemos las columnas Filtro y O…

 

En cada celda indicamos una condición que debe cumplir la columna correspondiente y se puede combinar varias condiciones mediante O (OR) e Y (AND) según coloquemos las condiciones en la misma columna  o en columnas diferentes. En el ejemplo anterior tenemos la condición compuesta: ((usuario=1) AND (Dias>5)) OR (Usuario=2).

Podemos variar el orden de aparición de las columnas arrastrando la fila correspondiente de la rejilla hasta el lugar deseado.

32

Page 33: Curso de SQL Server.docx

También podemos Elimnar filas de la rejilla para eliminar columnas del resultado, lo conseguimos seleccionando la fila haciendo clic sobre su extremo izquierda y cuando aparece toda la fila remarcada pulsamos Supr o desde el menú contextual de la fila.

Podemos definir consultas más complejas como por ejemplo consultas de resumen, pulsando sobre el botón Agrupar por de la barra de herramientas, se añade a la rejilla una nueva columna Agrupar por con las siguientes opciones:

Unidad 1. El entorno gráfico SSMS (XV)

1.27. El panel SQL

En él vemos la instrucción SQL generada, también podemos redactar directamente la sentencia SQL en el panel y ver los cambios equivalentes en los distintos paneles. Para ver estos cambios debemos de ejecutar o Comprobar la sintaxis para que se actualicen los demás paneles.

Por defecto el generador añade a la consulta una cláusula TOP (100) PERCENT que indica que se visualizarán el 100% de las filas. Esta cláusula no la hemos definido nosotros sino que la añade automáticamente el generador.

Una vez tenemos la vista definida la guardamos y podremos hacer con ella casi todo lo que podemos hacer con una tabla. De hecho si nos fijamos en el Explorador de objetos, en la carpeta Vistas:

33

Page 34: Curso de SQL Server.docx

Vemos que la estructura es muy similar a la estrutura de una tabla. Y que podemos modificar su definición y ejecutarla, igual que con las tablas:

Modificar para modificar la definición de la vista

Abrir vista para ejecutarla y ver los datos como si fuese una tabla real.

Unidad 2. Introducción al SQL. Transact-SQL (I)

2.1. Conceptos básicos de SQL

SQL (Structured Query Language), Lenguaje Estructurado de Consulta es el lenguaje utilizado para definir, controlar y acceder a los datos almacenados en una base de datos relacional.

Como ejemplos de sistemas gestores de bases de datos que utilizan SQL podemos citar DB2, SQL Server, Oracle, MySql, Sybase, PostgreSQL o Access.

El SQL es un lenguaje universal que se emplea en cualquier sistema gestor de bases de datos relacional. Tiene un estándar definido, a partir del cual cada sistema gestor ha desarrollado su versión propia.

En SQL Server la versión de SQL que se utiliza se llama TRANSACT-SQL.

EL SQL en principio es un lenguaje orientado únicamente a la definición y al acceso a los datos por lo que no se puede considerar como un lenguaje de programación como tal ya que no incluye funcionalidades como son estructuras condicionales, bucles, formateo de la salida, etc. (aunque veremos que esto está evolucionando).

Se puede ejecutar directamente en modo interactivo, pero también se suele emplear embebido en programas escritos en lenguajes de programación convencionales. En estos programas se mezclan las instrucciones del propio lenguaje (denominado anfitrión) con

34

Page 35: Curso de SQL Server.docx

llamadas a procedimientos de acceso a la base de datos que utilizan el SQL como lenguaje de acceso. Como por ejemplo en Visual Basic, Java, C#, PHP .NET, etc.

Las instrucciones SQL se clasifican según su propósito en tres grupos:

El DDL (Data Description Language) Lenguaje de Descripción de Datos.

El DCL (Data Control Language) Lenguaje de Control de Datos.

El DML (Data Manipulation Language) Lenguaje de Manipulación de Datos.

El DDL, es la parte del SQL dedicada a la definición de la base de datos, consta de sentencias para definir la estructura de la base de datos, permiten crear la base de datos, crear, modificar o eliminar la estructura de las tablas, crear índices, definir reglas de validación de datos, relaciones entre las tablas, etc. Permite definir gran parte del nivel interno de la base de datos. Por este motivo estas sentencias serán utilizadas normalmente por el administrador de la base de datos.

El DCL (Data Control Language) se compone de instrucciones que permiten:

Ejercer un control sobre los datos tal como la asignación de privilegios de acceso a los datos (GRANT/REVOKE).

La gestión de transacciones (COMMIT/ROLLBACK).

Una transacción se puede definir como un conjunto de acciones que se tienen que realizar todas o ninguna para preservar la integridad de la base de datos.Por ejemplo supongamos que tenemos una base de datos para las reservas de avión. Cuando un usuario pide reservar una plaza en un determinado vuelo, el sistema tiene que comprobar que queden plazas libres, si quedan plazas reservará la que quiera el usuario generando un nuevo billete y marcando la plaza como ocupada. Aquí tenemos un proceso que consta de dos operaciones de actualización de la base de datos (crear una nueva fila en la tabla de billetes y actualizar la plaza reservada en el vuelo, poniéndola como ocupada) estas dos operaciones se tienen que ejecutar o todas o ninguna, si después de crear el billete no se actualiza la plaza porque se cae el sistema, por ejemplo, la base de datos quedaría en un estado inconsistente ya que la plaza constaría como libre cuando realmente habría un billete emitido para esta plaza. En este caso el sistema tiene el mecanismo de transacciones para evitar este error. Las operaciones se incluyen las dos en una misma transacción y así el sistema sabe que las tiene que ejecutar las dos, si por lo que sea no se pueden ejecutar las dos, se encarga de deshacer los cambios que se hubiesen producido para no ejecutar ninguna.

Las instrucciones que gestionan las autorizaciones serán utilizadas normalmente por el administrador mientras que las otras, referentes a proceso de transacciones serán utilizadas también por los programadores.

No todos los sistemas disponen de ellas.

El DML se compone de las instrucciones para el manejo de los datos, para insertar nuevos datos, modificar datos existentes, para eliminar datos y la más utilizada, para recuperar datos de la base de datos. Veremos que una sola instrucción de recuperación de datos es tan potente que permite recuperar datos de varias tablas a la vez, realizar cálculos sobre estos datos y obtener resúmenes.

El DML interactúa con el nivel externo de la base de datos por lo que sus instrucciones son muy parecidas, por no decir casi idénticas, de un sistema a otro, el usuario sólo indica lo que quiere recuperar no cómo se tiene que recuperar, no influye el cómo están almacenados los datos.

Es el lenguaje que utilizan los programadores y los usuarios de la base de datos.

35

Page 36: Curso de SQL Server.docx

A lo largo del curso se explicarán cada una de las formas de explotación de la base de datos. Dependiendo de tu perfil profesional (programador o administrador) o de tu interés personal te resultará más útil un bloque u otro.

2.2. Introducción al TRANSACT-SQL

Como hemos dicho, el sistema gestor de base de datos SQL-Server 2005 utiliza su propia versión del lenguaje SQL, el TRANSACT-SQL.

TRANSACT-SQL es un lenguaje muy potente que nos permite definir casi cualquier tarea que queramos efectuar sobre la base de datos.  En este tema veremos que TRANSACT-SQL va más allá de un lenguaje SQL cualquiera ya que incluye características propias de cualquier lenguaje de programación, características que nos permiten definir la lógica necesaria para el tratamiento de la información:

Tipos de datos.

Definición de variables.

Estructuras de control de flujo.

Gestión de excepciones.

Funciones predefinidas.

Sin embargo no permite:

Crear interfaces de usuario.

Crear aplicaciones ejecutables, sino elementos que en algún momento llegarán al servidor de datos y serán ejecutados.

Debido a estas restricciones se emplea generalmente para crear procedimientos almacenados, triggers y  funciones de usuario.

Puede ser utilizado como cualquier SQL como lenguaje embebido en aplicaciones desarrolladas en otros lenguajes de programación como Visual Basic, C, Java, etc. Y por supuesto los lenguajes incluidos en la plataforma .NET.

También lo podremos ejecutar directamente de manera interactiva, por ejemplo desde el editor de consultas de SSMS (SQL Server Management Studio) el entorno de gestión que ya conocemos. Esta es la forma en que lo utilizaremos nosotros.

Unidad 2. Introducción al SQL. Transact-SQL (II)

2.3. Características generales del lenguaje Transact-SQL

El lenguaje SQL se creó con la finalidad de ser un lenguaje muy potente y a la vez muy fácil de utilizar, se ha conseguido en gran medida ya que con una sola frase (instrucción) podemos recuperar datos complejos (por ejemplo datos que se encuentran en varias tablas, combinándolos, calculando resúmenes), y utilizando un lenguaje muy cercano al lenguaje hablado (¡suponiendo que hablamos inglés, claro!).

Por ejemplo:

SELECT codigo, nombre FROM Clientes WHERE localidad=’Valencia’;

Esta instrucción nos permite SELECCIONAR el código y nombre DE los Clientes CUYA localidad sea Valencia.

36

Page 37: Curso de SQL Server.docx

La sencillez también radica en que lo que indicamos es lo que queremos obtener, no el cómo lo tenemos que obtener, de eso se encargará el sistema automáticamente.

Las sentencias SQL además siguen todas el mismo patrón:

Empiezan por un verbo que indica la acción a realizar,

completado por el objeto sobre el cual queremos realizar la acción,

seguido de una serie de cláusulas (unas obligatorias, otras opcionales) que completan la frase, y proporcionan más detalles acerca de lo que se quiere hacer.

Si sabemos algo de inglés nos será más fácil interpretar a la primera lo que quiere decir la instrucción, y de lo contrario, como el número de palabras que se emplean es muy reducido, enseguida nos las aprenderemos.

Por ejemplo en el DDL (acciones sobre la definición de la base de datos), tenemos 3 verbos básicos:

CREATE (Crear)

DROP (Eliminar)

ALTER (Modificar)

Completados por el tipo de objeto sobre el que actúan y el objeto concreto:

CREATE DATABASE mibase .......;

Permite crear una base de datos llamada mibase, a continuación escribiremos las demás cláusulas que completarán la acción, en este caso dónde se almacenará la base de datos, cuánto ocupará, etc...

CREATE TABLE mitabla (.....);

Permite crear una nueva tabla llamada mitabla, entre paréntesis completaremos la acción indicando la definición de las columnas de la tabla.

CREATE INDEX miindex...;

Lo mismo para crear un índice (¿a que lo habíais adivinado?).

DROP DATABASE  mibase;

Permite borrar, eliminar la base de datos mibase.

DROP TABLE mitabla;

Elimina la tabla mitabla.

ALTER TABLE mitabla.....;

Permite modificar la definición de la tabla mitabla.

En el DML (acciones sobre los datos almacenados) utilizaremos los verbos:

INSERT (Crear, es decir, insertar una nueva fila de datos)

DELETE (Eliminar filas de datos)

UPDATE (Modificar filas de datos)

37

Page 38: Curso de SQL Server.docx

SELECT (Seleccionar, obtener)

Por ejemplo:

INSERT INTO mitabla ..... Inserta nuevas filas en mitabla

DELETE FROM mitabla Eliminar filas de mitabla

UPDATE mitabla ....... Actualiza filas de mitabla

Como ejemplo de cláusula dentro de una instrucción tenemos:

SELECT codigo, nombre FROM Clientes WHERE localidad=’Valencia’;

En esta sentencia nos aparecen dos cláusulas, la cláusula FROM que nos permite indicar de dónde hay que coger los datos y la cláusula WHERE que permite indicar una condición de selección.

Otra característica de una sentencia SQL es que acaba con un punto y coma (;) originalmente éste era obligatorio y servía para indicar el fin de la instrucción, pero ahora se puede omitir, aunque se recomienda su uso.

En una sentencia utilizaremos palabras reservadas (las fijas del lenguaje), y nombres de objetos y variables (identificadores).

Las palabras reservadas no se pueden utilizar para otro propósito, por ejemplo una tabla no se puede llamar FROM, y los nombres (los identificadores) siguen las reglas detalladas en el punto siguiente.

Nombres cualificados. En ocasiones deberemos utilizar nombres cualificados, por ejemplo cuando se escribe un nombre de tabla, SQL presupone que se está refiriendo a una de las tablas de la base de datos activa, si queremos hacer referencia a una tabla de otra base de datos utilizamos su nombre cualificado nombrebasedatos.nombredeesquema.nombretabla, utilizamos el punto para separar el nombre del objeto y el nombre de su contenedor.

O por ejemplo si en una consulta cuyo origen son dos tablas, queremos hacer referencia a un campo y ese nombre de campo es un nombre de campo en las dos tablas, pues utilizaremos su nombre cualificado nombretabla.nombrecampo.

El valor NULL.

Puesto que una base de datos es un modelo de una situación del mundo real, ciertos datos pueden inevitablemente faltar, ser desconocidos o no ser aplicables, esto se debe de indicar de alguna manera especial para no confundirlo con un valor conocido pero que sea cero por ejemplo, SQL tiene para tal efecto el valor NULL que indica precisamente la ausencia de valor.

Por ejemplo: no es lo mismo que el alumno no tenga nota a que tenga la nota cero, esto afectaría también a todos los cálculos que se pueden realizar sobre la  columna nota.

38

Page 39: Curso de SQL Server.docx

Unidad 2. Introducción al SQL. Transact-SQL (III)

2.4. Reglas de formato de los identificadores

Los identificadores son los nombres de los objetos de la base de datos. Cualquier elemento de Microsoft SQL Server 2005 puede tener un identificador: servidores, bases de datos, tablas, vistas, columnas, índices, desencadenadores, procedimientos, restricciones, reglas, etc.

Las reglas de formato de los identificadores normales dependen del nivel de compatibilidad de la base de datos, que se establecía con el parámetro sp_dbcmptlevel pero que ahora Microsoft aconseja no utilizar ya que desaparecerá en versiones posteriores en vez de eso se tiene que utilizar la cláusula SET COMPATIBILITY_LEVEL de la instrucción ALTER TABLE. Cuando el nivel de compatibilidad es 90, (el asignado por defecto) se aplican las reglas siguientes para los nombres de los identificadores:

No puede ser una palabra reservada.

El nombre debe tener entre 1 y 128 caracteres, excepto para algunos tipos de objetos en los que el número es más limitado.

El nombre debe empezar por:

o Una letra, como aparece definida por el estándar Unicode 3.2. La definición Unicode de letras incluye los caracteres latinos de la "a" a la "z" y de la "A" a la "Z".

o El carácter de subrayado ( _ ), arroba ( @ ) o número ( # ).

Ciertos símbolos al principio de un identificador tienen un significado especial en SQL Server. Un identificador que empieza con el signo de arroba indica un parámetro o una variable local. Un identificador que empieza con el signo de número indica una tabla o procedimiento temporal. Un identificador que empieza con un signo de número doble (##) indica un objeto temporal global.

Algunas funciones de Transact-SQL tienen nombres que empiezan con un doble signo de arroba (@@). Para evitar confusiones con estas funciones, se recomienda no utilizar nombres que empiecen con @@.

No se permiten los caracteres especiales o los espacios incrustados.

Si queremos utilizar un nombre que no siga estas reglas, normalmente para poder incluir espacios en blanco, lo tenemos que escribir encerrado entre corchetes [ ] (también se pueden utilizar las comillas pero recomendamos utilizar los corchetes).

2.5. Tipos de datos

En SQL Server 2005, cada columna, expresión, variable y parámetro está asociado a un tipo de datos. Un tipo de datos, realmente define el conjunto de valores válidos para los campos definidos de ese tipo. Indica si el campo puede contener: datos numéricos, de caracteres, moneda, fecha y hora, etc.

SQL Server proporciona un conjunto de tipos de datos del sistema que define todos los tipos de datos que pueden utilizarse. También podemos definir nuestros propios tipos de datos en Transact-SQL o Microsoft .NET Framework.

Los tipos de datos más utilizados son:

Los numéricos: int, decimal, money

39

Page 40: Curso de SQL Server.docx

Los de fecha y hora: datetime

Y las cadenas de caracteres: varchar

Si quieres conocer todos los tipos de datos disponibles en SQLServer 2005, visita el

siguiente avanzado .

2.6. Las constantes

Una constante es un valor específico o un símbolo que representa un valor de dato específico. El formato de las constantes depende del tipo de datos del valor que representan. En este apartado veremos las más utilizadas.

Las constantes numéricas se escriben mediante una cadena de números, con la consideración de que el separador decimal es un punto, no una coma, y que si se trata de un valor monetario deberemos incluir la moneda al inicio de la constante. Por ejemplo: 85.90 y €85.90, el primero sería un valor decimal y el segundo un valor money. De forma predeterminada, los valores serán positivos. Para indicar lo contrario escribimos el signo - al principio.

Las constantes de fecha y hora van entre comillas simples y con un formato de fecha y hora adecuado. Por ejemplo: '03/10/90'.

Y las constantes en cadenas de caracteres van entre comillas simples. Por ejemplo: 'Juan García López'.

Para indicar valores negativos y positivos añadimos el prefijo + o - según sea el valor positivo o negativo. Sin prefijo se entiende que el valor es positivo.

Si quieres ver cómo definir constantes para otros tipos de datos, visita el siguiente avanzado (arriba).

Unidad 2. Introducción al SQL. Transact-SQL (IV)

2.7. Las expresiones

Una expresión es una combinación de símbolos y operadores que el motor de base de datos de SQL Server evalúa para obtener un único valor. Una expresión simple puede ser una sola constante, variable, columna o función escalar. Los operadores se pueden usar para combinar dos o más expresiones simples y formar una expresión compleja. Dos expresiones pueden combinarse mediante un operador si ambas tienen tipos de datos admitidos por el operador y se cumple al menos una de estas condiciones:

Las expresiones tienen el mismo tipo de datos.

El tipo de datos de menor prioridad se puede convertir implícitamente al tipo de datos de mayor prioridad.

La función CAST puede convertir explícitamente el tipo de datos con menor prioridad al tipo de datos con mayor prioridad o a un tipo de datos intermedio que pueda convertirse implícitamente al tipo de datos con la mayor prioridad.

Tipos de operadores:

- Operadores numéricos:

suma +

40

Page 41: Curso de SQL Server.docx

resta -

multiplicación *

división /

módulo (resto de una división)

%

- Operadores bit a bit: realizan manipulaciones de bits entre dos expresiones de cualquiera de los tipos de datos de la categoría del tipo de datos entero.

AND &

OR |

OR exclusivo ^

- Operadores de comparación:

Igual a =

Mayor que >

Menor que <

Mayor o igual que >=

Menor o igual que <=

Distinto de <>

No es igual a !=

No menor que !<

No mayor que !>

- Operadores lógicos:

Aquí sólo los nombraremos ya que en el tema de consultas simples los veremos en detalle.

ALL IN

AND LIKE

ANY NOT

BETWEEN OR

41

Page 42: Curso de SQL Server.docx

EXISTS SOME

- Operadores de cadenas:

Concatenación +

Resultados de la expresión

- Si se combinan dos expresiones mediante operadores de comparación o lógicos, el tipo de datos resultante es booleano y el valor es uno de los siguientes: TRUE, FALSE o UNKNOWN.

- Cuando dos expresiones se combinan mediante operadores aritméticos, bit a bit o de cadena, el operador determina el tipo de datos resultante.

Las expresiones complejas formadas por varios símbolos y operadores se evalúan como un resultado formado por un solo valor. El tipo de datos, intercalación, precisión y valor de la expresión resultante se determina al combinar las expresiones componentes de dos en dos, hasta que se alcanza un resultado final. La prioridad de los operadores de la expresión define la secuencia en que se combinan las expresiones.

Unidad 2. Introducción al SQL. Transact-SQL (V)

2.8. Funciones

SQL Server 2005 proporciona numerosas funciones integradas y permite crear funciones definidas por el usuario.

Existen diferentes tipos de funciones:

Funciones de conjuntos de filas: devuelven un objeto que se puede utilizar, en instrucciones Transact-SQL, en lugar de una referencia a una tabla.

Funciones de agregado (también llamadas funciones de columna): Operan sobre una colección de valores y devuelven un solo valor de resumen. Por ejemplo, la función de suma sobre la columna importe para conocer el importe total: SUM(importe)

Funciones de categoría: Devuelven un valor de categoría para cada fila de un conjunto de filas, por ejemplo devuelve el número de la fila, el ranking de la fila en una determinada ordenación, etc.

Funciones escalares: Operan sobre un valor y después devuelven otro valor. Son las funciones que estamos acostumbrados a utilizar. Las funciones escalares se clasifican según el tipo de datos de sus operandos

Las variables

En Transact-SQL podemos definir variables, que serán de un tipo de datos determinado, como tipos de datos podemos utilizar los propios de la base de datos SQL-SERVER, pero también podemos utilizar tipos propios del lenguaje que no pueden ser utilizados en DDL. El tipo Cursor y el tipo Table son dos de estos tipos.

42

Page 43: Curso de SQL Server.docx

Las variables se definen utilizando la instrucción DECLARE con el siguiente formato:

DECLARE @nbvariable tipo

El nombre de la variable debe empezar por el símbolo @, este símbolo hace que SQL interprete el nombre como un nombre de variable y no un nombre de objeto de la base de datos.

Por ejemplo: DECLARE @empleados INT

Con esto  hemos definido la variable @empleados de tipo entero.

Para asignar un valor a una variable, la asignación se realiza con la palabra SELECT y el signo igual con el formato:

SELECT @nbvariable = valor

El valor puede ser cualquier valor constante, otro nombre de variable, una expresión válida o algo más potente, parte de una sentencia SELECT de SQL.Por ejemplo:

SELECT @empleados = 0;

SELECT @empleados = @otra * 100;

SELECT @EMPLEADOS = COUNT(numemp) FROM empleados;

El valor almacenado en la variable se puede visualizar mediante la orden PRINT. o SELECT

PRINT @nbvariable o SELECT @nbvariable

El valor almacenado en la variable se visualizará en la pestaña de resultados. También se puede usar para escribir mensajes:

PRINT 'Este es el mensaje'

Otros elementos del lenguaje

Comentarios. Como en cualquier otro lenguaje de programación, debemos utilizar comentarios destinados a facilitar la legibilidad del código. En SQL se insertan comentarios con los signos:

/* */ Varias líneas/* Esto es un comentarioen varias líneas */

-- Una única línea -- Esto es un comentario en una única línea.

USE. Cambia el contexto de la base de datos al de la base de datos especificada.

USE nbBaseDeDatos

Hace que la base de datos activa pase a ser la base de datos indicada en la instrucción, las consultas que se ejecuten a continuación se harán sobre tablas de esa base de datos si no se indica lo contrario. Es una instrucción útil para asegurarnos de que la consulta se ejecuta sobre la base de datos correcta.

GO

43

Page 44: Curso de SQL Server.docx

GO no es una instrucción Transact-SQL, sino un comando reconocido por las utilidades sqlcmd y osql, así como por el Editor de código de SQL Server Management Studio.Las utilidades de SQL Server interpretan GO como una señal de que deben enviar el lote actual de instrucciones Transact-SQL a una instancia de SQL Server. El lote actual de instrucciones está formado por todas las instrucciones específicadas desde el último comando GO o desde el comienzo de la sesión o script si se trata del primer comando GO. Por ejemplo si queremos crear una consulta para crear una base de datos y sus tablas, después del CREATE DATABASE…; tenemos que poner GO antes del primer CREATE TABLE para que el sistema efectúe la primera operación y la base de datos esté creada antes de ejecutar el primer CREATE TABLE.

BEGIN...END

Encierra un conjunto de instrucciones Transact-SQL de forma que estas instrucciones formen un bloque de instrucciones.

Unidad 3. Consultas simples (I)

3.1. Introducción

Vamos a empezar por la instrucción que más se utiliza en SQL, la sentencia SELECT. La sentencia SELECT es, con diferencia, la más compleja y potente de las sentencias SQL, con ella podemos recuperar datos de una o más tablas, seleccionar ciertos registros e incluso obtener resúmenes de los datos almacenados en la base de datos. Es tan compleja que la estudiaremos a lo largo de varias unidades didácticas incorporando poco a poco nuevas funcionalidades.

El resultado de una SELECT es una tabla lógica que alberga las filas resultantes de la ejecución de la sentencia.

La sintaxis completa es la siguiente:

SELECT sentencia::=[WITH <expresion_tabla_comun> [,...n]]

<expresion_consulta>

[ORDER BY {expression_columna|posicion_columna [ASC|DESC] }

[ ,...n ]]

[COMPUTE

{{AVG|COUNT|MAX|MIN|SUM} (expression)}[ ,...n ] [BY expression[ ,...n ]]

]

[<FOR clausula_for>]

[OPTION (<query_hint>[ ,...n ])]

<expresion_consulta> ::=

{<especificacion_consulta> | ( < expresion_consulta > ) }

[ {UNION [ALL]|EXCEPT|INTERSECT}

44

Page 45: Curso de SQL Server.docx

<especificacion_consulta> | (<expresion_consulta>) [...n ]

]

<especificacion_consulta> ::=

SELECT [ALL|DISTINCT]

[TOP expresion [PERCENT] [WITH TIES] ]

<lista_seleccion>

[INTO nueva_tabla]

[FROM { <origen> } [ ,...n ] ]

[WHERE <condicion_busqueda> ]

[GROUP BY [ ALL ] expresion_agrupacion [ ,...n ]

[WITH { CUBE | ROLLUP } ]

]

[HAVING < condicion_busqueda > ]

Debido a la complejidad de la sentencia (en la sintaxis anterior no se han detallado algunos elementos), la iremos viendo poco a poco, empezaremos por ver consultas básicas para luego ir añadiendo más cláusulas.

Empezaremos por ver las consultas más simples, basadas en una sola tabla y nos limitaremos a la siguiente sintaxis:

SELECT [ALL|DISTINCT]

[TOP expresion [PERCENT] [WITH TIES]]

<lista_seleccion>

FROM <origen>

[WHERE <condicion_busqueda> ]

[ORDER BY {expression_columna|posicion_columna [ASC|DESC]} [ ,...n ]]

3.2. Origen de datos FROM

De la sintaxis anterior, el elemento <origen> indica de dónde se va a extraer la información y se indica en la cláusula FROM, es la única cláusula obligatoria. En este tema veremos un origen de datos basado en una sola tabla.

La sintaxis será la siguiente:

<origen>::=

nb_tabla | nb_vista [[ AS ] alias_tabla ]

nb_tabla representa un nombre de tabla.

nb_vista un  nombre de vista.

45

Page 46: Curso de SQL Server.docx

Tanto para las tablas como para las vistas, podemos hacer referencia a tablas que están en otras bases de datos (siempre que tengamos los permisos adecuados), en este caso tenemos que cualificar el nombre de la tabla, indicando delante el nombre de la base de datos (Lógica) y el nombre del esquema al que pertenece la tabla dentro de la base de datos.

Por ejemplo: MiBase.dbo.MiTabla se refiere a la tabla MiTabla que se encuentra en el esquema dbo de la base de datos MiBase.

Cuando no se definen esquemas, SQL-Server crea uno por defecto en cada base de datos denominado dbo.

Opcionalmente podemos definir un nombre de alias.

Un nombre de alias (alias_tabla) es un nombre alternativo que se le da a la tabla dentro de la consulta.

Si se define un nombre de alias, dentro de la consulta, será el nombre a utilizar para referirnos a la tabla, el nombre original de la tabla  ya no tendrá validez.

Se utilizan los nombres de alias para simplificar los nombres de tablas a veces largos y también cuando  queremos combinar una tabla consigo misma; ya volveremos sobre los alias de tabla cuando veamos consultas multitabla.

La palabra AS no añade ninguna operatividad, está más por estética.

Podemos escribir:

SELECT ...

FROM tabla1 Sacamos los datos de la tabla tabla1

SELECT ...

FROM tabla1 t1 Sacamos los datos de la tabla tabla1 y le asignamos un alias de tabla: t1

SELECT ...

FROM tabla1 AS t1 Es equivalente a la sentencia anterior.

Si la tabla o la vista están en otra base de datos del mismo equipo que está ejecutando la instancia de SQL Server, se utiliza el nombre cualificado con el formato nbBaseDatos.nbEsquema.nbTabla.

Si la tabla o la vista están fuera del servidor local en un servidor vinculado, se utiliza un nombre de cuatro partes con el formato nbservidor.catalogo.nbEsquema.nbTabla. Volveremos más adelante sobre las conexiones remotas.

Unidad 3. Consultas simples (II)

3.3. La lista de selección

En la lista de selección <lista_seleccion> indicamos las columnas que se tienen que visualizar en el resultado de la consulta.

<lista_seleccion> ::=

46

Page 47: Curso de SQL Server.docx

{ *

| {nombre_tabla|nombre_vista|alias_tabla}.*

| { [{nombre_tabla|nombre_vista|alias_tabla}.]

{nb_columna|$IDENTITY|$ROWGUID}

|<expresion>

}[[AS] alias_columna]

    | alias_columna = <expresion>

 } [ ,...n ]

Separamos la definición de cada columna por una coma y las columnas del resultado aparecerán en el mismo orden que en la lista de selección.

Para cada columna del resultado su tipo de datos, tamaño, precisión y escala son los mismos que los de la expresión que da origen a esa columna.

Podemos definir las columnas del resultado de varias formas, mediante:

Una expresión simple:

o una referencia a una función.

o una variable local

o una constante

o una columna del origen de datos,

Una subconsulta escalar, que es otra instrucción SELECT que devuelve un único valor y se evalúa para cada fila del origen de datos (esto no lo veremos de momento).

Una expresión compleja generada al usar operadores en una o más expresiones simples.

La palabra clave *.

La asignación de variables con el formato @variable_local = expresión.

La palabra clave $IDENTITY.

La palabra clave $ROWGUID.

3.4. Columnas del origen de datos

Cuando queremos indicar en la lista de selección una columna del origen de datos, la especificamos mediante su nombre simple o nombre cualificado. El nombre cualificado consiste en el nombre de la columna precedido del nombre de la tabla donde se encuentra la columna.

Si en el origen de datos hemos utilizado una vista o un nombre de alias, deberemos utilizar ese nombre.  Es obligatorio utilizar el nombre cualificado cuando el nombre de la columna aparece en más de una tabla del origen de datos.

Ejemplos de consulta simple.

47

Page 48: Curso de SQL Server.docx

Listar nombres, oficinas, y fechas de contrato de todos los empleados:

SELECT nombre, oficina, contrato

FROM empleados;

El resultado sería:

nombre oficina contrato

Antonio Viguer 12 1986-10-20

Alvaro Jaumes 21 1986-12-10

Juan Rovira 12 1987-03-01

José González 12 1987-05-19

Vicente Pantalla 13 1988-02-12

Luis Antonio 11 1988-06-14

Jorge Gutiérrez 22 1988-11-14

Ana Bustamante 21 1989-10-12

María Sunta 11 1999-10-12

Juan Victor NULL 1990-01-13

Listar una tarifa de productos:

SELECT idfab, idproducto, descripcion, productos.precio

FROM productos;

Hemos cualificado la columna precio aunque no es necesario en este caso. 

El resultado sería:

Idfab idproducto descripcion precio

aci 41001 arandela 0,58

aci 41002 bisagra 0,80

aci 41003 art t3 1,12

aci 41004 art t4 1,23

aci 4100x junta 0,26

aci 4100y extractor 28,88

48

Page 49: Curso de SQL Server.docx

aci 4100z mont 26,25

bic 41003 manivela 6,52

bic 41089 rodamiento 2,25

Unidad 3. Consultas simples (III)

3.5. Alias de columna

Por defecto, en el encabezado de cada columna del resultado, aparece el nombre de la columna origen, pero esto se puede cambiar definiendo un alias de columna, el alias de columna es un nombre alternativo que se le da a esa columna.

El alias de columna se indica mediante la cláusula AS. Se escribe el nuevo texto tal cual sin comillas siguiendo las reglas de los identificadores.

Ejemplo:

SELECT numclie,nombre AS nombrecliente

FROM clientes;

El resultado será :

Numclie nombrecliente

2101 Luis García Antón

2102 Alvaro Rodríguez

2103 Jaime Llorens

en vez de:

Numclie nombre

2101 Luis García Antón

2102 Alvaro Rodríguez

2103 Jaime Llorens

La palabra AS es opcional.

SELECT numclie,nombre nombrecliente

49

Page 50: Curso de SQL Server.docx

FROM clientes;

Sería equivalente a la consulta anterior

Si queremos incluir espacios en blanco en el nombre lo debemos encerrar entre corchetes.

SELECT numclie,nombre AS [nombre cliente]

FROM clientes;

Nota importante: Este nombre de alias se podrá utilizar en la lista de selección y en la cláusula ORDER BY pero no en la cláusula WHERE.

3.6. Funciones

Existen funciones que podemos utilizar en la lista de selección, e incluso en otras cláusulas que veremos más adelante, como el WHERE. Las principales funciones son las siguientes:

Funciones de fecha:

Función DescripciónVer

+

GETDATE Devuelve la fecha actual.

GETUTCDATE Devuelve la hora UTC.

DATEPART Devuelve un entero que corresponde a la parte de la fecha solicitada.

DAY Devuelve el día de la fecha indicada.

MONTH Devuelve el mes de la fecha indicada.

YEAR Devuelve el año de la fecha indicada.

DATENAMEDevuelve una cadena de caracteres que representa el valor de la unidad especificada de una fecha especificada.

DATEADDDevuelve un valor datetime nuevo que resulta de sumar un intervalo de tiempo a una fecha especificada.>

DATEDIFF Devuelve el nº de intervalos que hay entre dos fechas.

@@DATEFIRST Devuelve el primer día de la semana establecido con SET DATEFIRST.

SET DATEFIRST Establece el primer día de la semana en un número del 1 al 7.

50

Page 51: Curso de SQL Server.docx

Unidad 3. Consultas simples (IV)

Funciones de cadena:

Función DescripciónVer

+

ASCIIDevuelve el valor de código ASCII del carácter situado más a la izquierda de una expresión de caracteres.

CHAR Devuelve el carácter ASCII del entero indicado.

NCHAR Devuelve el carácter Unicode del entero indicado.

UNICODE Devuelve el entero que se corresponde al carácter Unicode indicado.

LEN Devuelve el total de caracteres de una cadena, excluidos los espacios en blanco finales.

LTRIM Devuelve una cadena tras quitarle los espacios en blanco iniciales.

RTRIM Devuelve una cadena tras quitarle los espacios en blanco finales.

LEFT Devuelve los N últimos caracteres de una cadena.

RIGHT Devuelve los N primeros caracteres de una cadena.

SUBSTRING Devuelve parte de una expresión.

LOWER Devuelve la cadena convertida a minúsculas.

UPPER Devuelve la cadena convertida a mayúsculas.

REPLACE Reemplaza una determinada cadena.

STUFFElimina el número de caracteres especificado e inserta otro conjunto de caracteres en el punto de inicio indicado.

QUOTENAMEDevuelve una cadena Unicode con los delimitadores agregados para convertirla en un identificador delimitado válido de Microsoft SQL Server 2005.

SPACE Devuelve una cadena de espacios repetidos.

STR Devuelve una cadena de caracteres a partir de datos numéricos.

REPLICATE Repite una cadena N veces.

REVERSE Devuelve una cadena invertida.

51

Page 52: Curso de SQL Server.docx

CHARINDEX Devuelve la posición inicial de la expresión especificada en una cadena de caracteres.

PATINDEXDevuelve la posición inicial de la primera repetición de un patrón en la expresión especificada, o ceros si el patrón no se encuentra, en todos los tipos de datos de texto y caracteres.

Otras funciones:

Función DescripciónVer

+

ROUND Redondea un valor a la longitud y precisión indicadas.

CAST y CONVERT Convierten de un tipo de datos a otro de forma explícita.

CASE Evalúa una lista de condiciones.

ISNULL Reemplaza el valor NULL por otro especificado.

COALESCE Devuelve la primera expresión distinta de NULL entre sus argumentos.

Unidad 3. Consultas simples (V)

3.7. Columnas calculadas

Además de las columnas que provienen directamente de la tabla origen, una consulta SQL puede incluir columnas calculadas cuyos valores se evalúan a partir de una expresión.

La expresión puede contener cualquier operador válido (+, -, *, /, &…), cualquier función válida, nombres de columnas del origen de datos, nombres de parámetros o constantes y para combinar varias operaciones se pueden utilizar los paréntesis.

Ejemplos de columnas calculadas:

Listar la ciudad, región y el superávit de cada oficina. Consideraremos el superávit como el volumen de ventas que se encuentran por encima o por debajo del objetivo de la oficina.

SELECT ciudad, region, (ventas-objetivo) AS superavit

FROM oficinas;

El resultado será:

ciudad region superavit

Valencia este 11800,00

Alicante este -6500,00

52

Page 53: Curso de SQL Server.docx

Castellon este 1800,00

Badajoz oeste 11100,00

A Coruña oeste -11400,00

Madrid centro NULL

Madrid centro -10000,00

Pamplona norte NULL

Valencia este -90000,00

De cada producto queremos saber el id de fabricante, id de producto, su descripción y el valor de sus existencias.

SELECT idfab,idproducto,descripcion,(existencias*precio) AS valoracion

FROM productos;

El resultado sería:

Idfab idproducto descripcion valoracion

aci 41001 arandela 160,66

aci 41002 bisagra 133,60

aci 41003 art t3 231,84

aci 41004 art t4 170,97

aci 4100x junta 9,62

aci 4100y extractor 722,00

aci 4100z mont 735,00

bic 41003 manivela 19,56

bic 41089 rodamiento 175,50

Unidad 3. Consultas simples (VI)

Listar el nombre, mes y año del contrato de cada vendedor.

53

Page 54: Curso de SQL Server.docx

SELECT nombre, MONTH(contrato) AS [Mes de contrato], YEAR(contrato) AS [Año de contrato]

FROM  empleados;

El resultado será:

Nombre Mes de contrato Año de contrato

Antonio Viguer 10 1986

Alvaro Jaumes 12 1986

Juan Rovira 3 1987

Para practicar puedes realizar este Ejercicio Funciones en la lista de selección.

Listar las ventas en cada oficina con el formato: 22 tiene ventas de 186,042.00 €

SELECT  oficina, 'tiene ventas de ' AS [ ], ventas

FROM oficinas;

El resultado sería:

oficina ventas

11 tiene ventas de 69300,00

12 tiene ventas de 73500,00

13 tiene ventas de 36800,00

21 tiene ventas de 83600,00

22 tiene ventas de 18600,00

23 tiene ventas de NULL

24 tiene ventas de 15000,00

26 tiene ventas de NULL

28 tiene ventas de 0,00

El incluir una constante como columna en la lista de selección puede parecer inútil (se repetirá el mismo valor en todas las filas) pero veremos más adelante que tiene utilidad en ciertos casos.

También podemos utilizar la sintaxis:

54

Page 55: Curso de SQL Server.docx

alias_columna = <expresion>

Ejemplo:

SELECT oficina, superavit = ventas-objetivo

Esto tiene el mismo efecto que

SELECT oficina, ventas-objetivo AS superavit

Unidad 3. Consultas simples (VII)

3.8. Utilización del asterisco *

Si queremos visualizar todas las columnas del origen de datos, en lugar de indicar todas las columnas una a una se puede utilizar el carácter de sustitución *.

Mostrar todos los datos de la tabla oficinas.

SELECT *

FROM oficinas;

Obtener todos los datos y el superávit de cada oficina.

SELECT *, (ventas-objetivo) AS superavit

FROM oficinas;

También podemos cualificar el * con un nombre de tabla, de vista o un alias de tabla:

SELECT oficinas.*

FROM oficinas;

oficinas.* se interpreta como: todas las columnas de la tabla oficinas.

Esta forma se utiliza normalmente cuando el origen está basado en varias tablas y queremos indicar  todas las columnas no del origen completo sino de una tabla concreta.

Para practicar puedes realizar este Ejercicio La palabra clave *.

3.9. Las palabras clave $IDENTITY y $ROWGUID

La palabra clave $IDENTITY se interpreta como la columna de la tabla que tiene la propiedad IDENTITY (la columna de identidad que vimos en un tema anterior).

Por ejemplo, si en la columna codigo de la tabla usuarios (BD Biblio) se ha definido la propiedad IDENTITY.

55

Page 56: Curso de SQL Server.docx

SELECT $IDENTITY, nombre, apellidos

FROM usuarios;

Es equivalente a:

SELECT codigo, nombre, apellidos

FROM usuarios;

La palabra clave $ROWGUID se interpreta como la columna de la tabla que tiene la propiedad ROWGUIDCOL y se puede utilizar de la misma forma que $IDENTITY.

Unidad 3. Consultas simples (VIII)

3.10. Ordenación de las filas del resultado ORDER BY

Si queremos que las filas del resultado de la consulta aparezcan ordenadas, lo podemos indicar mediante la cláusula ORDER BY.

ORDER BY {expression_columna|posicion_columna [ASC|DESC]}[ ,...n ]

Podemos indicar una columna o varias separadas por una coma, la columna de ordenación se especifica mediante el nombre de columna en el origen de datos o su posición dentro de la lista de selección. Si utilizamos el nombre de columna, no hace falta que la columna aparezca en la lista de selección. Si utilizamos la posición es la posición de la columna dentro de la lista de selección empezando en 1.

Por defecto la filas se ordenarán en modo ascendente (ASC), de menor a mayor; si queremos invertir ese orden añadimos detrás de la columna la palabra DESC.

Si la columna de ordenación es alfanumérica, las filas se ordenarán por orden alfabético.

Si la columna de ordenación es numérica, las filas se ordenarán de menor a mayor.

Si la columna de ordenación es de tipo fecha, las filas se ordenarán de más antigua a más reciente o futura.

Ejemplos:

Mostrar las ventas de cada oficina, ordenadas por orden alfabético de región y dentro de cada región por ciudad.

SELECT oficina, region, ciudad, ventas

FROM oficinas

ORDER BY region, ciudad;

Da como resultado:

Oficina region ciudad ventas

56

Page 57: Curso de SQL Server.docx

24 centro Aranjuez 15000,00

23 centro Madrid NULL

12 este Alicante 73500,00

13 este Castellón 36800,00

11 este Valencia 69300,00

28 este Valencia 0,00

26 norte Pamplona NULL

22 oeste A Coruña 18600,00

21 oeste Badajoz 83600,00

Listar las oficinas de manera que las oficinas de mayores ventas aparezcan en primer lugar.

SELECT ciudad, region, ventas

FROM oficinas

ORDER BY ventas DESC;

ciudad region ventas

Badajoz oeste 83600,00

Alicante este 73500,00

Valencia este 69300,00

Castellon este 36800,00

A Coruña oeste 18600,00

Aranjuez centro 15000,00

Valencia este 0,00

Pamplona norte NULL

Madrid centro NULL

Listar las oficinas clasificadas en orden descendente de rendimiento de ventas, de modo que las de mayor rendimiento aparezcan las primeras.

57

Page 58: Curso de SQL Server.docx

SELECT ciudad, region, ventas-objetivo

FROM oficinas

ORDER BY 3 DESC;

Lo mismo que el anterior pero agrupadas por región.

SELECT region, ciudad, (ventas-objetivo) AS superavit

FROM oficinas

ORDER BY region, superavit DESC;

Resultado:

Region ciudad superavit

centro Aranjuez -10000,00

centro Madrid NULL

este Valencia 11800,00

este Castellón 1800,00

este Alicante -6500,00

este Valencia -90000,00

norte Pamplona NULL

oeste Badajoz 11100,00

oeste A Coruña -11400,00

En este caso hemos utilizado el alias de columna para hacer referencia a la columna calculada y también se puede observar que las filas aparecen ordenadas por región ascendente (no hemos incluido nada después del nombre de la columna) y dentro de cada región por superávit y descendente.

Unidad 3. Consultas simples (IX)

3.11. Eliminar filas duplicadas DISTINCT/ALL

SQL no elimina las filas duplicadas en el resultado de la consulta, si nosotros no queremos que se repitan las filas, tenemos la cláusula DISTINCT.Al incluir la cláusula DISTINCT en la SELECT, se eliminará del resultado las repeticiones de filas de resultado. Si por el contrario queremos que aparezcan todas las filas seleccionadas podemos incluir la cláusula ALL o nada, ya que ALL es el valor por defecto.

Listar los nº de empleado de los directores de las oficinas.

58

Page 59: Curso de SQL Server.docx

SELECT  dir

FROM oficinas;

dir

106

104

105

108

108

108

108

NULL

NULL

Si un mismo empleado dirige varias oficinas (por ejemplo el 108), su código aparece repetido en el resultado. Para evitarlo modificamos la consulta:

SELECT DISTINCT dir

FROM oficinas;

dir

NULL

104

105

106

108

Han desaparecido los valores duplicados.

Los que se eliminan son valores duplicados de filas del resultado, por ejemplo:

SELECT DISTINCT dir, region

FROM oficinas;

dir region

59

Page 60: Curso de SQL Server.docx

NULL este

NULL norte

104 este

105 este

106 este

108 centro

108 oeste

Ahora el 108 aparece dos veces porque las dos filas donde aparece no son iguales (porque tienen distinta región).

NOTA: La cláusula DISTINCT hace que la consulta tarde algo más en ejecutarse debido al proceso adicional de buscar y eliminar las repeticiones, por lo que se aconseja utilizarla únicamente cuando sea imprescindible.

Para practicar puedes realizar este Ejercicio Eliminar filas duplicadas.

Unidad 3. Consultas simples (X)

3.12. La cláusula TOP

[TOP <expresión> [PERCENT] [WITH TIES]]

La cláusula TOP indica que en el resultado no deben aparecer todas las filas resultantes sino un cierto número de registros, las n primeras. Si la consulta incluye la cláusula ORDER BY, se realiza la ordenación antes de extraer los n primeros registros.

La expresión representa ese número n y debe devolver un número entero sin signo.

Por ejemplo tenemos la siguiente tabla:

SELECT * FROM productos:

60

Page 61: Curso de SQL Server.docx

Si ordenamos por ventas:

SELECT * FROM productos

ORDER BY ventas;

Obtenemos el siguiente resultado:

Si añadimos la cláusula TOP:

SELECT TOP 3 * FROM productos

ORDER BY ventas

Obtenemos los 3 primeros registros:

Si existen más registros con las mismas ventas que el último valor de la lista, éstos no saldrán en el  resultado de la consulta.

En el ejemplo el registro con cod = 2 no sale en el resultado y tiene las mismas ventas que cod = 3.

Si queremos que salgan añadimos la cláusula WITH TIES. La cláusula WITH TIES sólo se puede emplear si la SELECT incluye un ORDER BY, de lo contrario dará error.

Si añadimos la cláusula WITH TIES:

SELECT TOP 3 WITH TIES *

FROM productos

ORDER BY ventas

Obtenemos:

61

Page 62: Curso de SQL Server.docx

Se incluyen en el resultado todos los registros que tienen ventas iguales al último registro.

Otro ejemplo:

SELECT TOP 10 oficina, ciudad, ventas FROM oficinas

ORDER BY ventas;

Devuelve las 10 peores oficinas en cuanto a ventas: ordenamos las oficinas por ventas de menor a mayor y sacamos las 10 primeras.

Si incluimos la palabra PERCENT, entonces n no indica el número de registros a recuperar sino el porcentaje de registros a recuperar del total de filas recuperadas después de ejecutar la cláusula WHERE.

SELECT TOP 50 PERCENT  * FROM productos ORDER BY ventas

Devuelve:

Si el porcentaje no da exacto, siempre redondea al alza.

Unidad 3. Consultas simples (XI)

3.13. Selección de filas WHERE

La cláusula WHERE se emplea para especificar las filas que se desean recuperar del origen de datos.

WHERE <condicion_búsqueda>

<condicion_búsqueda> ::=

{ [NOT]<predicado>

|(<condicion_búsqueda>)

}

[{AND|OR} [NOT] {<predicado>|(<condicion_búsqueda>)}]

[ ...n ]

En el resultado de la consulta sólo aparecerán las filas que cumplan que la condición de búsqueda sea TRUE, los valores NULL no se incluyen, por lo tanto, en las filas del resultado. La condición de búsqueda  puede ser una condición simple o una condición compuesta por varias condiciones (predicados)  unidas por operadores AND y OR, no hay

62

Page 63: Curso de SQL Server.docx

límite en cuanto al número de predicados que se pueden incluir. En las condiciones compuestas se pueden utilizar paréntesis para delimitar predicados y se aconseja su uso cuando se incluyen operadores AND y OR en la misma condición de búsqueda.

3.14. Predicados

En SQL tenemos 7 tipos de predicados,  condiciones básicas de búsqueda:

Comparación estándar

Pertenencia a un intervalo (BETWEEN)

Pertenencia a un conjunto (IN)

Test de valor nulo (IS NULL).

Coincidencia con patrón (LIKE)

Si contiene (CONTAINS)

FREETEXT

Comparación estándar.

Compara el valor de una expresión con el valor de otra. Para la comparación se pueden emplear  =  , <>  , !=, <  , <=  , !<, >  , >= ,!>

Sintaxis:

<expresion> {=|<>|!=|>|>=|!>|<|<=|!<} <expresion>

<expresion> Puede ser:

Un nombre de columna,

una constante,

una función (inclusive la función CASE),

una variable,

una subconsulta escalar o

cualquier combinación de nombres de columna, constantes y funciones conectados mediante uno o varios operadores o una subconsulta.

Ejemplo:

Listar los "buenos" vendedores (los que han rebasado su cuota).

SELECT numemp, nombre, ventas, cuota

FROM empleados

WHERE ventas > cuota

numemp nombre ventas cuota

101 Antonio Viguer 30500,00 30000,00

63

Page 64: Curso de SQL Server.docx

102 Alvaro Jaumes 47400,00 35000,00

103 Juan Rovira 28600,00 27500,00

105 Vicente Pantalla 36800,00 35000,00

106 Luis Antonio 29900,00 27500,00

108 Ana Bustamante 36100,00 35000,00

109 María Sunta 39200,00 3000,00

Las columnas que aparecen en el WHERE no tienen por qué aparecer en la lista de selección, esta instrucción es igual de válida:

SELECT numemp, nombre FROM empleados

WHERE ventas > cuota;

Hallar vendedores contratados antes de 1988.

SELECT numemp, nombre, contrato FROM empleados

WHERE contrato < '01/01/1988';

numemp nombre contrato

101 Antonio Viguer 1986-10-20

102 Alvaro Jaumes 1986-12-10

103 Juan Rovira 1987-03-01

104 José González 1987-05-19

También podemos utilizar funciones, ésta es equivalente a la anterior:

SELECT numemp, nombre

FROM empleados

WHERE YEAR(contrato) < 1988;

La función YEAR(fecha) devuelve el año de una fecha.

Hallar oficinas cuyas ventas estén por debajo del 80% de su objetivo:

SELECT oficina

FROM oficinas

WHERE ventas < (.8 * objetivo);

64

Page 65: Curso de SQL Server.docx

Hallar las oficinas dirigidas por el empleado 108:

SELECT oficina

FROM oficinas

WHERE dir = 108;

Unidad 3. Consultas simples (XII)

Pertenencia a un intervalo. BETWEEN

<expresion> [NOT] BETWEEN <expresion2> AND <expresion3>

Examina si el valor de la expresión de test está en el rango delimitado por los valores resultantes de expresion1 y expresion2, estos valores no tienen por qué estar ordenados en ANSI/ISO; expresion1 debe ser menor o igual a expresion2.

Hallar vendedores cuyas ventas estén entre 20.000 euros y 50.000.

SELECT numemp, nombre, ventas FROM empleados

WHERE  ventas BETWEEN 20000 AND 100000;

numemp nombre ventas

101 Antonio Viguer 30500,00

102 Alvaro Jaumes 47400,00

103 Juan Rovira 28600,00

105 Vicente Pantalla 36800,00

106 Luis Antonio 29900,00

108 Ana Bustamante 36100,00

109 María Sunta 39200,00

La instrucción anterior es equivalente a:

SELECT numemp, nombre, ventas

FROM empleados

WHERE  ventas >= 20000 AND ventas <=100000;

Parece que con BETWEEN se lee mejor.

Observa que no hemos utilizado separadores de millares (100.000), porque se habría interpretado por una coma decimal.

65

Page 66: Curso de SQL Server.docx

Para practicar puedes realizar este Ejercicio Intervalos con BETWEEN.

Test de pertenencia a conjunto IN

<expresion> IN ( <exp_valor> [ ,...n ] )

Examina si el valor de la expresion es uno de los valores incluidos en la lista de valores indicados entre paréntesis. Se pueden expresar los valores mediante cualquier expresión, la única condición es que todas las exp_valor devuelvan el mismo tipo de datos.

Ejemplo:

Obtener los empleados que trabajan en las oficinas 11, 20 o 22:

SELECT oficina, numemp, nombre

FROM empleados

WHERE oficina IN (11,20,22);

oficina numemp nombre

11 106 Luis Antonio

22 107 Jorge Gutiérrez

11 109 María Sunta

Para practicar puedes realizar este Ejercicio Pertenencia a un conjunto con IN.

Test de valor nulo IS NULL

<expression> IS [NOT] NULL

Una condición de búsqueda puede ser TRUE, FALSE o NULL/UNKNOW, este último caso se produce cuando algún campo que interviene en la condición tiene valor NULL.A veces es útil comprobar explícitamente los valores NULL en una condición de búsqueda ya que estas filas puede que queramos darles un tratamiento especial, para ello tenemos el predicado IS NULL.

Este test produce un valor TRUE o FALSE, por lo que se podrá combinar con otras condiciones. El valor NULL no es en sí un valor por eso no lo podemos utilizar en una igualdad.

SELECT numemp,nombre FROM empleados

WHERE oficina = NULL;

Esta instrucción no da error pero no obtiene lo que en principio parece que quiere obtener. No obtenemos los empleados cuya oficina sea un valor nulo (es decir los empleados que no tienen oficina), no obtenemos nada, en cambio los obtendremos utilizando el test de valor nulo:

66

Page 67: Curso de SQL Server.docx

SELECT numemp,nombre, oficina FROM empleados

WHERE oficina IS NULL;

Resultado:

numemp nombre oficina

110 Juan Victor NULL

Juan Victor es el único empleado que no tiene oficina asignada.

Listar los vendedores asignados a alguna oficina.

SELECT numemp, nombre, oficina FROM empleados

WHERE oficina IS NOT NULL;

numemp nombre oficina

101 Antonio Viguer 12

102 Alvaro Jaumes 21

103 Juan Rovira 12

104 José González 12

105 Vicente Pantalla 13

106 Luis Antonio 11

107 Jorge Gutiérrez 22

108 Ana Bustamante 21

109 María Sunta 11

Unidad 3. Consultas simples (XIII)

Test de correspondencia con patrón LIKE

Se utiliza cuando queremos comparar el valor de una columna con un patrón en el que se utilice caracteres comodines.

<expression>  [NOT] LIKE <patron>  [ESCAPE 'car_escape']

Con expresión indicamos el valor a comparar (normalmente será el nombre de una columna) y patrón es la cadena que se busca. El patrón es de tipo texto y tiene que

67

Page 68: Curso de SQL Server.docx

escribirse entre comillas simples. Dentro del patrón podemos utilizar los siguientes comodines:

%    representa cualquier cadena de cero o más caracteres.

SELECT numemp,nombre

FROM empleados

WHERE nombre LIKE ‘An%’;

numemp nombre

101 Antonio Viguer

108 Ana Bustamante

Obtiene todos los nombres que empiecen por An.

SELECT numemp,nombre

FROM empleados

WHERE nombre LIKE ‘%z’;

numemp nombre

104 José González

107 José González

Obtiene los nombres que acaban en z.

SELECT numemp,nombre

FROM empleados

WHERE nombre LIKE ‘%on%’;

numemp nombre

101 Antonio Viguer

104 José González

106 Luis Antonio

Obtiene los nombres que contienen on.

_     representa cualquier carácter (sólo uno).

SELECT numemp,nombre

68

Page 69: Curso de SQL Server.docx

FROM empleados

WHERE nombre LIKE '__a%';

numemp nombre

103 Juan Rovira

108 Ana Bustamante

110 Juan Victor

Obtiene los nombres cuya tercera letra sea una a (en el patrón tenemos dos caracteres subrayado).

[  ] sirve para indicar un carácter cualquiera perteneciente al conjunto indicando.       El conjunto se indica enumerando los caracteres o indicando un intervalo.

SELECT numemp,nombre

FROM empleados

WHERE nombre LIKE '[a-d]%';

Obtiene los nombres que empiezan por cualquier letra de la a a la d.

Es equivalente a escribir:

SELECT numemp,nombre

FROM empleados

WHERE nombre LIKE '[abcd]%';

[^] significa cualquier carácter individual que no se encuentre en el conjunto.

SELECT numemp,nombre

FROM empleados

WHERE nombre LIKE '[^abcd]%';

Y

SELECT numemp,nombre

FROM empleados

WHERE nombre LIKE '[^a-d]%';

Obtienen los nombres que no empiecen por a, b, c ni d.

Es importante tener en cuenta que dentro del patrón el espacio en blanco es considerado como un carácter más, si colocamos dos espacios en el patrón, se buscarán dos espacios en el campo.

69

Page 70: Curso de SQL Server.docx

Si queremos incluir en el patrón uno de los caracteres comodines y que no sea interpretado como un comodín, sino como un carácter normal, lo tenemos que encerrar entre corchetes o utilizar un carácter de escape.

[ESCAPE 'car_escape']

La cláusula ESCAPE es opcional y permite definir un carácter de escape.

Un carácter de escape es un carácter que se coloca delante de un carácter comodín para indicar que el comodín no debe interpretarse como tal, sino como un carácter normal.

Por ejemplo queremos buscar los nombres compuestos que incluyen un subrayado. En este caso tenemos que poner el carácter _ como un carácter normal no como un comodín, así que lo escribiremos así:

SELECT numemp,nombre

FROM empleados

WHERE nombre LIKE '%[_]%';

O bien,

SELECT numemp,nombre

FROM empleados

WHERE nombre LIKE '%!_%' ESCAPE '!';

Unidad 3. Consultas simples (XIV)

3.15. Condiciones de búsqueda compuestas

En una cláusula WHERE podemos incluir una condición de búsqueda simple (formada por un solo predicado) o compuesta (formada por la combinación de predicados unidos por los operadores lógicos NOT, AND, OR).

Cuando la condición incluye varios operadores lógicos, el orden de prioridad de estos operadores es:

NOT (el más alto),

seguido de AND y OR (estos dos al mismo nivel).

Como siempre, se pueden utilizar paréntesis para alterar esta prioridad en una condición de búsqueda.

El orden de evaluación de los operadores lógicos puede variar dependiendo de las opciones elegidas por el optimizador de consultas.

Los operadores lógicos pueden devolver tres valores distintos: TRUE, FALSE, NULL (UNKNOWN).

Tablas de verdad de los operadores:

AND Combina dos condiciones y se evalúa como TRUE cuando ambas condiciones son TRUE.

70

Page 71: Curso de SQL Server.docx

AND TRUE FALSE NULL

TRUE TRUE FALSE NULL

FALSE FALSE FALSE FALSE

NULL NULL FALSE NULL

OR Combina dos condiciones y se evalúa como TRUE cuando alguna de las condiciones es TRUE.

OR TRUE FALSE NULL

TRUE TRUE TRUE TRUE

FALSE TRUE FALSE NULL

NULL TRUE NULL NULL

NOT Niega la expresión booleana que especifica el predicado

NOT TRUE FALSE NULL

FALSE TRUE NULL

Hallar los vendedores que están por debajo de su cuota y tienen ventas inferiores a 30.000.

SELECT nombre

FROM empleados

WHERE ventas < cuota AND ventas < 30000;

Hallar los vendedores que están debajo de su cuota, pero cuyas ventas no sean inferiores a 150.000.

SELECT nombre

FROM empleados

WHERE ventas < cuota AND ventas < 150000;

Hallar las oficinas no dirigidas por el empleado 108

SELECT oficina

FROM oficinas

WHERE NOT dir = 108;

O

71

Page 72: Curso de SQL Server.docx

SELECT oficina

FROM oficinas

WHERE  dir <> 108;

Devuelven:

oficina

11

12

13

Las oficinas sin director no aparecen, para que aparezcan deben añadir otro predicado:

SELECT oficina, dir

FROM oficinas

WHERE NOT dir = 108 or dir is null;

oficina dir

11 106

12 104

13 105

26 NULL

28 NULL

Unidad 4. Consultas multitabla (I)

4.1. Introducción

Hasta ahora hemos visto consultas que obtienen los datos de una sola tabla, en este tema veremos cómo obtener datos de diferentes tablas.

En esta parte ampliaremos la cláusula FROM y descubriremos nuevas palabras reservadas (UNION, EXCEPT e INTERSECT) que corresponden a operaciones relacionales.

Para obtener datos de varias tablas tenemos que combinar estas tablas mediante alguna operación basada en el álgebra relacional.

El álgebra relacional define una serie de operaciones cuyos operandos son tablas y cuyo resultado es también una tabla.

72

Page 73: Curso de SQL Server.docx

Las operaciones de álgebra relacional implementadas en Transact-Sql son:

La unión UNION

La diferencia EXCEPT

La intersección INTERSECT

El producto cartesiano CROSS JOIN

La composición interna INNER JOIN

La composición externa LEFT JOIN, RIGHT JOIN Y FULL JOIN

 En todo el tema cuando hablemos de tablas nos referiremos tanto a las tablas que físicamente están almacenadas en la base de datos como a las tablas temporales y a las resultantes de una consulta o vista.

4.2. La unión de tablas UNION

La unión de tablas consiste en coger dos tablas y obtener una tabla con las filas de las dos tablas, en el resultado aparecerán las filas de una tabla y, a continuación, las filas de la otra tabla.

Para poder realizar la operación, las dos tablas tienen que tener el mismo esquema (mismo número de columnas y tipos compatibles) y la tabla resultante hereda los encabezados de la primera tabla.

La sintaxis es la siguiente:

{< consulta >|(< consulta >)}

   UNION [ALL]

{< consulta >|(< consulta >)}

[{UNION [ALL] {< consulta >|(< consulta >)}}[ ...n ] ]

[ORDER BY {expression_columna|posicion_columna [ASC|DESC]}

             [ ,...n ]]

< consulta > representa la especificación de la consulta que nos devolverá la  tabla a combinar.Puede ser cualquier especificación de consulta con la limitación de que no admite la cláusula ORDER BY, los alias de campo se pueden definir pero sólo tienen efecto cuando se indican en la primera consulta ya que el resultado toma los nombres de columna de esta.

Ejemplo: Suponemos que tenemos una tabla Valencia con las nuevas oficinas de Valencia y otra tabla Madrid con las nuevas oficinas de Madrid y queremos obtener una tabla con las nuevas oficinas de las dos ciudades:

SELECT oficina as OFI, ciudad FROM Valencia

UNION ALL

SELECT oficina, ciudad FROM Madrid;

El resultado sería:

73

Page 74: Curso de SQL Server.docx

OFI ciudad

11 Valencia

28 Valencia

23 Madrid

El resultado coge los nombres de columna de la primera consulta y aparecen primero las filas de la primera consulta y después las de la segunda.

Si queremos que el resultado aparezca ordenado podemos incluir la cláusula ORDER BY, pero después de la última especificación de consulta, y expresion_columna será cualquier columna válida de la primera consulta.

SELECT oficina as OFI, ciudad FROM Valencia

UNION

SELECT oficina, ciudad FROM Madrid

ORDER BY ofi;

OFI ciudad

11 Valencia

23 Madrid

28 Valencia

Ahora las filas aparecen ordenadas por el número de oficina y hemos utilizado el nombre de columna de la primera consulta.

Cuando aparezcan en el resultado varias filas iguales, el sistema por defecto elimina las repeticiones.Si se especifica ALL, el sistema devuelve todas las filas resultante de la unión incluidas las repetidasEl empleo de ALL también hace que la consulta se ejecute más rápidamente ya que el sistema no tiene que eliminar las repeticiones.

Se pueden combinar varias tablas con el operador UNION. Por ejemplo supongamos que tenemos otra tabla Pamplona con las oficinas nuevas de Pamplona:

SELECT oficina, ciudad FROM Valencia

UNION

SELECT oficina, ciudad FROM Madrid

UNION

SELECT oficina, ciudad FROM Pamplona;

Combinamos las tres tablas.

74

Page 75: Curso de SQL Server.docx

Otro ejemplo:Obtener todos los productos cuyo precio exceda de 20 € o que se haya vendido más de 300 euros del producto en algún pedido.

SELECT idfab, idproducto

FROM  productos

WHERE precio > 20

UNION

SELECT fab, producto

FROM pedidos

WHERE importe > 300;

Unidad 4. Consultas multitabla (II)

4.3. La diferencia EXCEPT

Aparecen en la tabla resultante las filas de la primera consulta que no aparecen en la segunda.Las condiciones son las mismas que las de la unión.

   {<consulta>|(<consulta>)}

   EXCEPT

{<consulta>|(<consulta>)}

 [{EXCEPT {<consulta>|(<consulta>)}}[ ...n ] ]

[ORDER BY {expression_columna|posicion_columna [ASC|DESC]}

             [ ,...n ]]

Por ejemplo tenemos las tablas T1 y T2.

T1 T2

1

2

4

5

6

2

3

4

5

SELECT cod FROM T1

75

Page 76: Curso de SQL Server.docx

EXCEPT

SELECT codigo FROM T2;

Devuelve:

Cod

1

6

Ejemplo:Listar los productos que no aparezcan en ningún pedido.

SELECT idfab, idproducto

FROM  productos

EXCEPT

SELECT DISTINCT fab, producto

FROM pedidos;

Para practicar puedes realizar este Ejercicio La diferencia EXCEPT.

4.4. La intersección INTERSECT

Tiene una sintaxis parecida a las anteriores pero en el resultado de la intersección aparecen las filas que están simultáneamente en las dos consultas.Las condiciones son las mismas que las de la unión.

   { <consulta>|(<consulta>)}

   INTERSECT

{<especificacion_consulta>|(<especificacion_consulta>)}

          [{INTERSECT {<consulta>|(<consulta>)}} [ ...n ] ]

[ORDER BY {expression_columna|posicion_columna [ASC|DESC]}

             [ ,...n ]]

Retomando el ejemplo anterior:

SELECT cod FROM T1

INTERSECT

SELECT cod FROM T2;

Devuelve:

Cod

76

Page 77: Curso de SQL Server.docx

2

4

5

Ejemplo: Obtener todos los productos que valen más de 20 euros y que además se haya vendido en un pedido más de 300 euros de ese producto.

SELECT idfab, idproducto

FROM  productos

WHERE precio > 20

INTERSECT

SELECT fab, producto

FROM pedidos

WHERE importe > 300;

Unidad 4. Consultas multitabla (III)

4.5. La composición de tablas

Hasta ahora hemos operado con tablas que tenían el mismo esquema, pero muchas veces lo que necesitamos es obtener una tabla que tenga en una misma fila datos de varias tablas, por ejemplo, obtener las facturas y que en la misma fila de factura aparezca el nombre y dirección del cliente. Pues en lo que queda del tema estudiaremos este tipo de consultas basadas en la composición de tablas. La composición de tablas consiste en obtener a partir de dos tablas cualesquiera una nueva tabla fusionando las filas de una con las filas de la otra, concatenando los esquemas de ambas tablas. Consiste en formar parejas de filas.

La sentencia SELECT permite realizar esta composición, incluyendo dos o más tablas en la cláusula FROM.

Es hora de ampliar la cláusula FROM que vimos en el tema anterior.

Empezaremos por estudiar la operación a partir de la cual están definidas las demás operaciones de composición de tabla, el producto cartesiano.

4.6. El producto cartesiano CROSS JOIN

El producto cartesiano obtiene todas las posibles concatenaciones de filas de la primera tabla con filas de la segunda tabla.Se indica escribiendo en la cláusula FROM los nombres de las tablas separados por una coma o utilizando el operador CROSS JOIN.

FROM {<tabla_origen>} [ ,...n ]

77

Page 78: Curso de SQL Server.docx

  |<tabla_origen> CROSS JOIN <tabla_origen>

Tabla_origen puede ser un nombre de tabla o de vista o una tabla derivada (resultado de una SELECT), en este último caso la SELECT tiene que aparecer entre paréntesis y la tabla derivada debe llevar asociado obligatoriamente un alias de tabla. También puede ser una composición de tablas.Se pueden utilizar hasta 256 orígenes de tabla en una instrucción, aunque el límite varía en función de la memoria disponible y de la complejidad del resto de las expresiones de la consulta. También se puede especificar una variable table como un origen de tabla.

Ejemplo:

SELECT *

FROM empleados, oficinas;

Si ejecutamos esta consulta veremos que las filas del resultado están formadas por las columnas de empleados y las columnas de oficinas. En las filas aparece cada empleado combinado con la primera oficina, luego los mismos empleados combinados con la segunda oficina y así hasta combinar todos los empleados con todas las oficinas.Si ejecutamos:

SELECT *

FROM empleados CROSS JOIN oficinas;

Obtenemos lo mismo.

Este tipo de operación no es la que se utiliza más a menudo, lo más frecuente sería combinar cada empleado con los datos de SU oficina. Lo podríamos obtener añadiendo a la consulta un WHERE para filtrar los registros correctos:

SELECT *

FROM empleados, oficinas

WHERE empleados.oficina=oficinas.oficina;

Aquí nos ha aparecido la necesidad de cualificar los campos ya que el nombre oficina es un campo de empleados y de oficinas por lo que si no lo cualificamos, el sistema nos da error.Hemos utilizado en la lista de selección *, esto nos recupera todas las columnas de las dos tablas.

SELECT empleados.*,ciudad, region

FROM empleados, oficinas

WHERE empleados.oficina=oficinas.oficina;

Recupera todas las columnas de empleados y las columnas ciudad y región de oficinas.

También podemos combinar una tabla consigo misma, pero en este caso hay que definir un alias de tabla, en al menos una, sino el sistema da error ya que no puede nombrar los campos.

78

Page 79: Curso de SQL Server.docx

SELECT *

FROM oficinas, oficinas as ofi2;

No insistiremos más sobre el producto cartesiano porque no es la operación más utilizada, ya que normalmente cuando queramos componer dos tablas lo haremos con una condición de selección basada en campos de combinación y para este caso es más eficiente el JOIN que veremos a continuación.

Unidad 4. Consultas multitabla (IV)

4.7. La composición interna INNER JOIN

Una composición interna es aquella en la que los valores de las columnas que se están combinando se comparan mediante un operador de comparación.Es otra forma, mejor, de expresar un producto cartesiano con una condición.Es la operación que más emplearemos ya que lo más frecuente es querer juntar los registros de una tabla relacionada con los registros correspondientes en la tabla de referencia (añadir a cada factura los datos de su cliente, añadir a cada línea de pedido los datos de su producto, etc..,).

FROM

<tabla_origen> INNER JOIN <tabla_origen> ON <condicion_combi>

tabla_origen tiene el mismo significado que en el producto cartesiano.condicion_combi es cualquier condición que permite seleccionar las parejas de filas que aparecen en el resultado. Normalmente será una condición de igualdad.

SELECT *

FROM empleados INNER JOIN oficinas

ON empleados.oficina=oficinas.oficina;

Obtiene los empleados combinados con los datos de su oficina.

SELECT *

FROM pedidos INNER JOIN productos

ON producto = idproducto AND fab = idfab;

Obtiene los pedidos combinados con los productos correspondientes.

Normalmente la condición de combinación será una igualdad pero se puede utilizar cualquier operador de comparación (<>, >…).

Es fácil ver la utilidad de esta instrucción y de hecho se utilizará muy a menudo, pero hay algún caso que no resuelve. En las consultas anteriores, no aparecen las filas que no tienen fila correspondiente en la otra tabla.

SELECT numemp,nombre,empleados.oficina, ciudad

79

Page 80: Curso de SQL Server.docx

FROM empleados INNER JOIN oficinas

ON empleados.oficina=oficinas.oficina;

numemp nombre oficina ciudad

101 Antonio Viguer 12 Alicante

102 Alvaro Jaumes 21 Badajoz

103 Juan Rovira 12 Alicante

104 José González 12 Alicante

105 Vicente Pantalla 13 Castellón

106 Luis Antonio 11 Valencia

107 Jorge Gutiérrez 22 A Coruña

108 Ana Bustamante 21 Badajoz

109 María Sunta 11 Valencia

No aparecen los empleados que no tienen oficina,  ni las oficinas que no tienen empleados, porque para que salga la fila, debe de existir una fila de la otra tabla que cumpla la condición.

Para resolver este problema debemos utilizar otro tipo de composición, la composición externa.

Para practicar puedes realizar este Ejercicio La composición interna INNER JOIN.

Unidad 4. Consultas multitabla (V)

4.8. La Composición externa LEFT, RIGHT y FULL OUTER JOIN

La composición externa se escribe de manera similar al INNER JOIN indicando una condición de combinación pero en el resultado se añaden filas que no cumplen la condición de combinación.

Sintaxis

 FROM

<tabla_origen> {LEFT|RIGHT|FULL} [OUTER] JOIN <tabla_origen>

ON <condicion_combi>

La palabra OUTER es opcional y no añade ninguna función.Las palabras LEFT, RIGHT y FULL indican la tabla de la cual se van a añadir las filas sin correspondencia.

80

Page 81: Curso de SQL Server.docx

SELECT numemp,nombre,empleados.oficina, ciudad

FROM empleados LEFT JOIN oficinas

ON empleados.oficina=oficinas.oficina;

numemp nombre oficina ciudad

101 Antonio Viguer 12 Alicante

102 Alvaro Jaumes 21 Badajoz

103 Juan Rovira 12 Alicante

104 José González 12 Alicante

105 Vicente Pantalla 13 Castellón

106 Luis Antonio 11 Valencia

107 Jorge Gutiérrez 22 A Coruña

108 Ana Bustamante 21 Badajoz

109 María Sunta 11 Valencia

110 Juan Victor NULL NULL

Ahora sí aparece el empleado 110 que no tiene oficina

Obtiene los empleados con su oficina y los empleados (tabla a la izquierda LEFT del JOIN) que no tienen oficina aparecerán también en el resultado con los campos de la tabla oficinas rellenados a NULL.

SELECT numemp,nombre,empleados.oficina, ciudad, oficinas.oficina

FROM empleados RIGHT JOIN oficinas

ON empleados.oficina=oficinas.oficina;

numemp nombre oficina ciudad oficina

106 Luis Antonio 11 Valencia 11

109 María Sunta 11 Valencia 11

101 Antonio Viguer 12 Alicante 12

103 Juan Rovira 12 Alicante 12

104 José González 12 Alicante 12

105 Vicente Pantalla 13 Castellón 13

81

Page 82: Curso de SQL Server.docx

102 Alvaro Jaumes 21 Badajoz 21

108 Ana Bustamante 21 Badajoz 21

107 Jorge Gutiérrez 22 A Coruña 22

NULL NULL NULL Madrid 23

NULL NULL NULL Aranjuez 24

NULL NULL NULL Pamplona 26

NULL NULL NULL Valencia 28

Las oficinas 23,24,26 y 28 no tienen empleados.

Obtiene los empleados con su oficina y las oficinas (tabla a la derecha RIGHT del JOIN) que no tienen empleados aparecerán también en el resultado con los campos de la tabla empleados rellenados a NULL.

SELECT numemp,nombre,empleados.oficina, ciudad, oficinas.oficina

FROM empleados FULL JOIN oficinas

ON empleados.oficina=oficinas.oficina;

numemp nombre oficina ciudad oficina

101 Antonio Viguer 12 Alicante 12

102 Alvaro Jaumes 21 Badajoz 21

103 Juan Rovira 12 Alicante 12

104 José González 12 Alicante 12

105 Vicente Pantalla 13 Castellón 13

106 Luis Antonio 11 Valencia 11

107 Jorge Gutiérrez 22 A Coruña 22

108 Ana Bustamante 21 Badajoz 21

109 María Sunta 11 Valencia 11

110 Juan Victor NULL NULL NULL

NULL NULL NULL Madrid 23

NULL NULL NULL Aranjuez 24

NULL NULL NULL Pamplona 26

82

Page 83: Curso de SQL Server.docx

NULL NULL NULL Valencia 28

Aparecen tanto los empleados sin oficina como las oficinas sin empleados.

SELECT numemp,nombre,empleados.oficina, ciudad, oficinas.oficina

FROM empleados FULL OUTER JOIN oficinas

ON empleados.oficina=oficinas.oficina;

Es equivalente, la palabra OUTER como hemos dicho no añade ninguna funcionalidad y se utiliza si se quiere por cuestiones de estilo.

NOTA: Cuando necesitamos obtener filas con datos de dos tablas con una condición de combinación utilizaremos un JOIN, os aconsejo empezar por escribir el JOIN con la condición que sea necesaria para combinar las filas, y luego plantearos si la composición debe de ser interna o externa. Para este segundo paso ésta sería la norma a seguir:

Empezamos con INNER JOIN.

Si pueden haber filas de la primera tabla que no estén  relacionadas con filas de la segunda tabla y nos interesa que salgan en el resultado, entonces cambiamos a LEFT JOIN.

Si pueden haber filas de la segunda tabla que no estén  relacionadas con filas de la primera tabla y nos interesa que salgan en el resultado, entonces cambiamos a RIGHT JOIN.

Si necesitamos LEFT y RIGHT entonces utilizamos FULL JOIN.

Siguiendo el ejemplo anterior nos preguntaríamos:

¿Pueden haber empleados que no tengan oficina y nos interesan?, si es que sí, necesitamos un LEFT JOIN.

Seguiríamos preguntando:

¿Pueden haber oficinas que no tengan empleados y nos interesan?, si es que sí, necesitamos un RIGHT JOIN.

Si al final necesitamos LEFT y también RIGHT entonces utilizamos FULL JOIN.

Unidad 4. Consultas multitabla (VI)

4.9. Combinar varias operaciones

En las operaciones anteriores tabla_origen puede ser a su vez una composición de tablas, en este caso aunque sólo sea obligatorio cuando queramos cambiar el orden de ejecución de las composiciones, es recomendable utilizar paréntesis para delimitar las composiciones.

Por ejemplo:

SELECT numemp, nombre, empleados.oficina, ciudad, oficinas.oficina, pedidos.*

83

Page 84: Curso de SQL Server.docx

FROM (oficinas RIGHT JOIN empleados

       ON empleados.oficina = oficinas.oficina)

        INNER JOIN pedidos on rep=numemp;

O bien:

SELECT numemp, nombre, empleados.oficina, ciudad, oficinas.oficina, pedidos.*

FROM oficinas RIGHT JOIN (empleados INNER JOIN pedidos on rep = numemp)

       ON empleados.oficina = oficinas.oficina);

Unidad 5. Consultas de resumen (I)

5.1. Introducción

Una de las funcionalidades de la sentencia SELECT es el permitir obtener resúmenes de los datos contenidos en las columnas de las tablas.

Para poder llevarlo a cabo la sentencia SELECT consta de una serie de cláusulas específicas (GROUP BY, HAVING), y Transact-SQL tiene definidas unas funciones para poder realizar estos cálculos, las funciones de agregado (también llamadas funciones de columna).La diferencia entre una consulta de resumen y una consulta de las que hemos visto hasta ahora es que en las consultas normales las filas del resultado se obtienen directamente de las filas del origen de datos y cada dato que aparece en el resultado tiene su dato correspondiente en el origen de la consulta mientras que las filas generadas por las consultas de resumen no representan datos del origen sino un total calculado sobre estos datos. Esta diferencia hará que las consultas de resumen tengan algunas limitaciones que veremos a lo largo del tema.

Un ejemplo sería:

84

Page 85: Curso de SQL Server.docx

A la izquierda tenemos una consulta simple que nos saca las oficinas con sus ventas ordenadas por región, y a la derecha una consulta de resumen que obtiene la suma de las ventas de las oficinas de cada región

5.2. Las funciones de agregado

Una función de agregado SQL acepta un grupo de datos (normalmente una columna de datos) como argumento, y produce un único dato que resume el grupo. Por ejemplo la función AVG() acepta una columna de datos numéricos y devuelve la media aritmética (average) de los valores contenidos en la  columna.El mero hecho de utilizar una función de agregado en una consulta, convierte ésta en una consulta de resumen.

Todas las funciones de agregado tienen una estructura muy parecida:

Función ([ALL|DISTINCT] expression) 

El grupo de valores sobre el que actúa la función lo determina el resultado de la expresión que será un nombre de columna o una expresión basada en una columna o varias del origen de datos. En la expresión nunca puede aparecer una función de agregado ni una subconsulta.

La palabra ALL indica que se tiene que tomar en cuenta todos los valores de la columna. Es el valor por defecto.

La palabra DISTINCT hace que se consideren todas las repeticiones del mismo valor como uno sólo (considera valores distintos).

Todas las funciones de agregado se aplican a las filas del origen de datos una vez ejecutada la cláusula WHERE (si la hubiera).

Si exceptuamos la función COUNT, todas las funciones de agregado ignoran los valores NULL.

Una función de agregado puede aparecer en la lista de selección en cualquier lugar en el que puede aparecer un nombre de columna. Puede, por ejemplo, formar parte de una expresión pero no se pueden anidar funciones de agregado. Tampoco se pueden mezclar funciones de columna con nombres de columna ordinarios. Hay excepciones a esta regla pero cuando definimos agrupaciones y subconsultas que veremos más adelante.

Unidad 5. Consultas de resumen (II)

5.3. La función COUNT

COUNT ({[ALL|DISTINCT] expresion | * } )

Expresion puede ser de cualquier tipo excepto text, image o ntext. No se permite utilizar funciones de agregado ni subconsultas. El tipo de dato devuelto es int.Si el número de valores devueltos por expresion es superior a 231-1, COUNT genera un error, en ese caso hay que utilizar la función COUNT_BIG.

85

Page 86: Curso de SQL Server.docx

La función cuenta los valores distintos de NULL que hay en la columna. La palabra ALL indica que se tienen que tomar todos los valores de la columna, mientras que DISTINCT hace que se consideren todas las repeticiones del mismo valor como uno solo. Estos parámetros son opcionales, por defecto se considera ALL.

Por ejemplo:

SELECT COUNT(region) FROM oficinas;

Devuelve 9 porque tenemos nueve valores no nulos en la columna region. A la hora de interpretar un COUNT es conveniente no olvidar que cuenta valores no nulos, por ejemplo si interpretáramos la sentencia tal cual se lee, “cuántas regiones tenemos en oficinas”  sería erróneo, realmente estamos obteniendo cuántas oficinas tienen una región asignada. 

SELECT COUNT(DISTINCT region) FROM oficinas;

Devuelve 4 porque tenemos cuatro valores distintos, no nulos, en la columna región, los valores repetidos los considera sólo una vez. Ahora sí nos devuelve cuántas regiones tenemos en oficinas.

Si utilizamos * en vez de expresión, devuelve el número de filas del origen que nos quedan después de ejecutar la cláusula WHERE.

COUNT(*) no acepta parámetros y no se puede utilizar con DISTINCT. COUNT(*) no requiere un parámetro expression porque, por definición, no utiliza información sobre ninguna columna específica. En el recuento se incluyen las filas que contienen valores NULL.

SELECT COUNT(*) FROM empleados WHERE oficina=12;

Obtiene el número de empleados asignados a la oficina 12.

Si tenemos un COUNT(columna) y columna no contiene valores nulos, se obtiene el mismo resultado que COUNT(*)  pero el COUNT(*) es más rápido por lo que en este caso hay que utilizarlo en vez de COUNT(columna).

Por ejemplo:

SELECT COUNT(*) FROM empleados WHERE oficina IS NOT NULL;

Es mejor que:

SELECT COUNT(oficina) FROM empleados WHERE oficina IS NOT NULL;

Las dos nos devuelven el número de empleados que tienen una oficina asignada pero la primera es mejor porque se calcula más rápidamente.

Para practicar puedes realizar este Ejercicio La función COUNT.

5.4. La función COUNT_BIG

86

Page 87: Curso de SQL Server.docx

Funciona igual que la función COUNT. La única diferencia entre ambas funciones está en los valores devueltos, COUNT_BIG siempre devuelve un valor de tipo bigint y por lo tanto admite más valores de entrada, no está limitado a  231-1 valores de entrada como COUNT.

5.5. La función MAX

MAX ([ALL|DISTINCT] expression) 

Devuelve el valor máximo de la expresión sin considerar los nulos.MAX se puede usar con columnas numéricas, de caracteres y de datetime, pero no con columnas de bit. No se permiten funciones de agregado ni subconsultas.Utilizar DISTINCT no tiene ningún sentido con MAX (el valor máximo será el mismo si consideramos las repeticiones o no) y sólo se incluye para la compatibilidad con SQL-92.Por ejemplo:

SELECT SUM(ventas) AS VentasTotales, MAX(objetivo) AS MayorObjetivo

FROM oficinas;

Devuelve 9 porque tenemos nueve valores no nulos en la columna region. A la hora de interpretar un COUNT es conveniente no olvidar que cuenta valores no nulos, por ejemplo si interpretáramos la sentencia tal cual se lee, “cuántas regiones tenemos en oficinas”  sería erróneo, realmente estamos obteniendo cuántas oficinas tienen una región asignada.

Para practicar puedes realizar este Ejercicio La función MAX.

5.6. La función MIN

MIN ([ALL|DISTINCT] expression)

Devuelve el valor mínimo de la expresión sin considerar los nulos.MIN se puede usar con columnas numéricas, de caracteres y de datetime, pero no con columnas de bit. No se permiten funciones de agregado ni subconsultas.Utilizar DISTINCT no tiene ningún sentido con MIN (el valor mínimo será el mismo si consideramos las repeticiones o no) y sólo se incluye para la compatibilidad con SQL-92.

Unidad 5. Consultas de resumen (III)

5.7. La función SUM

SUM ([ALL|DISTINCT] expresion )

Devuelve la suma de los valores devueltos por la expresión.Sólo puede utilizarse con columnas numéricas.

El resultado será del mismo tipo aunque puede tener una precisión mayor.

SELECT SUM(importe) FROM pedidos;

87

Page 88: Curso de SQL Server.docx

Obtiene el importe total vendido en todos los pedidos.

SELECT SUM(ventas) AS VentasTotales, MAX(objetivo) AS MayorObjetivo

FROM oficinas;

Devuelve la suma de las ventas de todas las oficinas y de los objetivos de todas las oficinas, el de mayor importe.

Para practicar puedes realizar este Ejercicio La función SUM.

5.8. La función AVG

AVG ([ALL|DISTINCT] expresion )

Devuelve el promedio de los valores de un grupo, para calcular el promedio se omiten los valores nulos.

El grupo de valores lo determina el resultado de la expresión que será un nombre de columna o una expresión basada en una columna o varias del origen de datos.La función se aplica también a campos numéricos, y en este caso el tipo de dato del resultado puede cambiar según las necesidades del sistema para representar el valor del resultado.

Para practicar puedes realizar este Ejercicio La función AVG.

5.9. La función VAR

VAR ([ALL|DISTINCT] expresion )

Devuelve la varianza estadística de todos los valores de la expresión especificada.VAR sólo se puede utilizar con columnas numéricas. Los valores NULL se pasan por alto.

5.10. La función VARP

VARP ([ALL|DISTINCT] expresion )

Devuelve la varianza estadística de la población para todos los valores de la expresión especificada.Sólo se puede utilizar con columnas numéricas. Los valores NULL se pasan por alto.

5.11.  La función STDEV

STDEV ([ALL|DISTINCT] expresion )

Devuelve la desviación típica estadística de todos los valores de la expresión especificada.Sólo se puede utilizar con columnas numéricas. Los valores NULL se pasan por alto.

5.12. La función STDEVP

88

Page 89: Curso de SQL Server.docx

STDEVP ([ALL|DISTINCT] expresion )

Devuelve la desviación estadística estándar para la población de todos los valores de la expresión especificada.Sólo se puede utilizar con columnas numéricas. Los valores NULL se pasan por alto.

5.13. La función GROUPING

GROUPING (nb_columna)

Es una función de agregado que genera como salida una columna adicional con el valor 1 si la fila se agrega mediante el operador CUBE o ROLLUP, o el valor 0 cuando la fila no es el resultado de CUBE o ROLLUP.

Nb_columna tiene que ser una de las columnas de agrupación y la cláusula GROUP BY debe contener  el operador CUBE o ROLLUP.

En el siguiente punto, cuando veamos las cláusulas CUBE y ROLLUP quedará más claro.

Unidad 5. Consultas de resumen (IV)

5.14. Agrupamiento de filas (cláusula GROUP BY).

Hasta ahora las consultas sumarias que hemos visto obtienen totales de todas las filas del origen y producen una única fila de resultado.

Muchas veces cuando calculamos resúmenes nos interesan totales parciales, por ejemplo saber de cada empleado cuánto ha vendido, y cuál ha sido su pedido máximo, de cada cliente cuándo fue la última vez que nos compró, etc.

En todos estos casos en vez de obtener una fila única de resultados necesitamos una fila por cada empleado, cliente, etc.

 Podemos obtener estos subtotales con la cláusula GROUP BY.

GROUP BY [ ALL ] expresion_agrupacion [ ,...n ]

[ WITH { CUBE | ROLLUP } ]

Una consulta con una cláusula GROUP BY agrupa los datos de la tabla origen y produce una única fila resultado por cada grupo formado. Las columnas indicadas en el GROUP BY se llaman columnas de agrupación o agrupamiento .

Cuando queremos realizar una agrupación múltiple, por varias columnas, éstas se indican en la cláusula GROUP BY en el orden de mayor a menor agrupación igual que con la cláusula ORDER BY.

expresion_agrupacion puede ser una columna o una expresión no agregada que haga referencia a una columna devuelta por la cláusula FROM. Un alias de columna que esté definido en la lista de selección no puede utilizarse para especificar una columna de agrupamiento.No se pueden utilizar columnas de tipo text, ntext e image en expresion_agrupacion.

89

Page 90: Curso de SQL Server.docx

En las cláusulas GROUP BY que no contengan CUBE o ROLLUP, el número de columnas de agrupación está limitado por los tamaños de columna de GROUP BY, las columnas de agregado y los valores de agregado que participan en la consulta. Este límite procede del límite de 8.060 bytes de la tabla de trabajo intermedia que se necesita para contener los resultados intermedios de la consulta. Se permite un máximo de 10 expresiones de agrupamiento cuando se especifica CUBE o ROLLUP.

Si en la columna de agrupación existen valores nulos, se generará una fila de resumen para este “valor”, en este caso se considera el valor nulo como otro valor cualquiera.

Ejemplo:

SELECT oficina, count(numemp) AS [Número de empleados]

FROM empleados

GROUP BY oficina;

Resultado:

oficina Número de empleados

NULL 2

11 2

12 3

13 1

21 2

22 1

Hay empleados sin oficinas (con oficina a nulo), estos forman un grupo con el valor NULL en oficina, en este caso hay dos empleados así.

Podemos indicar varias columnas de agrupación.

Ejemplo:

SELECT rep, clie, count(numpedido) AS [Número de pedidos], MAX(importe) AS [Importe máximo]

FROM pedidos

WHERE YEAR(fechapedido) = 1997

GROUP BY  rep, clie

ORDER BY rep, clie;

Resultado:

rep clieNúmero

de pedidosImporte máximo

90

Page 91: Curso de SQL Server.docx

101 2113 1 225,00

102 2106 2 21,30

102 2120 1 37,50

103 2111 2 21,00

105 2103 4 275,00

105 2111 1 37,45

106 2101 1 14,58

107 2109 1 313,50

107 2124 2 24,30

108 2112 1 29,25

108 2114 1 71,00

108 2118 3 14,20

De cada representante obtenemos el número de pedidos y el importe máximo vendido a cada cliente, de las ventas de 1997. La cláusula ORDER BY se ha incluido para que las filas aparezcan ordenadas y quede más claro.

Unidad 5. Consultas de resumen (V)

Hemos dicho que los resúmenes se calculan sobre todas las filas del origen después de haber ejecutado el WHERE, pues ALL permite obtener un resumen de las filas que no cumplen el WHERE.

ALL Incluye todos los grupos y conjuntos de resultados, incluso aquellos en los que no hay filas que cumplan la condición de búsqueda especificada en la cláusula WHERE. Cuando se especifica ALL, se devuelven valores NULL para las columnas de resumen de los grupos que no cumplen la condición de búsqueda. No se puede especificar ALL con los operadores CUBE y ROLLUP.

GROUP BY ALL no se admite en consultas que tienen acceso a tablas remotas si también hay una cláusula WHERE en la consulta.

Por ejemplo, vamos a modificar la consulta anterior:

SELECT rep, clie, count(numpedido) AS [Número de pedidos], MAX(importe) AS [Importe máximo]

FROM pedidos

WHERE YEAR(fechapedido) = 1997

GROUP BY  ALL rep, clie

ORDER BY rep, clie;

91

Page 92: Curso de SQL Server.docx

Resultado:

rep clieNúmero

de pedidosImporte máximo

101 2102 0 NULL

101 2108 0 NULL

101 2113 1 225,00

102 2106 2 21,30

102 2120 1 37,50

103 2111 2 21,00

105 2103 4 275,00

105 2111 1 37,45

106 2101 1 14,58

106 2117 0 NULL

107 2109 1 313,50

107 2124 2 24,30

108 2112 1 29,25

108 2114 1 71,00

108 2118 3 14,20

Cuál ha sido el efecto de añadir ALL? Se han añadido filas para las filas del origen que no cumplen la condición del WHERE pero sin que intervengan en el cálculo de las funciones de agregado.

Por ejemplo el representante 101 tiene pedidos con el cliente 2102 pero estos pedidos no son del año 1997, por eso aparece la primera fila (no estaba en el resultado de la otra consulta) pero con 0 y NULL como resultados de las funciones de agregado.

ROLLUP especifica que, además de las filas que normalmente proporciona GROUP BY, se incluyen filas de resumen en el conjunto de resultados. Los grupos se resumen en un orden jerárquico, desde el nivel inferior del grupo hasta el superior. La jerarquía del grupo se determina por el orden en que se especifican las columnas de agrupamiento. Cambiar el orden de las columnas de agrupamiento puede afectar al número de filas generadas en el conjunto de resultados.

Por ejemplo:

92

Page 93: Curso de SQL Server.docx

SELECT rep, clie, count(numpedido) AS [Número de pedidos], MAX(importe) AS [Importe máximo]

FROM pedidos

WHERE YEAR(fechapedido) = 1997

GROUP BY  rep, clie WITH ROLLUP;

  Resultado:

rep clieNúmero

de pedidosImportemáximo

101 2113 1 225,00

101 NULL 1 225,00

102 2106 1 21,30

102 2120 1 37,50

102 NULL 3 37,50

103 2111 2 21,00

103 NULL 2 21,00

105 2103 4 275,00

105 2111 1 37,45

105 NULL 5 275,00

106 2101 1 14,28

106 NULL 1 14,28

107 2109 1 313,50

107 2124 2 24,30

107 NULL 3 313,50

108 2112 1 29,25

108 2114 1 71,00

108 2118 3 14,20

108 NULL 5 71,00

... ... ... ...

NULL NULL 23 450,00

93

Page 94: Curso de SQL Server.docx

Efecto: Se han añadido automáticamente subtotales por cada nivel de agrupamiento y una línea de totales generales al final. En este caso no hemos incluido ORDER BY porque las filas salen ya ordenadas.

Unidad 5. Consultas de resumen (VI)

CUBE especifica que, además de las filas que normalmente proporciona GROUP BY, deben incluirse filas de resumen en el conjunto de resultados. Se devuelve una fila de resumen GROUP BY por cada posible combinación de grupo y subgrupo del conjunto de resultados. En el resultado se muestra una fila de resumen GROUP BY como NULL, pero se utiliza para indicar todos los valores.

Por ejemplo:

SELECT rep, clie, count(numpedido) AS [Número de pedidos], MAX(importe) AS [Importe máximo]

FROM pedidos

WHERE YEAR(fechapedido) = 1997

GROUP BY  rep, clie WITH CUBE;

Resultado:

rep clieNúmero

de pedidosImportemáximo

101 2113 1 225,00

101 NULL 1 225,00

102 2106 1 21,30

102 2120 1 37,50

102 NULL 3 37,50

103 2111 2 21,00

103 NULL 2 21,00

105 2103 4 275,00

105 2111 1 37,45

105 NULL 5 275,00

106 2101 1 14,28

106 NULL 1 14,28

94

Page 95: Curso de SQL Server.docx

107 2109 1 313,50

107 2124 2 24,30

107 NULL 3 313,50

108 2112 1 29,25

108 2114 1 71,00

108 2118 3 14,20

108 NULL 5 71,00

... ... ... ...

NULL NULL 23 450,00

NULL 2101 1 14,58

NULL 2103 4 275,00

NULL 2106 2 21,30

NULL 2107 1 6,32

NULL 2108 1 56,25

NULL 2109 1 313,50

NULL 2111 3 37,45

NULL 2112 2 450,00

NULL 2113 1 225,00

NULL 2114 1 71,00

NULL 2118 3 14,20

NULL 2120 1 37,50

NULL 2124 2 24,30

Efecto: Obtenemos además de los resultados obtenidos con ROLLUP (los totales por cada representante), los totales por el otro criterio (los totales por cada cliente).El número de filas de resumen del conjunto de resultados se determina mediante el número de columnas que contiene la cláusula GROUP BY. Cada operando (columna) de la cláusula GROUP BY se enlaza según el agrupamiento NULL y se aplica el agrupamiento al resto de los operandos (columnas). CUBE devuelve todas las combinaciones posibles de grupo y subgrupo.

Tanto si utilizamos CUBE como ROLLUP, nos será útil la función de agregado GROUPING.

95

Page 96: Curso de SQL Server.docx

Si cogemos por ejemplo la primera fila remarcada (101 NULL …) el valor NULL, no sabemos si se refiere a una fila de subtotal o a que el representante 101 ha realizado un pedido sin número de cliente. Para poder salvar este problema se utiliza la función de agregado GROUPING.

SELECT rep, clie, count(numpedido) AS [Número de pedidos], MAX(importe) AS [Importe máximo], GROUPING(clie) AS [Fila resumen]

FROM pedidos

WHERE YEAR(fechapedido) = 1997

GROUP BY  rep, clie WITH ROLLUP;

rep clieNúmero

de pedidosImportemáximo

FilaResumen

101 2113 1 225,00 0

101 NULL 1 225,00 1

102 2106 2 21,30 0

102 2120 1 37,50 0

102 NULL 3 37,50 1

103 2111 2 21,00 0

Las filas que corresponden a subtotales aparecen con un 1 y las normales con un cero.

Ahora que estamos más familiarizados con las columnas de agrupamiento debemos comentar una regla a no olvidar:

EN LA LISTA DE SELECCIÓN DE UNA CONSULTA DE RESUMEN UN NOMBRE DE COLUMNA NO PUEDE APARECER FUERA DE UNA FUNCIÓN DE AGREGADO SI NO ES UNA COLUMNA DE AGRUPACIÓN.

Unidad 5. Consultas de resumen (VII)

5.15. Selección sobre grupos de filas, la cláusula HAVING

Cuando queremos incluir una cláusula de selección sobre las filas del origen, utilizamos la cláusula WHERE, pero cuando estamos definiendo una consulta de resumen, no podemos utilizar esta cláusula para seleccionar filas del resultado ya que cada una de éstas representa un grupo de filas de la tabla original. Para seleccionar filas del resumen tenemos la cláusula HAVING.

HAVING condición de búsqueda

HAVING funciona igual que la cláusula WHERE pero en vez de actuar sobre las filas del origen de datos, actúa sobre las filas del resultado, selecciona grupos de filas por lo que la condición de búsqueda sufrirá alguna limitación, la misma que para la lista de

96

Page 97: Curso de SQL Server.docx

selección:Ejemplo:

SELECT oficina, count(numemp) AS [Número de empleados]

FROM empleados

GROUP BY oficina

HAVING COUNT(numemp)<2;

Resultado:

oficina Número de empleados

13 1

22 1

Esta SELECT es la misma que la del primer ejemplo del apartado sobre la cláusula GROUP BY, la diferencia es que le hemos añadido la cláusula HAVING, que hace que del resultado sólo se visualicen los grupos que cumplan la condición. Es decir sólo aparecen las oficinas que tienen menos de 2 empleados.

Siempre que en una condición de selección haya una función de columna, la condición deberá incluirse en la cláusula HAVING, además, como HAVING filtra filas del resultado, sólo puede contener expresiones (nombres de columnas, expresiones, funciones…) que también pueden aparecer en la lista de selección, por lo que también se aplica la misma regla a no olvidar:

EN LA CLÁUSULA HAVING UN NOMBRE DE COLUMNA NO PUEDE APARECER FUERA DE UNA FUNCIÓN DE AGREGADO SI NO ES UNA COLUMNA DE AGRUPACIÓN.

Las expresiones que pongamos en HAVING no tienen porqué aparecer en la lista de selección, por ejemplo en la SELECT anterior se podía haber escrito:

HAVING SUM(ventas)=10000

Unidad 6. Las subconsultas (I)

6.1. Introducción

Una subconsulta es una consulta que aparece dentro de otra consulta o subconsultas, en la lista de selección o en la cláusula WHERE o HAVING, originalmente no se podían incluir en la lista de selección.

Una subconsulta se denomina también consulta o selección interna, mientras que la instrucción que contiene la subconsulta es conocida como consulta o selección externa.

Aparece siempre encerrada entre paréntesis y tiene la misma sintaxis que una sentencia SELECT normal con alguna limitación:

No puede incluir una cláusula COMPUTE o FOR BROWSE y sólo puede incluir una cláusula ORDER BY cuando se especifica también una cláusula TOP.

97

Page 98: Curso de SQL Server.docx

Una subconsulta puede anidarse en la cláusula WHERE o HAVING de una instrucción externa SELECT, INSERT, UPDATE o DELETE, o bien en otra subconsulta. Se puede disponer de hasta 32 niveles de anidamiento, aunque el límite varía dependiendo de la memoria disponible y de la complejidad del resto de las expresiones de la consulta. Hay que tener en cuenta que para cada fila de la consulta externa, se calcula la subconsulta, si anidamos varias consultas, el número de veces que se ejecutarán las subconsultas ¡puede dispararse!

Cuando la subconsulta aparece en la lista de selección de otra consulta, deberá devolver un solo valor, de lo contrario provocará un error.

Ejemplo de subconsulta: Listar los empleados cuya cuota no supere el importe vendido por el empleado.

SELECT nombre

FROM empleados

WHERE cuota <= (SELECT SUM(importe)

FROM pedidos

WHERE rep = numemp);

Por cada fila de la tabla de empleados (de la consulta externa) se calcula la subconsulta y se evalúa la condición, por lo que utilizar una subconsulta puede en algunos casos ‘ralentizar’ la consulta, en contrapartida se necesita menos memoria que una composición de tablas.

Muchas de las instrucciones Transact-SQL que incluyen subconsultas se pueden formular también utilizando composiciones de tablas. Otras preguntas se pueden formular sólo con subconsultas.

En Transact-SQL, normalmente no hay una regla fija en cuanto a diferencias de rendimiento entre una instrucción que incluya una subconsulta y una versión semánticamente equivalente que no la incluya.

Podremos utilizar una subconsulta siempre y cuando no se quiera que aparezcan en el resultado columnas de la subconsulta ya que si una tabla aparece en la subconsulta y no en la consulta externa, las columnas de esa tabla no se pueden incluir en la salida (la lista de selección de la consulta externa).

Tenemos tres tipos de subconsultas:

Las que devuelven un solo valor, aparecen en la lista de selección de la consulta externa o con un operador de comparación sin modificar.

Las que generan una columna de valores, aparecen con el operador IN o con un  operador de comparación modificado con  ANY, SOME o ALL.

Las que pueden generar cualquier número de columnas y filas, son utilizadas en pruebas de existencia especificadas con EXISTS.

A lo largo del tema las estudiaremos todas.

Antes de terminar con la introducción queda comentar el concepto de referencia externa muy útil en las subconsultas.

A menudo, es necesario, dentro del cuerpo de una subconsulta, hacer referencia al valor de una columna en la fila actual de la consulta externa, el nombre de columna de la

98

Page 99: Curso de SQL Server.docx

consulta externa dentro de la subconsulta recibe el nombre de referencia externa, ya que hace referencia a una columna externa.

En el ejemplo anterior numemp es una referencia externa, no es una columna del origen de datos de la subconsulta (pedidos), es una columna del origen de la consulta externa (empleados).

Hay que tener en cuenta de cómo se ejecuta la consulta; por cada fila de la consulta externa se calcula el resultado de la subconsulta y se evalúa la comparación.En el ejemplo, se coge el primer empleado (numemp= 101, por ejemplo) y se calcula la subconsulta sustituyendo numemp por el valor 101, se calcula la suma de los pedidos del rep = 101, y el resultado se compara con la cuota de ese empleado, y así se repite el proceso con todas las filas de empleados.

El nombre de una columna dentro de la subconsulta se presupone del origen de datos de la subconsulta y, sólo si no se encuentra en ese origen, la considera como columna externa y la busca en el origen de la consulta externa.

Por ejemplo:

SELECT oficina, ciudad

FROM oficinas

WHERE objetivo > (SELECT SUM(ventas)

FROM empleados

WHERE oficina = oficina);

 La columna oficina se encuentra en los dos orígenes (oficinas y empleados) pero esta consulta no dará error (no se nos pedirá cualificar los nombres como pasaría en una composición de tablas), dentro de la subconsulta se considera oficina el campo de la tabla empleados. Con lo que compararía la oficina del empleado con la misma oficina del empleado y eso no es lo que queremos, queremos comparar la oficina del empleado con la oficina de oficinas, lo escribiremos pues así para forzar a que busque la columna en la tabla oficinas.

SELECT oficina, ciudad

FROM oficinas

WHERE objetivo > (SELECT SUM(ventas)

FROM empleados

WHERE oficina = oficinas.oficina);

Unidad 6. Las subconsultas (II)

6.2. Subconsultas de resultado único

Existen subconsultas que deben obligatoriamente devolver un único valor, son las que aparecen en la lista de selección de la consulta externa o las que aparecen en WHERE o HAVING combinadas con un operador de comparación sin modificar.

Los operadores de comparación sin modificar son los operadores de comparación que vimos con la cláusula WHERE.

99

Page 100: Curso de SQL Server.docx

Sintaxis:

<expresion> {=|<>|!=|>|>=|!>|<|<=|!<} <subconsulta>

En este caso la segunda expresión será una subconsulta, con una sola columna en la lista de selección y deberá devolver una única fila como mucho.Ese valor único será el que se compare con el resultado de la primera expresión.Si la subconsulta no devuelve ninguna fila, la comparación opera como si la segunda expresión fuese nula.Si la subconsulta devuelve más de una fila o más de una columna, da error.Ejemplo:

SELECT nombre

FROM empleados

WHERE cuota <= (SELECT SUM(importe)

FROM pedidos

WHERE rep = numemp);

La subconsulta devuelve una sola columna y como mucho una fila ya que es una consulta de resumen sin cláusula GROUP BY.

Para practicar puedes realizar este Ejercicio Subconsultas de resultado único.

6.3. Subconsultas de lista de valores

Otro tipo de subconsultas son las que devuelven una lista de valores en forma de una columna y cero, una o varias filas.

Estas consultas aparecen en las cláusulas WHERE o HAVING combinadas con el operador IN o con comparaciones modificadas.

6.4. El operador IN con subconsulta

<expresion> IN subconsulta

IN examina si el valor de expresion es uno de los valores incluidos en la lista de valores generados por la subconsulta.

La subconsulta tiene que generar valores de un tipo compatible con la expresión.

Ejemplo:

SELECT *

FROM empleados

WHERE oficina IN (SELECT oficina

FROM oficinas

WHERE region = 'Este');

100

Page 101: Curso de SQL Server.docx

Por cada empleado se calcula la lista de las oficinas del Este (nº de oficina) y se evalúa si la oficina del empleado está en esta lista. Obtenemos pues los empleados de oficinas del Este.

numemp nombre edad oficina titulo contrato jefe cuota ventas

101Antonio Viguer

45 12representante

1986-10-20

104 30000,00 30500,00

103Juan Rovira

29 23representante

1987-03-01

104 27500,00 28600,00

104José González

33 23 dir ventas1987-05-19

106 20000,00 14300,00

105Vicente Pantalla

37 13representante

1988-02-12

104 35000,00 36800,00

106Luis Antonio

52 11 dir general1988-06-14

NULL 27500,00 29900,00

Si la subconsulta no devuelve ninguna fila:

SELECT *

FROM empleados

WHERE oficina IN (SELECT oficina

FROM oficinas

WHERE region = 'Otro');

La lista generada está vacía por lo que la condición IN devuelve FALSE y en este caso no sale  ningún empleado.

Muchas veces la misma pregunta se puede resolver mediante una composición de tablas.

SELECT empleados.*

FROM Empleados INNER JOIN oficinas ON empleados.oficina = oficinas.oficina

WHERE region = 'Este';

Esta sentencia es equivalente. En el resultado no queremos ver ninguna columna de la tabla oficinas, el JOIN lo tenemos sólo para la pregunta, en este caso pues se puede sustituir por una subconsulta.

Unidad 6. Las subconsultas (III)

Si combinamos el operador IN con NOT obtenemos el operador NOT IN.

101

Page 102: Curso de SQL Server.docx

<expresion> NOT IN subconsulta

Devuelve TRUE si el valor de la expresión no está en la lista de valores devueltos por la subconsulta.

SELECT *

FROM empleados

WHERE oficina NOT IN (SELECT oficina

FROM oficinas

WHERE region = 'Este');

Devuelve los empleados cuya oficina no esté en la lista generada por la subconsulta, es decir empleados que trabajan en oficinas que no son del Este.

OJO con NOT IN.

Hay que tener especial cuidado con los valores nulos cuando utilizamos el operador NOT IN porque el resultado obtenido no siempre será el deseado por ejemplo:

* En la consulta anterior no salen los empleados que no tienen oficina ya que para esos empleados la columna oficina contiene NULL por lo que no se cumple el NOT IN.

* Si la subconsulta no devuelve ninguna fila, la condición se cumplirá para todas las filas de la consulta externa, en este caso todos los empleados.

* Si la subconsulta devuelve algún valor NULL, la condición NOT IN es NULL lo que nos puede ocasionar algún problema.

Por ejemplo, queremos obtener las oficinas que no están asignadas a ningún empleado.

SELECT *

FROM Oficinas

WHERE oficina NOT IN (SELECT oficina

FROM empleados);

Esta consulta no devuelve ninguna fila cuando sí debería ya que hay oficinas que nos están asignadas a ningún empleado. El problema está en que la columna oficina de la tabla empleados admite nulos por lo que la subconsulta devuelve valores nulos en todos los empleados que no están asignados a ninguna oficina. Estos valores nulos hacen que no se cumpla el NOT IN. La solución pasa por eliminar estos valores molestos:

SELECT *

FROM Oficinas

WHERE oficina NOT IN (SELECT oficina

FROM empleados

WHERE oficina IS NOT NULL);

102

Page 103: Curso de SQL Server.docx

En el primer ejemplo no tenemos ese problema porque la columna oficina en oficinas no admite nulos.

A diferencia de IN, NOT IN no siempre puede resolverse con una composición:

SELECT numemp AS [IN]

FROM empleados

WHERE numemp IN (SELECT rep

FROM pedidos

WHERE fab = 'ACI');

Se puede resolver con una composición:

SELECT DISTINCT empleados.numemp AS [=]

FROM Empleados INNER JOIN pedidos ON numemp = rep

WHERE fab = 'ACI';

En este caso, como un empleado puede tener varios pedidos hay que añadir DISTINCT para eliminar las repeticiones de empleados (si un empleado tiene varios pedidos de ACI aparecería varias veces).

Sin embargo esta sentencia con NOT IN, queremos los empleados que no tienen pedidos de ACI:

SELECT numemp AS [NOT IN]

FROM empleados

WHERE numemp NOT IN (SELECT rep

FROM pedidos

WHERE fab = 'ACI');

No se puede resolver con una composición:

SELECT DISTINCT empleados.numemp AS [<>]

FROM Empleados INNER JOIN pedidos ON numemp = rep

WHERE fab <> 'ACI';

Esta consulta devuelve los empleados que tienen pedidos que no son de ACI, pero un empleado puede tener pedidos de ACI y otros de otros fabricantes y por estos otros saldría en el resultado cuando sí tiene pedidos de ACI y no debería salir.Hay que tener mucho cuidado con este tipo de preguntas.

Para practicar puedes realizar este Ejercicio El operador IN con subconsulta.

103

Page 104: Curso de SQL Server.docx

Unidad 6. Las subconsultas (IV)

6.5. La comparación modificada (ANY, ALL)

Los operadores de comparación que presentan una subconsulta se pueden modificar mediante las palabras clave ALL, ANY o SOME. SOME es un equivalente del estándar de SQL-92 de ANY.

Se utiliza este tipo de comparación cuando queremos comparar el resultado de la expresión con una lista de valores y actuar en función del modificador empleado.

El test ANY

<expresion> {=|<>|!=|>|>=|!>|<|<=|!<} {ANY|SOME} subconsulta

ANY significa que, para que una fila de la consulta externa satisfaga la condición especificada, la comparación se debe cumplir para al menos un valor de los devueltos por la subconsulta.

Por cada fila de la consulta externa se evalúa la comparación con cada uno de los valores devueltos por la subconsulta y si la comparación es True para alguno de los valores ANY es verdadero, si la comparación no se cumple con ninguno de los valores de la consulta, ANY da False a no ser que todos los valores devueltos por la subconsulta sean nulos en tal caso ANY dará NULL.

Si la subconsulta no devuelve filas ANY da False incluso si expresion es nula.

Ejemplo:

SELECT *

FROM empleados

WHERE cuota > ANY (SELECT cuota

FROM empleados empleados2

WHERE empleados.oficina = empleados2.oficina);

Obtenemos los empleados que tienen una cuota superior a la cuota de alguno de sus compañeros de oficina, es decir los empleados que no tengan la menor cuota de su oficina.

En este caso hemos tenido un alias de tabla en la subconsulta (empleados2) para poder utilizar una referencia externa.

Para practicar puedes realizar este Ejercicio Comparación modificada ANY.

El test ALL

<expresion> {=|<>|!=|>|>=|!>|<|<=|!<} ALL subconsulta

Con el modificador ALL, para que se cumpla la condición, la comparación se debe cumplir con cada uno de los valores devueltos por la subconsulta.

Si la subconsulta no devuelve ninguna fila ALL da True.

104

Page 105: Curso de SQL Server.docx

SELECT *

FROM empleados

WHERE cuota > ALL (SELECT cuota

FROM empleados empleados2

WHERE empleados.oficina = empleados2.oficina);

En el ejemplo anterior obtenemos los empleados que tengan una cuota superior a todas las cuotas de la oficina del empleado. Podríamos pensar que obtenemos el empleado de mayor cuota de su oficina pero no lo es, aquí tenemos un problema, la cuota del empleado aparece en el resultado de subconsulta por lo tanto > no se cumplirá para todos los valores y sólo saldrán los empleados que no tengan oficina (para los que la subconsulta no devuelve filas).

Para salvar el problema tendríamos que quitar del resultado de la subconsulta la cuota del empleado modificando el WHERE:

WHERE empleados.oficina = empleados2.oficina

AND empleados.numemp <> empleados2.numemp);

De esta forma saldrían los empleados que tienen una cuota mayor que cualquier otro empleado de su misma oficina.

O bien

WHERE empleados.oficina = empleados2.oficina

AND empleados.cuota <> empleados2.cuota);

Para no considerar los empleados que tengan la misma cuota que el empleado. En este caso saldrían los empleados con la mayor cuota de sus oficina, pero si dos empleados tienen la misma cuota superior, saldrían, hecho que no sucedería con la otra versión.

Cuando la comparación es una igualdad, = ANY es equivalente a IN y <> ALL es equivalente a NOT IN (con los mismos problemas).

Unidad 6. Las subconsultas (V)

6.6. Subconsultas con cualquier número de columnas (EXISTS)

Existe otro operador de subconsulta con el que la subconsulta puede devolver más de una columna, el operador EXISTS.

En este caso la sintaxis es algo diferente:

WHERE [NOT] EXISTS subconsulta

No se realiza ninguna comparación con los valores devueltos por la subconsulta, simplemente se evalúa si la subconsulta devuelve alguna fila, en este caso EXISTS será True y si la subconsulta no devuelve ninguna fila, EXISTS será False.

105

Page 106: Curso de SQL Server.docx

Ejemplo:

SELECT *

FROM empleados

WHERE EXISTS (SELECT *

FROM pedidos

WHERE numemp = rep and fab ='ACI');

Obtenemos los empleados que tengan un pedido del fabricante ACI. Por cada empleado, se calcula la subconsulta (obteniendo los pedidos de ese empleado y con fabricante ACI), si existe alguna fila, el empleado sale en el resultado, si no, no sale.

Cuando se utiliza el operador EXISTS es muy importante añadir una referencia externa, no es obligatorio pero en la mayoría de los casos será necesario. Veámoslo con ese mismo ejemplo, si quitamos la referencia externa:

SELECT *

FROM empleados

WHERE EXISTS (SELECT *

FROM pedidos

WHERE fab ='ACI');

Sea el empleado que sea,  la subconsulta siempre devolverá filas (si existe algún pedido cuyo fabricante sea ACI) o nunca, indistintamente del empleado que sea, por lo que se obtendrán todos los empleados o ninguno para que el resultado varíe según las filas de la consulta externa habrá que incluir una referencia externa.

Otra cosa a tener en cuenta es que la lista de selección de una subconsulta que se especifica con EXISTS casi siempre consta de un asterisco (*). No hay razón para enumerar los nombres de las columnas porque no se van a utilizar y supone un trabajo extra para el sistema.

Si utilizamos NOT EXISTS el resultado será el contrario.

SELECT *

FROM empleados

WHERE NOT EXISTS (SELECT *

FROM pedidos

WHERE fab ='ACI' AND rep=numemp);

Devuelve los empleados que no tienen ningún pedido de ACI.

Unidad 7. Actualización de datos (I)

7.1. Introducción

106

Page 107: Curso de SQL Server.docx

Hasta ahora hemos trabajado con tablas que tenían datos introducidos y cuando nos ha hecho falta hemos añadido nuevos datos en las mismas y hemos modificado algún dato directamente desde el entorno de SSMS, en este tema veremos cómo hacerlo con instrucciones de Transact-SQL.

Seguimos en el DML porque las instrucciones que veremos actúan sobre los datos de la base de datos no sobre su definición y tenemos tres tipos de operaciones posibles:

Insertar nuevas filas en una tabla.

Modificar datos ya almacenados.

Eliminar filas de una tabla.

7.2. Insertar creando una nueva tabla

Una forma de insertar datos es crear una tabla que incluya los datos de otra. Esta es la sentencia SELECT... INTO.

SELECT ...

INTO nb_NuevaTabla

FROM ...

nb_NuevaTabla  es el nombre de la tabla que se va a crear, si en la base de datos ya hay una tabla con ese nombre, el sistema genera un error y no se ejecuta la sentencia.

En la nueva tabla las columnas tendrán el mismo tipo y tamaño que las columnas del resultado de la SELECT,  se llamarán con el nombre de alias de la columna o en su defecto con el nombre de la columna, pero no se transfiere ninguna otra propiedad del campo o de la tabla como por ejemplo las claves e índices.

Si retomamos el ejemplo del punto anterior:

CREATE TABLE trabajo (col1 INT, col2 VARCHAR(20), col3 MONEY);

INSERT INTO trabajo SELECT oficina, ciudad, ventas

FROM oficinas

WHERE region = 'Centro';

Se podría obtener el mismo resultado con una sola instrucción:

SELECT oficina AS col1, ciudad AS col2, ventas AS col3

INTO trabajo

FROM oficinas

WHERE region = 'Centro'

Si se tiene poca experiencia en esta instrucción, lo mejor es primero escribir la SELECT que permite obtener las filas a insertar y una vez la tenemos añadir la cláusula INTO destino delante de FROM.

107

Page 108: Curso de SQL Server.docx

Para practicar puedes realizar este Ejercicio Insertar datos creando una nueva tabla.

7.3. Insertar en una tabla existente  INSERT INTO

La inserción de nuevos datos en una tabla, se realiza añadiendo filas enteras a la tabla, la sentencia SQL que lo permite es la orden INSERT (o también denominada INSERT INTO).De la sentencia INSERT completa, nosotros estudiaremos la sintaxis más utilizada y estándar:

INSERT [INTO] <destino>

{

[(lista_columnas)]

{VALUES ({DEFAULT|NULL|expresion}[ ,...n ])

|tabla_derivada

}

}

|DEFAULT VALUES

[;]

<destino> ::=

{

[nbBaseDatos.nbEsquema. | nbEsquema.]nbTablaVista

}

Con esta instrucción podemos insertar una fila de valores determinados o un conjunto de filas derivadas de otra consulta.

Unidad 7. Actualización de datos (II)

7.4. Insertar una fila de valores

Para insertar una fila de valores utilizamos la sintaxis:

INSERT [INTO] <destino> [(lista_columnas)]

VALUES ({DEFAULT|NULL|expresion}[ ,...n ]) [;]

La palabra reservada INTO es opcional y no añade funcionalidad a la instrucción, originalmente era obligatoria.

Después de indicar que queremos insertar, debemos indicar dónde, mediante <destino>.<destino> es el nombre de la tabla donde queremos insertar, puede ser un nombre de tabla o un nombre de vista.

108

Page 109: Curso de SQL Server.docx

Si utilizamos una vista, y ésta tiene un origen basado en varias tablas, en su lista de selección deberán aparecer columnas de una sola tabla (no podemos insertar datos en varias tablas a la vez).

Con la cláusula VALUES indicamos entre paréntesis los valores a insertar, separados por comas.Cada valor se puede indicar mediante:

una expresión que normalmente será una constante,

mediante la palabra reservada DEFAULT que indica ‘valor por defecto’ en este caso la columna se rellenará con el valor predeterminado de la columna, si la columna no tiene  DEFAULT se sustituirá por el valor nulo NULL. 

Mediante la palabra reservada NULL valor nulo.

Delante de VALUES, de forma opcional podemos indicar una lista de columnas entre paréntesis. Las columnas son columnas del destino.

 Cuando indicamos nombres de columnas, esas columnas serán las que reciban los valores a insertar, la asignación de valores se realiza por posición, la primera columna recibe el primer valor, la segunda columna el segundo, y así sucesivamente.

En la lista, las columnas pueden estar en cualquier orden y también se pueden omitir algunas columnas.

Una columna que no aparezca en la lista de columnas se rellenará de acuerdo a su definición:

con su valor por defecto si está definida con la cláusula DEFAULT

con el valor de identidad incremental siguiente  si tiene la propiedad IDENTITY.

con el valor calculado si es una columna calculada.

con el valor NULL , en cualquier otro caso y si la columna lo admite.

Cuando no se indica una lista de columnas el sistema asume por defecto todas las columnas de la tabla y en el mismo orden que aparecen en la definición de la tabla, en este caso, los valores se tienen que especificar en el mismo orden que las columnas en la definición de la tabla, y se tiene que especificar un valor por cada columna ya que los valores se rellenan por posición, la primera columna recibe el primer valor, la segunda columna el segundo, y así sucesivamente.

En cualquier caso, el número de valores debe coincidir con el número de columnas y los tipos de dato de los valores deben ser compatibles con las columnas.

Aunque pueda parecer más engorroso escribir la lista de columnas, es un hábito recomendable, hace que la sentencia sea más fácil de leer y mantener (cuando leemos la sentencia sabemos en qué columnas asignamos los valores sin necesidad de consultar la definición de la tabla) y evita que se tenga que cambiar la sentencia si se modifica el esquema de la tabla (si el orden de las columnas dentro de la tabla cambia).

Los registros se agregan al final de la tabla.

Cuando se insertan nuevas filas en una tabla, el sistema comprobará que la nueva fila no infrinja ninguna regla de integridad, por ejemplo no podremos asignar a una columna PRIMARY KEY un valor nulo o que ya exista en la tabla, a una columna UNIQUE un valor que ya exista en la tabla, a una columna NOT NULL un valor NULL, a una clave ajena (FOREIGN KEY) un valor que no exista en la tabla de referencia.

109

Page 110: Curso de SQL Server.docx

De producirse alguna de las situaciones anterior, la instrucción genera un mensaje de error y la fila no se inserta.

Ejemplos.

INSERT INTO oficinas (oficina, ciudad) VALUES (26, 'Elx');

En este caso hemos indicado sólo dos columnas y dos valores, las demás columnas se rellenan con el valor por defecto si lo tiene (DEFAULT) o con NULL. Si alguna columna no nombrada no admite nulos ni tiene cláusula DEFAULT definida, la instrucción dará error.

INSERT INTO oficinas

VALUES (27,'Móstoles','Centro',default ,null, default)

Aquí no hemos indicado una lista de columnas luego los valores se tienen que indicar en el mismo orden que las columnas dentro de la tabla, si nos equivocamos de orden, el valor se guardará en una columna errónea (si los tipos son compatibles) o generará un mensaje de error y la fila no se insertará (si los tipos no son compatibles).

Unidad 7. Actualización de datos (III)

7.5. Inserción de varias filas

Si los valores que queremos insertar los tenemos en otras tablas, podemos insertar varias filas a la vez indicando una consulta que genere las filas de valores a insertar. En este caso utilizamos la sintaxis:

INSERT [INTO] <destino>  [(lista_columnas)]

tabla_derivada [;]

<destino> y lista_columnas funcionan igual que en el punto anterior.

Tabla_derivada es cualquier instrucción SELECT válida que devuelva filas con los datos que se van a cargar en el destino.

Cada fila devuelta por la SELECT es una lista de valores que se intentará insertar como con la cláusula VALUES, por lo que las columnas devueltas por la SELECT deberán cumplir las mismas reglas que los valores de la lista de valores anteriores.

Ejemplo:

CREATE TABLE trabajo (col1 INT, col2 VARCHAR(20), col3 MONEY);

Creamos una tabla trabajo de 3 columnas

INSERT INTO trabajo SELECT oficina, ciudad, ventas

FROM oficinas

WHERE region = 'Centro';

110

Page 111: Curso de SQL Server.docx

Insertamos en trabajo el resultado de la SELECT (el número de oficina, ciudad y ventas de las oficinas del Centro).

En este caso no hemos incluido una lista de columnas, por lo que en la SELECT tenemos que generar los valores en el mismo orden que en trabajo.

Si hubiesemos escrito:

INSERT INTO trabajo SELECT ciudad, oficina, ventas

FROM oficinas

WHERE region = 'Centro';

Hubiese dado error porque la columna col1 es INT y el valor a asignar es texto (el nombre de la ciudad de la oficina).

INSERT INTO trabajo (col2, col1)

SELECT ciudad, oficina

FROM oficinas

WHERE region = 'Este';

En este caso hemos incluido una lista de columnas, la SELECT debe generar los valores correspondientes, y col3 que no se rellena explícitamente se rellenará con NULL porque la columna col3 no está definida como columna calculada, ni con DEFAULT, ni IDENTITY y además admite nulos.

Para practicar puedes realizar este Ejercicio Insertar varias filas.

7.6. Insertar una fila de valores por defecto

TRANSACT-SQL nos permite insertar una fila de valores por defecto utilizando la sintaxis:

INSERT [INTO] <destino> DEFAULT VALUES

[;]

Hace que la nueva fila contenga los valores predeterminados definidos para cada columna.Hay que tener en cuenta una serie de aspectos al utilizar esta instrucción:Puede generar filas duplicadas en la tabla si los valores que se generan son siempre los mismos. Si la tabla tiene una clave principal, esta tendrá que estar basada en una columna con la propiedad IDENTITY para que se generen valores diferentes automáticamente.Si una columna está definida como NOT NULL tendrá que incluir un DEFAULT o ser una columna calculada con una expresión compatible.

Unidad 7. Actualización de datos (IV)

7.7. Modificar datos almacenados - UPDATE

111

Page 112: Curso de SQL Server.docx

La sentencia UPDATE modifica los valores de una o más columnas en  las filas seleccionadas de una única tabla.

Para modificar los datos de una tabla es necesario disponer del privilegio UPDATE sobre dicha tabla.

UPDATE

   [ TOP ( expression ) [ PERCENT ] ]

   <destino>

   SET { nbcolumna = { expresion | DEFAULT | NULL }

       } [ ,...n ]

   [ FROM{ <origen> }]

   [ WHERE <condicion> ]

 [;]

<destino> ::=

{   

  [nbBaseDatos.[nbEsquema.]| nbEsquema.]nbTablaVista

}

Con <destino> indicamos la tabla que se va a actualizar.La cláusula SET especifica qué columnas van a modificarse y con qué valor, el valor se puede expresar mediante una expresión, la palabra DEFAULT que equivale al valor predeterminado de la columna, o el valor nulo NULL.

Las columnas de identidad no se pueden actualizar.

Expresión en cada asignación  debe generar un valor del tipo de dato apropiado para la columna indicada. La expresión debe ser calculable basada en los valores de la fila actualmente en actualización. Si para el cálculo se utiliza una columna que también se modifica, el valor que se utilizará es el de antes de la modificación, lo mismo para la condición del WHERE.

Expresión también puede ser una subconsulta siempre y cuanto devuelva un único valor y cumpla las condiciones anteriormente expuestas.

Por ejemplo:

UPDATE oficinas SET ventas = 0;

Actualiza todas las filas de la tabla oficinas dejando el campo ventas con el valor cero.Si el campo ventas está definido con un valor predeterminado 0, la sentencia anterior equivale a:

UPDATE oficinas SET ventas = DEFAULT;

Si lo que queremos es dejar el campo a nulo:

UPDATE oficinas SET ventas = NULL;

112

Page 113: Curso de SQL Server.docx

En una misma sentencia podemos actualizar varias columnas, sólo tenemos que indicar las distintas asignaciones separadas por comas:

UPDATE oficinas SET ventas = 0, objetivo = 0;

Los nombres de columna pueden especificarse en cualquier orden.

Si no queremos actualizar todas las filas de la tabla sino unas cuantas, utilizaremos la cláusula TOP, o unas determinadas, utilizaremos la cláusula WHERE.

TOP ( expresion ) [ PERCENT ]

Especifica el número o porcentaje de filas aleatorias que se van a modificar. expression debe generar un valor numérico e indica el número de filas a modificar empezando por el principio. Como en la SELECT, si añadimos la palabra PERCENT, el número representado por expresión se refiere al porcentaje de filas a modificar sobre el total. La cláusula TOP funciona casi igual que en la SELECT pero en este caso, las filas no se ordenan, y la expresión debe ir entre paréntesis.

Por ejemplo:

UPDATE TOP (10) PERCENT oficinas

SET ventas = 0;

Actualiza el 10% de filas de la tabla oficinas.

[ WHERE <condicion> ]

Utilizamos la cláusula WHERE para filtrar las filas a actualizar. Se actualizarán todas las filas que cumplan la condición. Por ejemplo si queremos actualizar sólo las oficinas del Este:

UPDATE oficinas

SET ventas = 0

WHERE region = 'Este';

Cuando para la condición de la cláusula WHERE necesitamos un dato de otra tabla podemos utilizar una subconsulta:

UPDATE empleados SET ventas = 0

WHERE oficina IN (SELECT oficina

FROM oficinas

WHERE region = 'Este');

Cuando el campo de la otra tabla se utiliza para la cláusula SET, entonces debemos utilizar la cláusula FROM.

113

Page 114: Curso de SQL Server.docx

La cláusula FROM permite definir un origen de datos basado en varias tablas, y ese origen será el utilizado para realizar la actualización.

Por ejemplo queremos actualizar el importe de los pedidos con el precio de la tabla productos.

UPDATE pedidos SET importe = cant * precio

FROM pedidos INNER JOIN productos

ON fab = idfab AND producto = idproducto;

Modificamos la tabla pedidos dejando en la columna importe el resultado de multiplicar la cantidad del pedido por el precio del producto que se encuentra en la tabla productos.

Si la actualización de una fila infringe una restricción o una regla, infringe la configuración de valores NULL de la columna o si el nuevo valor es de un tipo de datos incompatible con la columna, se cancela la instrucción, se devuelve un error y no se actualiza ningún registro.

Cuando una instrucción UPDATE encuentra un error aritmético (error de desbordamiento, división por cero o de dominio) durante la evaluación de la expresión, la actualización no se lleva a cabo. El resto del lote no se ejecuta y se devuelve un mensaje de error.

Además del permiso de UPDATE, se requieren permisos SELECT para la tabla que se actualiza si la instrucción UPDATE contiene una cláusula WHERE o en el caso de que el argumento expression de la cláusula SET utilice una columna de la tabla, y permisos SELECT para la tabla del origen si utilizamos una cláusula FROM o un WHERE con subconsulta.

Unidad 7. Actualización de datos (V)

7.8. Eliminar filas - DELETE

La sentencia DELETE elimina filas de una tabla. Si se borran todas las filas, o se borra la única fila de una tabla, la definición de la tabla no desaparece, sólo que la tabla se queda vacía.

DELETE

    [ TOP ( expression ) [ PERCENT ] ] [ FROM ] <destino>

    [ FROM <origen>]

    [ WHERE < condicion>]

[; ]

<destino> ::=

{   

  [nbBaseDatos. nbEsquema. | nbEsquema.]nbTablaVista

}

Con esta instrucción podemos eliminar una o varias filas de una tabla.

114

Page 115: Curso de SQL Server.docx

La palabra FROM (la primera) es opcional (originalmente era obligatorio) y no añade funcionalidad sólo sirve para introducir el destino.

<destino> es el nombre de la tabla de donde queremos eliminar las filas, puede ser un nombre de tabla o un nombre de vista (de momento basada en una sólo tabla).La segunda cláusula FROM sirve para indicar un origen que permita una condición de WHERE sobre una tabla diferente de destino.

La instrucción básica sería pues:

DELETE oficinas;

Equivalente a:

DELETE FROM oficinas;

Con esta instrucción eliminamos todas las filas de la tabla oficinas.

La cláusula WHERE permite eliminar determinadas filas, indica una condición que deben cumplir las filas que se eliminan.

Por ejemplo:

DELETE oficinas

WHERE region = ’Este’;

Elimina las oficinas del Este.

TOP ( expresion ) [ PERCENT ]

Especifica el número o porcentaje de filas aleatorias que se van a eliminar. expression debe generar un valor numérico e indica el número de filas a eliminar empezando por el principio. Como en la SELECT, si añadimos la palabra PERCENT, el número representado por expresión se refiere al porcentaje de filas a eliminar sobre el total. La cláusula TOP funciona casi igual que en la SELECT pero en este caso, las filas no se ordenan, y la expresión debe ir entre paréntesis.

Por ejemplo:

DELETE TOP (10) PERCENT

FROM oficinas;

Elimina el 10% de filas de la tabla oficinas.

Originalmente sólo se podía indicar una tabla en la cláusula FROM, pero ahora podemos indicar un origen basado en varias tablas.

Si utilizamos un origen basado en varias tablas, se debe de utilizar una extensión de TRANSACT-SQL que consiste en escribir dos cláusulas FROM, una indica la tabla de donde eliminamos las filas y la otra el origen que utilizamos para eliminar.Este caso se produce cuando las filas a eliminar dependen de un valor que está en otra tabla. Por ejemplo queremos eliminar los empleados de las oficinas del Este. Como la

115

Page 116: Curso de SQL Server.docx

región de la oficina no está en empleados, habría que añadir al origen la tabla oficinas para poder formular la condición del WHERE:

DELETE FROM empleados

FROM empleados INNER JOIN oficinas

ON empleados.oficina = oficinas.oficina

WHERE region = 'Este';

En el origen tenemos las dos tablas y en la primera FROM indicamos de qué tabla queremos borrar.

Esto se podía haber resuelto, como toda la vida, mediante una subconsulta:

DELETE FROM empleados

WHERE oficina IN (SELECT oficina

FROM oficinas

WHERE region = 'Este');

Para finalizar no debemos olvidar que para poder ejecutar un DELETE se requieren permisos DELETE en la tabla de donde vamos a eliminar, y también se requieren los permisos para utilizar SELECT si la instrucción contiene una cláusula WHERE.

Muy importante siempre que actualicemos datos en nuestras tablas, no debemos olvidar tampoco las reglas de integridad referencial. Si la tabla afectada interviene como tabla principal en una relación con otra tabla, no se podrán eliminar sus filas que estén relacionadas con registros de la otra tabla (no se pueden eliminar ‘padres’ que tengan ‘hijos’ ). Si se van a eliminar  varias filas y al menos una no se puede eliminar por infringir las reglas de integridad, entonces la operación abortará y no se eliminará ninguna fila.

En el ejemplo anterior, si un empleado asignado a una oficina del Este tiene pedidos, no se podrá eliminar y entonces no se eliminará ningún empleado.

Unidad 7. Actualización de datos (VI)

7.9. Borrado masivo - TRUNCATE

Si queremos eliminar todas las filas de una tabla podemos utilizar también la instrucción TRUNCATE TABLE.

TRUNCATE TABLE

[nbBaseDatos.[nbEsquema.]| nbEsquema.]nbTabla [; ]

Esta sentencia quita todas las filas de una tabla sin registrar las eliminaciones individuales de filas. Desde un punto de vista funcional, TRUNCATE TABLE es equivalente a la instrucción DELETE sin una cláusula WHERE; no obstante, TRUNCATE TABLE es más rápida y utiliza menos recursos de registros de transacciones y de sistema.

En comparación con la instrucción DELETE, TRUNCATE TABLE ofrece las siguientes ventajas:

116

Page 117: Curso de SQL Server.docx

Se utiliza menos espacio del registro de transacciones.

La instrucción DELETE quita una a una las filas y graba una entrada en el registro de transacciones por cada fila eliminada.

TRUNCATE TABLE quita los datos al cancelar la asignación de las páginas de datos utilizadas para almacenar los datos de la tabla y sólo graba en el registro de transacciones las cancelaciones de asignación de páginas.

Por regla general, se utilizan menos bloqueos.

Si se ejecuta la instrucción DELETE con un bloqueo de fila, se bloquea cada fila de la tabla para su eliminación. TRUNCATE TABLE siempre bloquea la tabla y la página, pero no cada fila.

Las páginas cero se conservan en la tabla sin excepciones.

Después de ejecutar una instrucción DELETE, la tabla puede seguir conteniendo páginas vacías. Por ejemplo, no se puede cancelar la asignación de las páginas vacías de un montón sin un bloqueo de tabla exclusivo como mínimo. Si en la operación de eliminación no se utiliza un bloqueo de tabla, la tabla contiene muchas páginas vacías. En el caso de los índices, la operación de eliminación puede dejar páginas vacías, aunque la asignación de estas páginas se puede cancelar rápidamente mediante un proceso de limpieza en segundo plano.

Si la tabla contiene una columna de identidad, el contador para dicha columna se restablece al valor de inicialización definido para ella. Si no se define ningún valor de inicialización, se utiliza el valor predeterminado 1. Para conservar el contador de identidad, se utiliza DELETE.

Pero no todo son ventajas, no se puede utilizar TRUNCATE TABLE en las siguientes tablas:

Tablas a las que se hace referencia mediante una restricción FOREIGN KEY (las tablas que entran como principales en una relación).

Tablas que participan en una vista indizada.

Unidad 8. El DDL, Lenguaje de Definición de Datos (I)

8.1. Introducción

El DDL (Data Definition Language, o Data Description Language según autores), es la parte del SQL dedicada a la definición de la base de datos, consta de sentencias para definir la estructura de la base de datos, permite definir gran parte del nivel interno de la base de datos. Por este motivo estas sentencias serán utilizadas normalmente por el administrador de la base de datos.

La definición de la estructura de la base de datos incluye tanto la creación inicial de los diferentes objetos que formarán la base de datos, como el mantenimiento de esa estructura. Las sentencias del DDL utilizan unos verbos que se repiten para los distintos objetos. Por ejemplo para crear un objeto nuevo el verbo será CREATE y a continuación el tipo de objeto a crear. CREATE DATABASE es la sentencia para crear una base de datos, CREATE TABLE nos permite crear una nueva tabla, CREATE INDEX crear un nuevo índice… Para eliminar un objeto utilizaremos el verbo DROP (DROP TABLE, DROP INDEX…) y para modificar algo de la definición de un objeto ya creado utilizamos el verbo ALTER (ALTER TABLE, ALTER INDEX…).

Los objetos que veremos en este tema son:

117

Page 118: Curso de SQL Server.docx

Bases de datos

Tablas

Vistas

Índices

Como ya hemos comentado, las sentencias DDL están más orientadas al administrador de la base de datos, es el que más las va a utilizar, el programador tiene que conocer cuestiones relativas a la estructura interna de una base de datos, pero no tiene que ser experto en ello por lo que el estudio del tema se centrará en las sentencias y sobre todo en las cláusulas que pensamos pueden ser útiles a un programador y no entraremos en mucho detalle en cuanto a la estructura física de la base de datos y en la administración de la misma.

8.2. Definir una base de datos CREATE DATABASE

Estructura interna

Como ya vimos en el primer tema, las bases de datos de SQL Server 2005 utilizan tres tipos de archivos:

Archivos de datos principales (.mdf): Archivo requerido.

Archivos de datos secundarios (.ndf): Archivo opcional.

Archivos de registro (.ldf): Archivo requerido.

Y se deben situar en sistemas de archivos FAT o NTFS. Se recomienda NTFS.

CREATE DATABASE

CREATE DATABASE nbBasedeDatos

    [ ON

             [ PRIMARY ] [ <esp_fichero> [ ,...n ]

             [ , <grupo> [ ,...n ] ]

    [ LOG ON { < esp_fichero > [ ,...n ] } ]

    ]

    [ COLLATE nbintercalacion]

    [ WITH <external_access_option> ]

]

[;]

Como vemos la instrucción mínima es:

CREATE DATABASE nbBasedeDatos

nbBasedeDatos: Es el nombre de la nueva base de datos. Los nombres de base de datos deben ser únicos en una instancia de SQL Server y cumplir las reglas de los identificadores. Puede tener 128 caracteres como máximo, excepto en un caso que veremos más adelante.

118

Page 119: Curso de SQL Server.docx

Con la cláusula ON especificamos los ficheros utilizados para almacenar los archivos de datos.

    [ ON

        [ PRIMARY ] [ <esp_fichero> [ ,...n ]

        [ , <grupo> [ ,...n ] ]

<esp_fichero> ::=

 (

   NAME = nbfichero_logico ,

   FILENAME = 'nbfichero_fisico'

    [ , SIZE = tamaño [ KB | MB | GB | TB ] ]

    [ , MAXSIZE = { max_size [ KB | MB | GB | TB ] | UNLIMITED } ]

    [ , FILEGROWTH = incremento_crecimiento [ KB | MB | GB | TB | % ] ]

)

nbfichero_logico es el nombre que se utiliza para hacer referencia al archivo en todas las instrucciones Transact-SQL. El nombre de archivo lógico tiene que cumplir las reglas de los identificadores de SQL Server y tiene que ser único entre los nombres de archivos lógicos de la base de datos.

nbfichero_fisico es el nombre del archivo físico que incluye la ruta de acceso al directorio. Debe seguir las reglas para nombres de archivos del sistema operativo.

Con la cláusula SIZE indicamos el tamaño original del archivo. Los archivos de SQL Server 2005 pueden crecer automáticamente a partir del tamaño originalmente especificado. Con FILEGROWTH se puede especificar un incremento de crecimiento y cada vez que se llena el archivo, el tamaño aumentará en la cantidad especificada.

Cada archivo también puede tener un tamaño máximo especificado con MAXSIZE. Si no se especifica un tamaño máximo, el archivo puede crecer hasta utilizar todo el espacio disponible en el disco. Esta característica es especialmente útil cuando SQL Server se utiliza como una base de datos incrustada en una aplicación para la que el usuario no dispone fácilmente de acceso a un administrador del sistema. El usuario puede dejar que los archivos crezcan automáticamente cuando sea necesario y evitar así las tareas administrativas de supervisar la cantidad de espacio libre en la base de datos y asignar más espacio manualmente.

Unidad 8. El DDL, Lenguaje de Definición de Datos (II)

Si no se especifica un nombre de archivo de datos, SQL Server utiliza el nombre de la base de datos como nbfichero_logico y nbfichero_fisico.

Si queremos definir varios archivos de datos, después de la palabra ON escribiremos las definiciones de cada archivo separadas por comas.

PRIMARY especifica que la lista de archivos asociada define el grupo de archivos principal, y el primer archivo especificado se convierte en el archivo de datos principal.

119

Page 120: Curso de SQL Server.docx

Si no se especifica PRIMARY, el primer archivo enumerado en la instrucción CREATE DATABASE se convierte en el archivo principal.

 Detrás de la lista de archivos del grupo de archivos principal, con  <grupo> se puede colocar una lista opcional de elementos separados por comas que definan los grupos de archivos de usuario y sus archivos.

<grupo> ::=

{

FILEGROUP nbgrupo [ DEFAULT ]

    <esp_fichero> [ ,...n ]

}

Nbgrupo es el nombre del grupo y a continuación indicamos los archivos de datos que pertenecen a ese grupo, los archivos pertenecientes al grupo se indican con los del grupo principal.DEFAULT  Cambia el grupo de archivos predeterminado de la base de datos a Nbgrupo. Sólo un grupo de archivos de la base de datos puede ser el grupo de archivos predeterminado.

Con la cláusula LOG ON definiremos los archivos utilizados para almacenar el registro de la base de datos (los archivos de registro).

    [ LOG ON { <esp_fichero> [ ,...n ] } ]

Si no se especifica LOG ON, se crea automáticamente un archivo de registro cuyo tamaño es el 25 por ciento de la suma de los tamaños de todos los archivos de datos de la base de datos, o 512 KB (lo que sea mayor), también limitará el nombre de la base de datos a 123 caracteres ya que el sistema generará el nombre del archivo de registro añadiendo al nombre de la base de datos un sufijo.

Con la cláusula COLLATE podemos cambiar la intercalación predeterminada. La intercalación define:

El alfabeto o lenguaje cuyas reglas de ordenación se aplican si se especifica la ordenación de diccionario.

La página de códigos usada para almacenar datos de caracteres que no son Unicode.

Las reglas de comportamiento frente a mayúsculas y minúsculas y caracteres acentuados.

La sintaxis es la siguiente:

COLLATE <nbintercalacion>

< nbintercalacion >:: =

      nbinterWindows_ CaseSensitivity_AccentSensitivity

nbinterWindows: Es un nombre de intercalación de Windows. Visita el siguiente básico para saber más sobre las intercalaciones.

120

Page 121: Curso de SQL Server.docx

CaseSensitivity: Especifica que sí se distingue entre mayúsculas y minúsculas (CS), o no (CI). SQL Server Mobile sólo admite esta opción.

AccentSensitivity: Especifica si se distinguen los caracteres acentuados (AS), o no (AI). SQL Server Mobile sólo admite la opción AS.

Si no se especifica, se asigna a la base de datos la intercalación predeterminada de la instancia de SQL Server. No se puede especificar un nombre de intercalación en una instantánea de base de datos, ni tampoco con las cláusulas FOR ATTACH o FOR.Existen otras cláusulas a nivel de administración de la base de datos que no detallaremos aquí como son:

[ WITH <external_access_option> ]

<external_access_option> ::=

{

    DB_CHAINING { ON | OFF }

  | TRUSTWORTHY { ON | OFF }

}

Para controlar el acceso externo a la base de datos y desde ésta.

CREATE DATABASE nbBasedeDatos

    ON <esp_fichero> [ ,...n ]

    FOR { ATTACH [ WITH <service_broker_option> ]

        | ATTACH_REBUILD_LOG }

[;]

<service_broker_option> ::=

{

    ENABLE_BROKER

  | NEW_BROKER

  | ERROR_BROKER_CONVERSATIONS

}

Para adjuntar una base de datos.

CREATE DATABASE nbInstantanea_basedatos

    ON

        (

        NAME = nbfichero_logico ,

    FILENAME = 'nbfichero_fisico'

        ) [ ,...n ]

    AS SNAPSHOT OF nbBaseDatos_origen

121

Page 122: Curso de SQL Server.docx

[;]

Para crear una instantánea de base de datos (copia de sólo lectura de una base de datos).

CREATE DATABASE database_name

   [DATABASEPASSWORD 'database_password'

      [ENCRYPTION {ON|OFF}]

   ]

   [COLLATE collation_name comparison_style]

database password ::= identifier

Para crear una base de datos protegida mediante contraseña, opción disponible para SQL Server Mobile (Microsoft SQL Server 2005 Mobile Edition (SQL Server Mobile), antes denominado Microsoft SQL Server 2000 Windows CE 2.0 (SQL Server CE), es una base de datos compacta y con una gran variedad de funciones diseñada para admitir una lista ampliada de dispositivos inteligentes y Tablet PC. Entre los dispositivos inteligentes están todos los dispositivos que ejecuten Microsoft Windows CE 5.0, Microsoft Mobile Pocket PC 2003, Microsoft Mobile Version 5.0 Pocket PC o Microsoft Mobile Version 5.0 Smart Phone. Esta compatibilidad adicional con dispositivos permite a los programadores usar la misma funcionalidad de base de datos en un gran número de dispositivos.)

Unidad 8. El DDL, Lenguaje de Definición de Datos (III)

8.3. Eliminar una base de datos DROP DATABASE

Para eliminar una base de datos tenemos la instrucción DROP DATABASE.

DROP DATABASE { nbBasedeDatos } [ ,...n ] [;]

La base de datos puede ser una base de datos normal o una instantánea de base de datos.Para poder ejecutar la sentencia el usuario debe tener permiso de CONTROL y se debe de ejecutar en un contexto diferente del de la base de datos a eliminar, por ejemplo:

use b1

DROP DATABASE b1

Falla porque con el use estamos en el contexto de la base de datos a eliminar.

Como se ve en la sintaxis podemos eliminar varias bases de datos con una sóla sentencia DROP DATABASE.

Por ejemplo:

DROP DATABASE b1,b2

122

Page 123: Curso de SQL Server.docx

Elimina las bases de datos b1 y b2.

8.4. Modificar las propiedades de una BD ALTER DATABASE

Si después de crear la base de datos queremos cambiar algo de su definición podríamos eliminarla (con DROP DATABASE) y luego crearla otra vez (con CREATE DATABASE), pero si ya la hemos rellenado con tablas u otros objetos, esta solución no sería muy práctica. Para cambiar la definición de la base de datos una vez creada tenemos que utilizar la sentencia ALTER DATABASE.

Para poder ejecutar esta sentencia se debe de tener el permiso ALTER en la base de datos.  Esta sentencia se debe ejecutar en el modo de confirmación automática (modo de administración de transacciones predeterminado) y no se permite en una transacción explícita o implícita.

Las instantáneas de bases de datos no se pueden modificar, y para modificar las opciones de base de datos asociadas a la réplica, se utiliza el procedimiento almacenado del sistema  sp_replicationdboption.

Sintaxis:

ALTER DATABASE nbBasedeDatos

{

    <cambiar_ficheros>

  | <cambiar_grupos>

  | <opciones>

  | MODIFY NAME = nuevo_nbBasedeDatos

  | COLLATE nbintercalación

}

[;]

Con esta sentencia resumida vemos que nos permite cambiar la definición de la base de datos, nos va a permitir cambiar la definición de los ficheros que conforman la base de datos, también nos permite cambiar la definición de los grupos, la definición de varias opciones, el tipo de intercalación e incluso cambiar el nombre de la base de datos (con la cláusula MODIFY NAME).

Por ejemplo:

ALTER DATABASE Cliente

MODIFY NAME = Clientes;

La base de datos Cliente pasa a llamarse Clientes.

Como con la instrucción CREATE DATABASE veremos aquí un resumen de lo que más le puede interesar a un programador, sin entrar en demasiados detalles de administración.Como muchas de las palabras ya las hemos explicado con la sentencia CREATE DATABASE, sólo insistiremos en lo nuevo.

<cambiar_ficheros>::=

123

Page 124: Curso de SQL Server.docx

{

    ADD FILE < esp_fichero > [ ,...n ]

        [ TO FILEGROUP { nbgrupo | DEFAULT } ]

  | ADD LOG FILE < esp_fichero > [ ,...n ]

  | REMOVE FILE nbfichero

  | MODIFY FILE < esp_fichero >

}

Con este grupo de opciones podemos cambiar la definición de los archivos de datos de la base de datos.

ADD FILE permite añadir un nuevo archivo de datos (o varios) si no se añade nada (o TO FILEGROUP DEFAULT), el archivo se añadirá al grupo principal, si añadimos TO FILEGROUP nbgrupo, se añadirá el archivo al grupo indicado.

Con ADD LOG FILE podemos añadir un nuevo archivo de registro.

Con REMOVE FILE nbfichero eliminamos el archivo con nombre nbfichero. Se elimina la definición del archivo lógico (nbfichero) y elimina el archivo físico asociado. El archivo no se puede quitar a menos que esté vacío.

Unidad 8. El DDL, Lenguaje de Definición de Datos (IV)

Con MODIFY FILE <esp_fichero> podemos cambiar las especificaciones de alguno de los archivos de la base de datos.

<esp_fichero>::=

(

    NAME = nbarchivo 

    [ , NEWNAME = nuevo_nbarchivo ]

    [ , FILENAME = 'nbarchivo_fisico' ]

    [ , SIZE = tamaño [ KB | MB | GB | TB ] ]

    [ , MAXSIZE = { tamaño_máximo [ KB | MB | GB | TB ] | UNLIMITED } ]

    [ , FILEGROWTH = incremento [ KB | MB | GB | TB| % ] ]

    [ , OFFLINE ]

)

Sólo se puede cambiar una propiedad <especificaciónDeArchivo> cada vez. NAME se debe especificar siempre para identificar el archivo que se va a modificar. Si se especifica SIZE, el nuevo tamaño debe ser mayor que el tamaño actual del archivo. Para reducir el tamaño de una base de datos, se utiliza el comando de consola  SHRINKDATABASE de Transact_SQL.

124

Page 125: Curso de SQL Server.docx

Para modificar el nombre lógico de un archivo de datos o de un archivo de registro, especificamos el nombre lógico nuevo para el archivo en la cláusula NEWNAME. Por ejemplo:

ALTER DATABASE MiBasedeDatos

MODIFY FILE ( NAME = bd1, NEWNAME = base1)

Con esta sentencia, el archivo bd1 ahora se llama base1.

Con FILENAME podemos cambiar el nombre del fichero físico, esto nos permite también cambiar la ubicación del archivo físico.

Por ejemplo:

ALTER DATABASE MiBasedeDatos

MODIFY FILE(NAME = nbficherológico,

 FILENAME = 'nueva_ruta/nb_fichero_físico')

La cláusula OFFLINE establece el archivo sin conexión e impide el acceso a todos los objetos del grupo de archivos. ¡Muy importante!, esta opción sólo se debe de utilizar si el archivo está dañado y si se puede restaurar. Un archivo establecido en OFFLINE sólo se puede restablecer con conexión mediante la restauración del archivo a partir de una copia de seguridad. Para obtener más información acerca de cómo restaurar un solo archivo, consultar en la ayuda la sentencia  RESTORE (Transact-SQL).

UNLIMITED especifica que el tamaño del archivo aumenta hasta que el disco esté lleno. En SQL Server 2005, un archivo de registro especificado con un aumento ilimitado tiene un tamaño máximo de 2 TB y un archivo de datos tiene un tamaño máximo de 16 TB.

En cuanto a la modificación de la definición de grupos, tenemos esta sintaxis:

<cambiar_grupos>::=

{

    | ADD FILEGROUP nbgrupo

    | REMOVE FILEGROUP nbgrupo

    | MODIFY FILEGROUP nbgrupo

        {

             { READONLY | READWRITE }

             | { READ_ONLY | READ_WRITE }

  }

        | DEFAULT

        | NAME = nuevo_ nbgrupo

        }

}

125

Page 126: Curso de SQL Server.docx

Con ADD FILEGROUP nbgrupo  añadimos un nuevo grupo de archivos de la base de datos.Con REMOVE FILEGROUP nbgrupo  eliminamos el grupo de la base de datos.El grupo de archivos no se puede quitar a menos que esté vacío. Para quitar todos los archivos del grupo, primero se mueven los archivos a otro grupo, si los archivos están vacíos, se pueden eliminar directamente.

Con MODIFY FILEGROUP nbgrupo, modificamos el grupo de archivos.

DEFAULT Cambia el grupo de archivos predeterminado de la base de datos a nbgrupo.

NAME = nuevo_nbgrupo  Cambia el nombre del grupo a nuevo_nbgrupo.

READ_ONLY | READONLY Especifica que el grupo de archivos es de sólo lectura. En este caso no se permitirá la actualización de los objetos del mismo. Una base de datos de sólo lectura no permite realizar modificaciones en los datos por lo que:

Se omite la recuperación automática cuando se inicia el sistema.

No es posible reducir la base de datos.

No se produce ningún bloqueo en las bases de datos de sólo lectura. Esto puede acelerar el rendimiento de las consultas.

Para cambiar este estado, se debe tener acceso exclusivo a la base de datos.

El grupo de archivos principal no puede ser de sólo lectura.

Se puede utilizar indistintamente la palabra clave READONLY o READ_ONLY, pero READONLY se quitará en una versión futura de Microsoft SQL Server por lo que se recomienda  READ_ONLY.

READ_WRITE | READWRITE Especifica que el grupo es de lectura y escritura por lo que  pueden realizarse actualizaciones en los objetos del grupo de archivos. Para cambiar este estado se debe tener acceso exclusivo a la base de datos. Se puede utilizar indistintamente la palabra clave READWRITE o READ_ WRITE, pero READWRITE se quitará en una versión futura de Microsoft SQL Server por lo que se recomienda  READ_WRITE.

Nota. El estado de estas opciones se puede determinar mediante el examen de la columna is_read_only de la vista de catálogo sys.databases o la propiedad Updateability de la función DATABASEPROPERTYEX.

Unidad 8. El DDL, Lenguaje de Definición de Datos (V)

Para finalizar tenemos el apartado <opciones> que nos permite definir y/o cambiar muchas opciones de la base de datos. La lista de opciones es muy larga, como podemos observar a continuación, y no entraremos en detalles.

<opciones>::=

SET

{

    { <optionspec> [ ,...n ] [ WITH <termination> ] }

    | ALLOW_SNAPSHOT_ISOLATION {ON | OFF }

126

Page 127: Curso de SQL Server.docx

    | READ_COMMITTED_SNAPSHOT {ON | OFF } [ WITH <termination> ]

}

<optionspec>::=

{

    <db_state_option>

  | <db_user_access_option>

  | <db_update_option>   | <external_access_option>

  | <cursor_option>

  | <auto_option>

  | <sql_option>

  | <recovery_option>

  | <database_mirroring_option>

  | <supplemental_logging_option>

  | <service_broker_option>

  | <date_correlation_optimization_option>

  | <parameterization_option>

}

<db_state_option> ::=

    { ONLINE | OFFLINE | EMERGENCY }

<db_user_access_option> ::=

    { SINGLE_USER | RESTRICTED_USER | MULTI_USER }

<db_update_option> ::=

    { READ_ONLY | READ_WRITE }

<external_access_option> ::=

    DB_CHAINING { ON | OFF }

  | TRUSTWORTHY { ON | OFF }

}

<cursor_option> ::=

{   CURSOR_CLOSE_ON_COMMIT { ON | OFF }

  | CURSOR_DEFAULT { LOCAL | GLOBAL }

}

<auto_option> ::=

{

    AUTO_CLOSE { ON | OFF }

  | AUTO_CREATE_STATISTICS { ON | OFF }

  | AUTO_SHRINK { ON | OFF }

127

Page 128: Curso de SQL Server.docx

  | AUTO_UPDATE_STATISTICS { ON | OFF }

  | AUTO_UPDATE_STATISTICS_ASYNC { ON | OFF }

}

<sql_option> ::=

{

    ANSI_NULL_DEFAULT { ON | OFF }

  | ANSI_NULLS { ON | OFF }

  | ANSI_PADDING { ON | OFF }

  | ANSI_WARNINGS { ON | OFF }

  | ARITHABORT { ON | OFF }

  | CONCAT_NULL_YIELDS_NULL { ON | OFF }

  | NUMERIC_ROUNDABORT { ON | OFF }

  | QUOTED_IDENTIFIER { ON | OFF }

  | RECURSIVE_TRIGGERS { ON | OFF }

}

<recovery_option> ::=

{

    RECOVERY { FULL | BULK_LOGGED | SIMPLE }

  | TORN_PAGE_DETECTION { ON | OFF }

  | PAGE_VERIFY { CHECKSUM | TORN_PAGE_DETECTION | NONE }

}

< database_mirroring_option> ::=

{ <partner_option> | <witness_option> }

    <partner_option> ::=

    PARTNER { = 'partner_server'

            | FAILOVER

            | FORCE_SERVICE_ALLOW_DATA_LOSS

            | OFF

            | RESUME

            | SAFETY { FULL | OFF }

            | SUSPEND

            | REDO_QUEUE ( integer { KB | MB | GB } | UNLIMITED )

            | TIMEOUT integer

            }

<witness_option> ::=

WITNESS { = 'witness_server'

128

Page 129: Curso de SQL Server.docx

            | OFF

            }

<supplemental_logging_option> ::=

    SUPPLEMENTAL_LOGGING { ON | OFF }

<service_broker_option> ::=

{

    ENABLE_BROKER

  | DISABLE_BROKER

  | NEW_BROKER

  | ERROR_BROKER_CONVERSATIONS

}

<date_correlation_optimization_option> ::=

{

    DATE_CORRELATION_OPTIMIZATION { ON | OFF }

}

<parameterization_option> ::=

{

    PARAMETERIZATION { SIMPLE | FORCED }

}

<termination> ::=

{

    ROLLBACK AFTER integer [ SECONDS ]

  | ROLLBACK IMMEDIATE

  | NO_WAIT

}

Unidad 8. El DDL, Lenguaje de Definición de Datos (V)

Para finalizar tenemos el apartado <opciones> que nos permite definir y/o cambiar muchas opciones de la base de datos. La lista de opciones es muy larga, como podemos observar a continuación, y no entraremos en detalles.

<opciones>::=

SET

{

    { <optionspec> [ ,...n ] [ WITH <termination> ] }

    | ALLOW_SNAPSHOT_ISOLATION {ON | OFF }

129

Page 130: Curso de SQL Server.docx

    | READ_COMMITTED_SNAPSHOT {ON | OFF } [ WITH <termination> ]

}

<optionspec>::=

{

    <db_state_option>

  | <db_user_access_option>

  | <db_update_option>   | <external_access_option>

  | <cursor_option>

  | <auto_option>

  | <sql_option>

  | <recovery_option>

  | <database_mirroring_option>

  | <supplemental_logging_option>

  | <service_broker_option>

  | <date_correlation_optimization_option>

  | <parameterization_option>

}

<db_state_option> ::=

    { ONLINE | OFFLINE | EMERGENCY }

<db_user_access_option> ::=

    { SINGLE_USER | RESTRICTED_USER | MULTI_USER }

<db_update_option> ::=

    { READ_ONLY | READ_WRITE }

<external_access_option> ::=

    DB_CHAINING { ON | OFF }

  | TRUSTWORTHY { ON | OFF }

}

<cursor_option> ::=

{   CURSOR_CLOSE_ON_COMMIT { ON | OFF }

  | CURSOR_DEFAULT { LOCAL | GLOBAL }

}

<auto_option> ::=

{

    AUTO_CLOSE { ON | OFF }

  | AUTO_CREATE_STATISTICS { ON | OFF }

  | AUTO_SHRINK { ON | OFF }

130

Page 131: Curso de SQL Server.docx

  | AUTO_UPDATE_STATISTICS { ON | OFF }

  | AUTO_UPDATE_STATISTICS_ASYNC { ON | OFF }

}

<sql_option> ::=

{

    ANSI_NULL_DEFAULT { ON | OFF }

  | ANSI_NULLS { ON | OFF }

  | ANSI_PADDING { ON | OFF }

  | ANSI_WARNINGS { ON | OFF }

  | ARITHABORT { ON | OFF }

  | CONCAT_NULL_YIELDS_NULL { ON | OFF }

  | NUMERIC_ROUNDABORT { ON | OFF }

  | QUOTED_IDENTIFIER { ON | OFF }

  | RECURSIVE_TRIGGERS { ON | OFF }

}

<recovery_option> ::=

{

    RECOVERY { FULL | BULK_LOGGED | SIMPLE }

  | TORN_PAGE_DETECTION { ON | OFF }

  | PAGE_VERIFY { CHECKSUM | TORN_PAGE_DETECTION | NONE }

}

< database_mirroring_option> ::=

{ <partner_option> | <witness_option> }

    <partner_option> ::=

    PARTNER { = 'partner_server'

            | FAILOVER

            | FORCE_SERVICE_ALLOW_DATA_LOSS

            | OFF

            | RESUME

            | SAFETY { FULL | OFF }

            | SUSPEND

            | REDO_QUEUE ( integer { KB | MB | GB } | UNLIMITED )

            | TIMEOUT integer

            }

<witness_option> ::=

WITNESS { = 'witness_server'

131

Page 132: Curso de SQL Server.docx

            | OFF

            }

<supplemental_logging_option> ::=

    SUPPLEMENTAL_LOGGING { ON | OFF }

<service_broker_option> ::=

{

    ENABLE_BROKER

  | DISABLE_BROKER

  | NEW_BROKER

  | ERROR_BROKER_CONVERSATIONS

}

<date_correlation_optimization_option> ::=

{

    DATE_CORRELATION_OPTIMIZATION { ON | OFF }

}

<parameterization_option> ::=

{

    PARAMETERIZATION { SIMPLE | FORCED }

}

<termination> ::=

{

    ROLLBACK AFTER integer [ SECONDS ]

  | ROLLBACK IMMEDIATE

  | NO_WAIT

}

Se pueden ver más detalles de estas opciones en la ayuda de SQL SERVER buscando ALTER DABATABASE.

Unidad 8. El DDL, Lenguaje de Definición de Datos (VI)

8.5. Crear una tabla CREATE TABLE

Para crear una nueva tabla se emplea la sentencia CREATE TABLE.Se necesita el permiso CREATE TABLE en la base de datos y el permiso ALTER en el esquema en que se crea la tabla.

Si las columnas de la instrucción CREATE TABLE se definen como un tipo definido por el usuario CLR, se necesita la propiedad del tipo o el permiso REFERENCES.Si las columnas de la instrucción CREATE TABLE tienen una colección de esquemas

132

Page 133: Curso de SQL Server.docx

XML asociada, se necesita la propiedad de la colección de esquemas XML o el permiso REFERENCES.

Empezaremos por una sintaxis reducida:

CREATE TABLE

    [ nbBaseDatos.[nbEsquema].| nbEsquema.]nbTabla

        ( { <definicion_columna> | < definicion_colCalc > } [ ,...n ]

        [ <restriccion_tabla> ] [ ,...n ] )

 [ ; ]

nbBaseDatos Es el nombre de la base de datos en la que se crea la tabla. Debe ser el nombre de una base de datos existente. Si no se especifica nbBaseDatos, se utiliza de manera predeterminada la base de datos actual. El inicio de sesión de la conexión actual debe estar asociado a un Id. de usuario existente en la base de datos especificada por nbBaseDatos, y ese Id. de usuario debe tener permisos CREATE TABLE. nbEsquema Es el nombre del esquema al que pertenece la nueva tabla. nbTabla Es el nombre de la nueva tabla. Los nombres de tablas deben seguir las reglas de los identificadores. nbTabla  puede contener un máximo de 128 caracteres excepto para los nombres de tablas temporales locales (nombres precedidos por un único signo de número (#)) que no pueden superar los 116 caracteres.

Después de indicar el nombre de la tabla,  entre paréntesis definimos, separadas por una coma, cada una de las columnas de la tabla y al final las restricciones a nivel de tabla si las hay.

Definir columnas físicas

< definicion_columna > ::=

nbCol <tipo_dato>

    [ COLLATE nbIntercalacion ]

    [ NULL | NOT NULL ]

    [

       [ CONSTRAINT nbRestriccion ] DEFAULT exp_constante ]

     | [ IDENTITY [( semilla, incremento )] [NOT FOR REPLICATION] ]

    ]

    [ ROWGUIDCOL ] 

[ <restriccion_columna> [ ...n ] ]

Como mínimo debemos indicar el nombre de la columna nbCol y su tipo de datos.

Los nombres de columnas deben seguir las reglas de los identificadores y deben ser únicos en la tabla. nbCol puede contener de 1 a 128 caracteres. nbCol se puede omitir en las columnas creadas con un tipo de datos timestamp, en tal caso, si no se especifica nbCol, el nombre de la columna timestamp será de manera predeterminada timestamp.En cuanto al tipo de dato, esta es la sintaxis:

133

Page 134: Curso de SQL Server.docx

<tipo_dato> ::=

[nbEsquema_tipo. ] nbtipo

    [ ( precision [ , escala ] | max |

        [ { CONTENT | DOCUMENT } ] xml_schema_collection ) ]

[ nbEsquema_tipo. ] nbtiponbtipo Especifica el tipo de datos de la columna y nbEsquema_tipo el esquema al que pertenece el tipo. El tipo de datos puede ser uno de los siguientes:

Un tipo de datos del sistema de SQL Server 2005 como los que ya conocemos.

Un tipo de alias basado en un tipo de datos del sistema de SQL Server. Los tipos de datos de alias se crean con la instrucción CREATE TYPE para poder utilizarlos en una definición de tabla. La asignación NULL o NOT NULL de un tipo de datos de alias puede anularse durante la instrucción CREATE TABLE. No obstante, la especificación de longitud no se puede cambiar; la longitud del tipo de datos de alias no se puede especificar en una instrucción CREATE TABLE.

Un tipo definido por el usuario CLR. Los tipos definidos por el usuario CLR se crean con la instrucción CREATE TYPE para poder utilizarlos en una definición de tabla.

Si no se especifica el parámetro nbEsquema_tipo, el SQL Server Database Engine (Motor de base de datos de SQL Server) hace referencia a nbtipo en el siguiente orden:

El tipo de datos del sistema de SQL Server.

El esquema predeterminado del usuario actual en la base de datos actual.

El esquema de dbo de la base de datos actual.

Precision es la precisión del tipo de datos especificado.

Escala es la escala del tipo de datos especificado.

Max sólo se aplica a los tipos de datos varchar, nvarchar y varbinary para almacenar 231 bytes de datos de caracteres y binarios, y 230 bytes de datos Unicode.

También podemos definir tipos de datos XML.

Para obtener más información acerca de los valores de precisión y de escala válidos,

visita el siguiente avanzado.

Unidad 8. El DDL, Lenguaje de Definición de Datos (VII)

Una vez indicado el tipo de datos de la columna podemos opcionalmente completar su definición con una serie de cláusulas.

[ COLLATE nbIntercalacion ]

Con la cláusula COLLATE podemos definir el tipo de intercalación que se utilizará para la columna (Ver CREATE TABLE).

134

Page 135: Curso de SQL Server.docx

[ NULL | NOT NULL ]

Determina si se permiten valores nulos (NULL) en la columna o no (NOT NULL). Realmente NULL no es estrictamente una restricción, si no indicamos nada la columna permitirá valores nulos, pero se puede especificar de la misma forma que NOT NULL. NOT NULL se puede especificar para las columnas calculadas sólo si se especifica también PERSISTED.

[ CONSTRAINT nbRestriccion ] DEFAULT exp_constante ]

Con la cláusula DEFAULT podemos especificar un valor por defecto, es decir el valor que tomará el campo cuando no se haya especificado explícitamente un valor durante la inserción. Las definiciones DEFAULT se pueden aplicar a cualquier columna excepto a las definidas como timestamp o a aquellas que tengan la propiedad IDENTITY. Si se especifica un valor por defecto a una columna de un tipo definido por el usuario, dicho tipo debe ser compatible con la conversión implícita de exp_constante en el tipo definido por el usuario. exp_constante sólo puede ser NULL o un valor constante (por ejemplo, una cadena de caracteres, una función escalar o una función del sistema, definida por el usuario o CLR).

 Para mantener la compatibilidad con las versiones anteriores de SQL Server, se puede asignar un nombre de restricción a DEFAULT con [ CONSTRAINT nbRestriccion ]. Los nombres de restricción deben ser únicos en el esquema al que pertenece la tabla.

[ IDENTITY [( semilla, incremento )] [NOT FOR REPLICATION] ]

IDENTITY indica que la nueva columna es una columna de identidad. Cuando se agrega una nueva fila a la tabla, el Motor de base de datos proporciona un valor incremental único para la columna. Las columnas de identidad se utilizan normalmente como claves principales.

La propiedad IDENTITY se puede asignar a las columnas tinyint, smallint, int, bigint, decimal(p,0) o numeric(p,0). Sólo se puede crear una columna de identidad para cada tabla. Las restricciones DEFAULT y los valores predeterminados enlazados no se pueden utilizar en las columnas de identidad. En este caso, deben especificarse el valor de inicialización y el incremento, o ninguno de esto valores. Si no se especifica ninguno, el valor predeterminado es (1,1).

semilla es el valor que se utiliza para la primera fila cargada en la tabla.Incremento es el valor incremental que se agrega al valor de identidad de la fila cargada anterior.De forma general, si se especifica la cláusula NOT FOR REPLICATION para una restricción, dicha restricción no se impone cuando los agentes de réplica realizan operaciones de inserción, actualización o eliminación. Si se especifica esta cláusula, junto con IDENTITY, los valores no se incrementan en las columnas de identidad cuando los agentes de réplica realizan inserciones.

[ ROWGUIDCOL ] 

ROWGUIDCOL indica que la nueva columna es una columna de GUID de filas. Sólo se puede designar una columna uniqueidentifier por tabla como columna ROWGUIDCOL. La propiedad ROWGUIDCOL se puede asignar únicamente a una columna uniqueidentifier. Las columnas de tipos de datos definidos por el usuario no se pueden designar con ROWGUIDCOL.

135

Page 136: Curso de SQL Server.docx

La propiedad ROWGUIDCOL no impone la unicidad de los valores almacenados en la columna. ROWGUIDCOL tampoco genera automáticamente valores para nuevas filas insertadas en la tabla, por lo que se debe de utilizar la función NEWID en las instrucciones INSERT o utilizar la función NEWID como el valor predeterminado de la columna para generar valores únicos en cada fila.

Para ver más consideraciones sobre columnas IDENTITY y ROWGUIDCOL.

Por último nos quedan las restricciones de clave que aparecen en la sintaxis como:

[ <restriccion_columna> [ ...n ] ]

< restriccion_columna > ::=

[ CONSTRAINT nbRestriccion]

{     { PRIMARY KEY | UNIQUE }[ CLUSTERED | NONCLUSTERED ]

        [ WITH FILLFACTOR = factorRelleno 

        | WITH ( < opcion_indice > [ , ...n ] )

  ]

        [ ON { partition_scheme_name ( partition_column_name )

            | filegroup | "default" } ]

  | [ FOREIGN KEY ]

        REFERENCES [ nbEsquema.] nbTablaPadre [ ( col_padre )  ]

        [ ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]

 }

       [ ON UPDATE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]

        [ NOT FOR REPLICATION ]

  | CHECK [ NOT FOR REPLICATION ] (expresion_validacion)

nbRestriccion es el nombre de la restricción, como hemos visto antes, debe ser único en el esquema al que pertenece la tabla. Las restricciones se implementan internamente con índices por lo que a veces podemos utilizar el término índice o restricción indistintamente.

{PRIMARY KEY | UNIQUE} [ CLUSTERED | NONCLUSTERED ]

PRIMARY KEY indica que la columna es la clave principal de la tabla. Sólo se puede crear una restricción PRIMARY KEY para cada tabla. Si la clave primaria (principal) está compuesta por varias columnas entonces no podemos utilizar esta restricción, tendremos que utilizar una restricción de tabla que veremos más adelante.

CLUSTERED indica que el índice que se va a crear es un índice agrupado. Como sólo puede haber un índice agrupado por tabla, si todavía no hay ninguno definido, por defecto se creará con la clave primaria, si ya existe un índice agrupado, la clave principal se creará sin índice agrupado.

136

Page 137: Curso de SQL Server.docx

Una clave primaria no puede contener valores nulos, por lo que todas las columnas definidas en una restricción PRIMARY KEY se deben definir como NOT NULL. Si cuando definimos la columna, no se indica nada, la columna se establecerá a NOT NULL.

Si la clave principal se define en una columna de tipo definido por el usuario CLR, la implementación del tipo debe admitir el orden binario.

UNIQUE indica que la columna no admite valores duplicados, por lo que se crea un índice único. Una tabla puede tener varios índices únicos.

Unidad 8. El DDL, Lenguaje de Definición de Datos (VIII)

Si no se especifica CLUSTERED o NONCLUSTERED, de forma predeterminada se utiliza NONCLUSTERED.

Como cada restricción UNIQUE genera un índice. El número de restricciones UNIQUE no puede hacer que el número de índices de la tabla exceda de 249 índices no agrupados y 1 índice agrupado.

Si se define una restricción UNIQUE en una columna de tipo definido por el usuario CLR, la implementación del tipo debe admitir el orden binario o basado en el operador. Las demás opciones de índices:

[ WITH FILLFACTOR = factorRelleno 

 | WITH ( < opcion_indice > [ , ...n ] ) ]

< opcion_indice > ::=

{

    PAD_INDEX = { ON | OFF }

  | FILLFACTOR = factorRelleno 

  | IGNORE_DUP_KEY = { ON | OFF }

  | STATISTICS_NORECOMPUTE = { ON | OFF }

  | ALLOW_ROW_LOCKS = { ON | OFF}

  | ALLOW_PAGE_LOCKS ={ ON | OFF}

}

Son cláusulas que nos permiten definir con más detalle el índice pero que no veremos aquí por entrar demasiado en cuestiones internas.

La cláusula CHECK.

CHECK [ NOT FOR REPLICATION ] ( expresion_validacion )

Con CHECK indicamos una regla de validación que deberán cumplir todas las filas de la tabla, es una restricción que exige la integridad del dominio al limitar los valores posibles que se pueden escribir en la columna.

expression es una expresión lógica que devuelve TRUE o FALSE. Si queremos definir una restricción CHECK sobre una columna calculada, esta se deberá definir como PERSISTED.

137

Page 138: Curso de SQL Server.docx

Una columna puede tener cualquier número de restricciones CHECK y la condición puede incluir varias expresiones lógicas combinadas con AND y OR. Varias restricciones CHECK para una columna se validan en el orden en que se crean.

La condición de búsqueda debe evaluarse como una expresión booleana y no puede hacer referencia a otra tabla.

Una restricción CHECK en el nivel de columna sólo puede hacer referencia a la columna restringida y una restricción CHECK en el nivel de tabla sólo puede hacer referencia a columnas de la misma tabla.

Las restricciones CHECK no se pueden definir en las columnas text, ntext o image.

Por ejemplo queremos que la columna Precio de la tabla que estamos definiendo no pueda contener valores negativos:

Precio CURRENCY CONSTRAINT precio_pos CHECK (Precio > = 0)

Por último a nivel de columna podemos definir una restricción de clave ajena:

[ FOREIGN KEY ]

        REFERENCES [ nbEsquema.] nbTablaPadre [ ( col_padre ) ]

        [ ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]

        [ ON UPDATE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]

        [ NOT FOR REPLICATION ]

Con esta cláusula definimos una regla de integridad referencial, los valores contenidos en la columna deberán apuntar a un registro en la tabla de referencia (la tabla padre).La palabra FOREIGN KEY no es obligatoria cuando estamos a nivel de columna, el utilizarla o no tiene el mismo efecto.

Nbesquema es el nombre del esquema al que pertenece la tabla padre y nbTablaPadre es el nombre de la tabla padre.

Col_padre es la columna de la tabla padre que se relaciona con la columna que estamos definiendo. Esta columna debe tener el mismo tipo de datos que la columna en la que se define la restricción. 

La col_padre debe tener en la tabla padre una restricción de PRIMARY KEY o UNIQUE, si no se indica una columna padre (columna de referencia) se utiliza la clave primaria de la tabla padre.

Las reglas de integridad referencial obligan a que si se especifica un valor distinto de NULL en una columna con una restricción FOREIGN KEY, ese valor debe existir en la columna referenciada de la tabla padre; de lo contrario, se devolverá un error de infracción de clave externa.

138

Page 139: Curso de SQL Server.docx

Las restricciones FOREIGN KEY sólo pueden hacer referencia a las tablas de la misma base de datos en el mismo servidor. La integridad referencial entre bases de datos debe implementarse a través de desencadenadores.

Las restricciones FOREIGN KEY pueden hacer referencia a otras columnas de la misma tabla. Esto se denomina autorreferencia.       

create table personas (codigo integer primary Key,

dni integer UNIQUE,

madre integer references personas,

padre integer references personas (col1),

dniTutor integer references personas (col4));

En esta tabla de personas, identificamos a cada persona por un código, también tenemos el dni de la persona y el código de su padre y de su madre, además nos guardamos el dni del tutor de la persona. Las madres, padres y tutores son personas que deben de existir en la tabla Personas y en este caso utilizamos el código para referenciar padres y madres y el dni para referencial el tutor, esto último lo podemos hacer porque el campo dni tiene una restricción UNIQUE.

Por último nos queda completar las reglas de integridad referencial en cuanto a qué hacer cuando se eliminan o modifican valores que intervienen en una relación referencial.

ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT }

Indica qué ocurre cuando se intenta eliminar un registro padre en la relación que estamos definiendo. El valor predeterminado es NO ACTION.

NO ACTION El Motor de base de datos genera un error y  no es posible eliminar la fila de la tabla primaria (el padre).

CASCADE  Si se borra una fila de la tabla primaria, se eliminan automáticamente todas las filas correspondientes de la tabla que estamos definiendo, en otras palabras, si se elimina un padre, se eliminan todos sus hijos.

 SET NULL Si se borra una fila de la tabla primaria, todas las filas correspondientes de la tabla que estamos definiendo tomarán el valor NULL en el campo clave ajena. En otras palabras, si se elimina un padre, sus hijos se quedan sin padre.

Para ejecutar esta restricción, la columna clave ajena debe admitir valores NULL.SET DEFAULT Es como la anterior pero en vez del valor NULL toman el valor que tienen predeterminado. Si no hay ningún valor predeterminado establecido de forma explícita, tomarán el valor NULL. Hay que tener en cuenta que el valor predeterminado debe de existir en la tabla primaria.

Unidad 8. El DDL, Lenguaje de Definición de Datos (IX)

Veamos estas opciones con un ejemplo:Tenemos una tabla Proveedores y una tabla artículos, en la tabla artículos nos guardamos el código del proveedor del artículo, por lo tanto definiremos la tabla artículos de la siguiente forma:

139

Page 140: Curso de SQL Server.docx

CREATE TABLE articulos (

Codigo INTEGER PRIMARY KEY,

Denominacion  VARCHAR(30),

….,

Proveedor INTEGER REFERENCES Proveedores,

…)

El campo Proveedor es clave ajena y hace referencia a un código de proveedor de la tabla Proveedores.Aquí no hemos añadido ninguna cláusula ON DELETE por lo que se toma NO ACTION.

….,

Proveedor INTEGER REFERENCES Proveedores ON DELETE NO ACTION,

…)

Estas dos sentencias son equivalentes e indican que si se intenta borrar de la tabla Proveedores un proveedor asignado a un artículo, el sistema da un error y no deja eliminar el proveedor.

….,

Proveedor INTEGER REFERENCES Proveedores ON DELETE CASCADE,

…)

Se eliminará el proveedor y todos los artículos asignados a él.

….,

Proveedor INTEGER REFERENCES Proveedores ON DELETE SET NULL,

…)

Se eliminará el proveedor de la tabla Proveedores y en la tabla Artículos, todas las filas que tenían ese número de proveedor pasarán a tener el valor nulo en el campo proveedor.

ON UPDATE { NO ACTION | CASCADE | SET NULL | SET DEFAULT }

Indica qué ocurre cuando se intenta cambiar un valor del campo relacionado de la tabla padre en la relación que estamos definiendo. El valor predeterminado es NO ACTION.

Las opciones son las mismas que para ON DELETE.

NO ACTION El Motor de base de datos genera un error y no es posible modificar la fila de la tabla primaria (el padre).

CASCADE  Si se modifica un valor de la columna padre en la tabla primaria, se modificarán automáticamente todas las filas correspondientes de la tabla que estamos

140

Page 141: Curso de SQL Server.docx

definiendo, en otras palabras, si se modifica el identificativo de un padre, se actualizan todos sus hijos.

 SET NULL Si se modifica un valor de la columna padre en la tabla primaria, todas las filas correspondientes de la tabla que estamos definiendo tomarán el valor NULL en el campo clave ajena. En otras palabras, si se modifica el identificativo de un padre, sus hijos se quedan sin padre.

Para ejecutar esta restricción, la columna clave ajena debe admitir valores NULL.SET DEFAULT Es como la anterior pero en vez del valor NULL toman el valor que tienen predeterminado. Si no hay ningún valor predeterminado establecido de forma explícita, tomarán el valor NULL. Hay que tener en cuenta que el valor predeterminado debe de existir en la tabla primaria.

Volviendo al ejemplo anterior:

….,

Proveedor INTEGER REFERENCES Proveedores ON UPDATE NO ACTION,

…)

Si cambiamos el código del proveedor 3 a 3000 y hay artículos asignados al proveedor 3,  el sistema da un error y no deja modificar el proveedor.

….,

Proveedor INTEGER REFERENCES Proveedores ON UPDATE CASCADE,

…)

Se modifica el proveedor y todos los artículos asignados a él pasan a tener el valor 3000 en el campo Proveedor.

….,

Proveedor INTEGER REFERENCES Proveedores ON UPDATE SET NULL,

…)

Se modifica el proveedor y todos los artículos asignados a él pasan a tener el valor NULL en el campo Proveedor.

Unidad 8. El DDL, Lenguaje de Definición de Datos (X)

Definir restricciones de tabla

Hasta el momento hemos aprendido a definir restricciones sobre una columna, mientras la estamos definiendo añadimos a su definición la restricción o restricciones que queramos.También existen restricciones de tabla, son restricciones que se definen después de definir todas las columnas de la tabla y que pueden afectar a una o varias columnas de la tabla. Como veremos la sintaxis para definir una restricción de tabla es muy parecida a la

141

Page 142: Curso de SQL Server.docx

sintaxis de la misma restricción de columna, lo que varía es que ahora tenemos que indicar las columnas afectadas por la restricción.

< restriccion_tabla > ::=

[ CONSTRAINT nbRestriccion]

{

    {PRIMARY KEY | UNIQUE } [ CLUSTERED | NONCLUSTERED ]

(nbCol[ASC|DESC][ ,...n ] )

        [   WITH FILLFACTOR = factorRelleno

           |WITH ( < opcion_indice > [ , ...n ] )

        ]

        [ ON { partition_scheme_name (partition_column_name)

            | filegroup | "default" } ]

   |

       FOREIGN KEY(nbCol[,...n])REFERENCES nbTablaPadre

[(col_padre)[,...n] )]

        [ ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]

        [ ON UPDATE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]

        [ NOT FOR REPLICATION ]

   | CHECK [NOT FOR REPLICATION] (expresion_validacion )

}

Como las cláusulas son las mismas que para las restricciones de columna, no repetiremos la explicación de cada cláusula, lo que veremos es un ejemplo y la explicación de ese ejemplo.

Volviendo al ejemplo anterior de la tabla de Personas, podemos definir la misma utilizando restricciones de tabla:

CREATE TABLE personas (

codigo int,

dni int,

madre int,

padre int,

dniTutor int,

PRIMARY KEY (codigo),

UNIQUE (dni),

FOREIGN KEY (madre) REFERENCES Personas,

142

Page 143: Curso de SQL Server.docx

FOREIGN KEY (padre) REFERENCES Personas (codigo),

FOREIGN KEY (dniTutor) REFERENCES Personas (dni));

También podíamos haber mezclado restricciones de columna con restricciones de tabla, lo que no podemos hacer es definir dos veces la misma restricción, o la definimos a nivel de columna o a nivel de tabla pero no dos veces!

Utilizando la restricciones de tabla parece que la definición queda más clara, por un lado tenemos la definición de cada columna, y luego las restricciones.

Las restricciones de tabla se hacen imprescindibles cuando la restricción afecta a una combinación de columnas. Por ejemplo imaginemos una tabla de productos en la que la clave principal está formada por el código de fabricante y código de producto (porque dos productos diferentes pueden tener el mismo código de producto con proveedores diferentes).No podemos definir la clave de  esta manera:

CREATE TABLE Productos (

Codproducto int PRIMARY KEY,

Codproveedor int PRIMARY KEY,

El Motor de la base de datos entendería que queremos definir dos claves primarias y eso es imposible. En este caso habría que utilizar una restricción de tabla:

CREATE TABLE Productos (

Codproducto int,

Codproveedor int,

… las demás columnas,

PRIMARY KEY (Codproducto, Codproveedor));

Ocurre lo mismo con las demás restricciones. Imaginemos ahora una tabla de líneas de pedido en la que tenemos en una línea el producto pedido, y la cantidad pedida.

CREATE TABLE LineasPed (

pedido INT,

nlin INT,

codprod INT,

codprov INT,

cantidad INT,

PRIMARY KEY (pedido, nlin),

FOREIGN KEY (codprod,codprov) REFERENCES Productos,

UNIQUE (pedido,codprod,codprov));

143

Page 144: Curso de SQL Server.docx

La combinación (codprod,codprov) forma una clave ajena que hace referencia a la tabla Productos, en este caso como la clave principal de la tabla Productos está compuesta por los dos campos, la clave ajena tiene que tener el mismo número de campo y del mismo tipo.

Con la restricción UNIQUE indicamos que la combinación formada por un número de pedido un código de producto y código de proveedor no se puede repetir, esto hace que no se puedan insertar en un mismo pedido dos líneas del mismo producto.  No se puede duplicar la combinación pero sí las columnas individualmente (pueden haber varias filas con el mismo número de pedido, varias filas con el mismo código de producto y varias filas con el mismo codigo de proveedor.

Aquí termina la explicación de la sintaxis básica de las instrucciones CREATE TABLE. Nos queda hablar de las columnas calculadas y de las tablas temporales, otras cláusulas de la instrucción se pueden consultar en la ayuda de la instrucción SQL CREATE TABLE.

Unidad 8. El DDL, Lenguaje de Definición de Datos (XI)

Definir columnas calculadas.

Una columna calculada es una columna cuyo valor no se introduce, sino que se obtiene como resultado de un cálculo.

< definicion_columna > ::=

nbCol AS expresion

    [ PERSISTED

[NOT NULL]

      [ <restriccion_columna> [...n ] ]

    ] 

expresion es la expresión que define el valor de una columna calculada y está basada en otras columnas de la tabla.

Por ejemplo, una columna calculada puede ser definida así:

 importe AS precio * cantidad

La expresión puede ser un nombre de columna no calculada, una constante, una función, una variable o cualquier combinación de estos elementos conectados mediante uno o más operadores. La expresión no puede ser una subconsulta ni contener tipos de datos de alias.

Una columna calculada es, por defecto, una columna virtual no almacenada físicamente en la tabla. PERSISTED indica que la columna calculada se almacena en la tabla y automáticamente se actualizan los valores almacenados en ella cuando se actualizan las columnas de las que depende.

Para que la columna pueda ser definida con PERSISTED la expresión que la calcula debe ser determinista. Una expresión es determinista a menos que utilice una función no determinista.

144

Page 145: Curso de SQL Server.docx

Una columna calculada se puede utilizar en la lista de selección, cláusula WHERE, cláusula ORDER BY u otras ubicaciones en que se puedan utilizar expresiones regulares, con las siguientes excepciones:

Una columna calculada no puede utilizarse como definición de restricción DEFAULT o FOREIGN KEY ni como NOT NULL.

Una columna calculada no puede ser el destino de una instrucción INSERT o UPDATE.  No tiene sentido querer asignar un determinado

Definir tablas temporales

Una tabla temporal es una tabla creada por un determinado proceso y desaparece cuando termina éste.

Se pueden crear tablas temporales locales y globales. Las tablas temporales locales son visibles sólo en la sesión actual y las tablas temporales globales son visibles para todas las sesiones.

Para indicar que la tabla que queremos crear es temporal añadimos a su nombre el prefijo # (#nbTabla) para tablas temporales locales y el prefijo ## (##nbTabla) tablas temporales globales.

Por ejemplo:

CREATE TABLE #trabajo (col1 INT PRIMARY KEY);

Esta instrucción crea una tabla temporal local llamada trabajo con una sola columna.

Las tablas temporales funcionan casi como las tablas normales con algunas diferencias.

No se pueden crear particiones en las tablas temporales.

nbTabla no puede tener más de 116 caracteres. Esto se debe a que si se crea una tabla temporal local en un procedimiento almacenado o una aplicación que varios usuarios pueden ejecutar al mismo tiempo, el Motor de base de datos tiene que ser capaz de distinguir las tablas creadas por los distintos usuarios, lo consigue añadiendo internamente un sufijo numérico a cada nombre de tabla temporal local. El nombre completo de una tabla temporal tal como se almacena en la tabla sysobjects de tempdb consta del nombre de la tabla especificado en la instrucción CREATE TABLE y el sufijo numérico generado por el sistema.

Las tablas temporales se quitan automáticamente cuando están fuera de ámbito, a menos que ya se hayan quitado explícitamente mediante DROP TABLE: Una tabla temporal local creada en un procedimiento almacenado se quita automáticamente cuando se completa el procedimiento almacenado. Cualquiera de los procedimientos almacenados anidados ejecutados por el procedimiento almacenado que creó la tabla, puede hacer referencia a la tabla. El proceso que llamó al procedimiento almacenado que creó la tabla no puede hacer referencia a la tabla.

Las tablas temporales se quitan automáticamente al final de la sesión actual.

Las tablas temporales globales se quitan automáticamente cuando la sesión que creó la tabla finaliza y las tareas restantes han dejado de hacer referencia a ellas. La asociación entre una tarea y una tabla se mantiene sólo durante la vida de una única instrucción Transact-SQL. Esto significa que la tabla temporal global se quita al finalizar la última instrucción Transact-SQL que estuviera haciendo referencia activamente a la tabla cuando finalizó la sesión que la creó.

145

Page 146: Curso de SQL Server.docx

Una tabla temporal local creada en un procedimiento almacenado o desencadenador, puede tener el mismo nombre que una tabla temporal creada antes de que se llame al procedimiento almacenado o al desencadenador. No obstante, si una consulta hace referencia a una tabla temporal y hay dos tablas temporales con el mismo nombre, no está definido en cuál de las dos tablas debe resolverse la consulta. Los procedimientos almacenados anidados pueden crear también tablas temporales con el mismo nombre que la tabla temporal creada por el procedimiento almacenado que la llamó. Sin embargo, en el caso de las modificaciones que se van a resolver en la tabla creada en el procedimiento anidado, la tabla debe tener la misma estructura, con los mismos nombres de columnas, que la tabla creada en el procedimiento que realiza la llamada. Esto se muestra en el ejemplo siguiente.

Con tablas temporales globales o locales, la sintaxis CREATE TABLE admite la definición de restricciones, excepto las restricciones FOREIGN KEY. Si se especifica una restricción FOREIGN KEY en una tabla temporal, la instrucción devuelve un mensaje de advertencia que indica que la restricción se ha omitido. La tabla se crea sin las restricciones FOREIGN KEY. En las restricciones FOREIGN KEY no se puede hacer referencia a tablas temporales.

Se recomienda utilizar variables de tabla en lugar de tablas temporales. Las tablas temporales son útiles cuando es necesario crear en ellas índices de forma explícita o bien cuando los valores de tabla deben ser visibles en varios procedimientos almacenados o funciones. En general, las variables de tabla contribuyen a que el procesamiento de las consultas sea más eficaz.

Unidad 8. El DDL, Lenguaje de Definición de Datos (XII)

8.6. Eliminar una tabla DROP TABLE

Para eliminar una tabla de una base de datos tenemos la sentencia DROP TABLE. Con ella quitamos una o varias definiciones de tabla y todos los datos, índices, desencadenadores, restricciones y especificaciones de permisos que tengan esas tablas. Las vistas o procedimientos almacenados que hagan referencia a la tabla quitada se deben quitar explícitamente con DROP VIEW o DROP PROCEDURE.

Su sintaxis es:

DROP TABLE [nbBaseDatos.[nbEsquema].|nbEsquema.]nbTabla[ ,...n ] [ ; ]

Para que las reglas de integridad referencial se cumplan, no se puede eliminar una tabla señalada por una restricción FOREIGN KEY. Primero se debe quitar la restricción FOREIGN KEY o la tabla que tiene la clave ajena.

Se pueden quitar varias tablas de cualquier base de datos en una misma sentencia DROP TABLE. Se irán eliminando en el mismo orden en que aparecen en la lista por lo que podremos eliminar dos tablas relacionadas con una sola sentencia pero escribiendo la tabla que contiene la clave ajena primero y después la tabla principal.

Requiere el permiso CONTROL en la tabla o pertenecer a la función fija de base de datos db_ddladmin.

Ejemplo:

DROP TABLE mitabla;

146

Page 147: Curso de SQL Server.docx

Elimina la tabla miTabla tanto su definición como los datos, índices definidos sobre ella y permisos.

8.7. Modificar la definición de una tabla ALTER TABLE

ALTER TABLE [nbBaseDatos.[nbEsquema].| nbEsquema.]nbTabla

{ ALTER COLUMN nbColumna

      {

        <tipo_dato>

        [ NULL | NOT NULL ]

        [ COLLATE nbIntercalacion ]

      | {ADD | DROP } { ROWGUIDCOL | PERSISTED }

      }

| [WITH{ CHECK | NOCHECK}] ADD

       {

        <definicion_columna>

      | <definicion_colCalc>

      | <restriccion_tabla>

       } [ ,...n ]

| DROP

       {

        [CONSTRAINT] nbRestriccion

        |COLUMN nbColumna

       } [,...n ]

| {CHECK|NOCHECK} CONSTRAINT {ALL|nbRestriccion[ ,...n ]}

| {ENABLE|DISABLE} TRIGGER {ALL | nbTrigger [ ,...n ] }

}

[ ; ]

Aunque la sintaxis parece un poco complicada, realmente no lo es. La sentencia nos permite variar la definición de una tabla ya creada, en qué consiste esta variación: modificar la definición de columnas ya existentes (ALTER COLUMN), añadir más columnas o restricciones (ADD), eliminar columnas y restricciones (DROP), habilitar/deshabilitar restricciones (CHECK CONSTRAINT) y habilitar/deshabilitar triggers.

Como muchas de las cláusulas las hemos estudiado con CREATE TABBLE, sólo incidiremos en lo nuevo.

Para modificar una columna escribiremos la cláusula ALTER COLUMN seguida del nombre de la columna que queremos modificar y la nueva definición, podemos cambiar su tipo de datos indicando uno nuevo, hacer que la columna acepte o no valores nulos (NULL|NOTNULL), cambiar la intercalación (COLLATE).

Con ADD ROWGUIDCOL  hacemos que la columna sea GUID de filas y DROP ROWGUIDCOL hacemos que ya no lo sea.

147

Page 148: Curso de SQL Server.docx

Si la columna es una columna calculada podemos cambiar su condición de columna almacenada con ADD/DROP PERSISTED.

Ejemplo:

ALTER TABLE Clientes ALTER COLUMN direccion VARCHAR(40);

Hace que la columna direccion de la tabla Clientes, ahora admita 40 caracteres alfanuméricos.Cuando cambiamos el tipo de una columna hay que tener en cuenta que el nuevo tipo debe ser compatible con el antiguo para que no se pierdan los datos almacenados.Además la columna no se puede modificar si es ROWGUIDCOL, calculada o si se  utiliza en una columna calculada, si se utiliza en un índice (a menos que la columna sea del tipo de datos varchar, nvarchar o varbinary, el tipo de datos no se cambie y el nuevo tamaño sea igual al tamaño anterior o mayor que éste), si se utiliza en estadísticas, en una restricción PRIMARY KEY, FOREIGN KEY, CHECK o UNIQUE. Sin embargo, se permite el cambio de longitud de una columna de longitud variable en una restricción CHECK o UNIQUE.

Unidad 8. El DDL, Lenguaje de Definición de Datos (XIII)

Para añadir una nueva columna o restricción utilizamos la cláusula ADD seguida de la definición de lo que queremos añadir, para eso seguimos la misma sintaxis que para definir las columnas y restricciones de tabla del CREATE TABLE. Por ejemplo:

ALTER TABLE Clientes ADD email varchar(50);

Añade una nueva columna email.

ALTER TABLE Clientes ADD CONSTRAINT Pk PRIMARY KEY (codcli);

Añade una restricción de clave primaria sobre la columna codcli que ya existe en la tabla.

La cláusula WITH CHECK|NOCHECK permite establecer si la restricción que estamos añadiendo se tiene que comprobar en las filas que ya existen en la tabla.

Con la cláusula DROP podemos eliminar de la tabla una restricción (DROP CONSTRAINT), o una columna (DROP COLUMN).

Con las siguientes limitaciones:

Una restricción PRIMARY KEY no puede quitarse si existe un índice XML en la tabla. Una columna no puede quitarse si se utiliza en un índice, en una restricción CHECK, FOREIGN KEY, UNIQUE o PRIMARY KEY, DEFAULT.

Ejemplo:

ALTER TABLE Clientes DROP COLUMN email;

Elimina de la tabla Clientes la columna email que habíamos creado anteriormente.

ALTER TABLE Clientes DROP CONSTRAINT pk ;

148

Page 149: Curso de SQL Server.docx

Elimina de la tabla Clientes la restricción de PRIMARY KEY, la columna sigue en la tabla pero ya no es clave principal.

Para finalizar, las dos últimas cláusulas nos permiten indicar si se tienen que comprobar o no determinadas restricciones y habilitar y deshabilitar triggers.

CHECK CONSTRAINT ALL activa la comprobación de todas las restricciones definidas sobre la tabla.

DISABLE TRIGGER ALL deshabilita todos los triggers definidos sobre la tabla.Cuando deshabilitamos un trigger, éste sigue definido, pero no entra en acción cuando se produce el evento que debería activarlo. En cualquier momento lo podremos habilitar con otra instrucción ALTER TABLE.

8.8. Crear una vista CREATE VIEW

Una vista es una tabla virtual que representa los datos de una o más tablas de una forma alternativa. Para crear una nueva vista se emplea la sentencia CREATE VIEW, debe ser la primera instrucción en un lote de consultas.

Una vista sólo se puede crear en la base de datos actual.

 Para ejecutar CREATE VIEW, se necesita, como mínimo, el permiso CREATE VIEW en la base de datos y el permiso ALTER en el esquema en el que se está creando la vista. Sintaxis:

CREATE VIEW [nbEsquema.] nbVista

[ (columna [ ,...n ] ) ]

    AS ( sentencia_select ) [ ; ]

nbEsquema Es el nombre del esquema al que pertenece la nueva tabla.

nbVista Es el nombre de la nueva vista. Los nombres de vistas deben seguir las reglas de los identificadores.

sentencia_select Es la instrucción SELECT que define la vista. Dicha instrucción puede utilizar más de una tabla y otras vistas. Se necesitan permisos adecuados para seleccionar los objetos a los que se hace referencia en la cláusula SELECT de la vista que se ha creado.

Una vista no tiene por qué ser un simple subconjunto de filas y de columnas de una tabla determinada. Es posible crear una vista que utilice más de una tabla u otras vistas mediante una cláusula SELECT de cualquier complejidad.

También se pueden utilizar funciones y varias instrucciones SELECT separadas por UNION o UNION ALL.

Una vista puede tener como máximo 1.024 columnas.

Unidad 8. El DDL, Lenguaje de Definición de Datos (XIV)

Ejemplos:

149

Page 150: Curso de SQL Server.docx

CREATE VIEW oficinas_este

AS SELECT * FROM oficinas WHERE region = ‘Este’;

Crea una vista con las oficinas del este.

CREATE VIEW oficinas_empleados

AS

SELECT oficinas.oficina AS ofi, ciudad, dir, region, objetivo, oficinas.ventas AS ventas_ofi, empleados.*

FROM oficinas INNER JOIN empleados

        ON oficinas.oficina = empleados.oficina;

Crea una vista con los datos de todos los empleados y de sus oficinas.En este caso hemos tenido que definir alias de campo porque en el origen de la sentencia SELECT existe duplicidad de nombres.

CREATE VIEW oficinas_EO

AS

SELECT * FROM oficinas WHERE region = ‘Este’;

UNION ALL

SELECT * FROM oficinas WHERE region = ‘Oeste’;

Por defecto las columnas de la vista heredan los nombres de las columnas de la sentencia SELECT asociada, pero podemos cambiar estos nombres indicando una lista de columnas después del nombre de la vista.

CREATE VIEW oficinas_este (Eoficina, Eciudad, Eregion, Edir, Eobjetivo,Eventas)

AS SELECT * FROM oficinas WHERE region = ‘Este’;

Utilizando una lista de columnas ya no tenemos que definir alias de columna en la sentencia SELECT como pasaba en el caso de la vista oficinas_empleados.

Normalmente se utiliza la lista de columnas cuando una columna proviene de una expresión aritmética, una función o una constante; cuando dos o más columnas puedan tener el mismo nombre, normalmente debido a una combinación; o cuando una columna de una vista recibe un nombre distinto al de la columna de la que proviene.

En definitiva se puede optar por utilizar la lista de columnas o definir alias de campo en la sentencia SELECT.

Cuando utilizamos una vista en una operación de actualización (INSERT, UPDATE, DELETE), la vista debe ser actualizable, para ello debe seguir las siguientes reglas:

Cualquier modificación, incluida en las instrucciones UPDATE, INSERT y DELETE, debe hacer referencia a las columnas de una única tabla base.

150

Page 151: Curso de SQL Server.docx

Las columnas que se vayan a modificar en la vista deben hacer referencia directa a los datos subyacentes de las columnas de la tabla, es decir que las columnas no se pueden obtener de otra forma, como con una función de agregado: AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VAR y VARP, o un cálculo.

Las columnas formadas mediante los operadores de conjunto UNION, UNION ALL, CROSSJOIN, EXCEPT e INTERSECT equivalen a un cálculo y tampoco son actualizables.

Las columnas que se van a modificar no se ven afectadas por las cláusulas GROUP BY, HAVING o DISTINCT.

Las restricciones anteriores se aplican a cualquier subconsulta de la cláusula FROM de la vista, al igual que a la propia vista. Normalmente, el Database Engine (Motor de base de datos) debe poder realizar un seguimiento sin ambigüedades de las modificaciones de la definición de la vista a una tabla base.

8.9. Eliminar una vista DROP VIEW

Para eliminar una vista de una base de datos tenemos la sentencia DROP TABLE. Sintaxis:

DROP VIEW [nbEsquema.]nbVista[ ,...n ] [ ; ]

Se eliminan las vista de la base de datos actual. Cuando eliminamos una vista eliminamos su definición y los permisos asociados a ella.

Se pueden quitar varias vistas en una misma sentencia DROP VIEW escribiendo los nombres de las vistas a eliminar separados por comas.

Para ejecutar DROP VIEW, como mínimo, se necesita el permiso ALTER en SCHEMA o el permiso CONTROL en OBJECT.

Ejemplo:

DROP VIEW oficinas_este, oficinas_EO;

Elimina las vistas oficinas_este y oficinas_EO.

Si eliminamos una tabla mediante DROP TABLE, se deben quitar explícitamente, con DROP VIEW, las vistas basadas en esta tabla ya que no se quitarán por sí solas.

Unidad 8. El DDL, Lenguaje de Definición de Datos (XV)

8.10. Definición de índice

Un índice es una estructura de datos definida sobre una columna de tabla (o varias) y que permite localizar de forma rápida las filas de la tabla en base a su contenido en la columna indexada además de permitir recuperar las filas de la tabla ordenadas por esa misma columna.

Funciona de forma parecida al índice de un libro donde tenemos el título del capítulo y la página donde empieza dicho capítulo, en un índice definido sobre una determinada

151

Page 152: Curso de SQL Server.docx

columna tenemos el contenido de la columna y la posición de la fila que contiene dicho valor dentro de la tabla.

La definición de los índices de la base de datos es tarea del administrador de la base de datos, los administradores más experimentados pueden diseñar un buen conjunto de índices, pero esta tarea es muy compleja, consume mucho tiempo y está sujeta a errores, incluso con cargas de trabajo y bases de datos con un grado de complejidad no excesivo.

8.11. Tipos de índices

Índice simple y compuesto.

Un índice simple está definido sobre una sóla columna de la tabla mientras que un índice compuesto está formado por varias columnas de la misma tabla (tabla sobre la cual está definido el índice.

Cuando se define un índice sobre una columna, los registros que se recuperen utilizando el índice aparecerán ordenados por el campo indexado. Si se define un índice compuesto por las columnas col1 y col2, las filas que se recuperen utilizando dicho índice aparecerán ordenadas por los valores de col1 y todas las filas que tengan el mismo valor de col1 se ordenarán a su vez por los valores contenidos en col2, función igual que la cláusula ORDER BY vista en el tema de consultas simples.

Por ejemplo si definimos un índice compuesto basado en las columnas (provincia, localidad), las filas que se recuperen utilizando este índice aparecerán ordenadas por provincia y dentro de la misma provincia por localidad.

Índice agrupado y no agrupado,

El término índice agrupado no se debe confundir con índice compuesto, el significado es totalmente diferente.

Un índice agrupado (CLUSTERED) es un índice en el que el orden lógico de los valores de clave determina el orden físico de las filas correspondientes de la tabla. El nivel inferior, u hoja, de un índice agrupado contiene las filas de datos en sí de la tabla. Una tabla o vista permite un solo índice agrupado al mismo tiempo.

Los índices no agrupados existentes en las tablas se vuelven a generar al crear un índice agrupado, por lo que es conveniente crear el índice agrupado antes de crear los índices no agrupados.

Un índice no agrupado especifica la ordenación lógica de la tabla. Con un índice no agrupado, el orden físico de las filas de datos es independiente del orden indizado.

Índice único

Índice único es aquel en el que no se permite que dos filas tengan el mismo valor en la columna de clave del índice. Es decir que no permite valores duplicados.

8.12. Ventajas e inconvenientes de los índices

Ventajas

La utilización de índices puede mejorar el rendimiento de las consultas, ya que los datos necesarios para satisfacer las necesidades de la consulta existen en el propio índice. Es decir, sólo se necesitan las páginas de índice y no las páginas de datos de la tabla o el índice agrupado para recuperar los datos solicitados; por tanto, se reduce la E/S global en el disco. Por ejemplo, una consulta de las columnas a y b de una tabla que

152

Page 153: Curso de SQL Server.docx

dispone de un índice compuesto creado en las columnas a, b y c puede recuperar los datos especificados del propio índice.

Los índices en vistas pueden mejorar de forma significativa el rendimiento si la vista contiene agregaciones, combinaciones de tabla o una mezcla de agregaciones y combinaciones.

Inconvenientes

Las tablas utilizadas para almacenar los índices ocupan espacio.

Los índices consumen recursos ya que cada vez que se realiza una operación de actualización, inserción o borrado en la tabla indexada, se tienen que actualizar todas las tablas de índice definidas sobre ella (en la actualización sólo es necesaria la actualización de los índices definidos sobre las columnas que se actualizan).Por estos motivos no es buena idea definir índices indiscriminadamente.

Consideraciones a tener en cuenta

A la hora de definir índices se deben de tener en cuenta estas consideraciones:

Hay que evitar crear demasiados índices en tablas que se actualizan con mucha frecuencia y procurar definirlos con el menor número de columnas posible.

Es conveniente utilizar un número mayor de índices para mejorar el rendimiento de consultas en tablas con pocas necesidades de actualización, pero con grandes volúmenes de datos. Un gran número de índices contribuye a mejorar el rendimiento de las consultas que no modifican datos, como las instrucciones SELECT, ya que el optimizador de consultas dispone de más índices entre los que elegir para determinar el método de acceso más rápido.

La indización de tablas pequeñas puede no ser una solución óptima, porque puede provocar que el optimizador de consultas tarde más tiempo en realizar la búsqueda de los datos a través del índice que en realizar un simple recorrido de la tabla. De este modo, es posible que los índices de tablas pequeñas no se utilicen nunca; sin embargo, sigue siendo necesario su mantenimiento a medida que cambian los datos de la tabla.

Se recomienda utilizar una longitud corta en la clave de los índices agrupados. Los índices agrupados también mejoran si se crean en columnas únicas o que no admitan valores NULL.

Un índice único en lugar de un índice no único con la misma combinación de columnas proporciona información adicional al optimizador de consultas y, por tanto, resulta más útil.

Hay que tener en cuenta el orden de las columnas si el índice va a contener varias columnas. La columna que se utiliza en la cláusula WHERE en una condición de búsqueda igual a (=), mayor que (>), menor que (<) o BETWEEN, o que participa en una combinación, debe situarse en primer lugar. Las demás columnas deben ordenarse basándose en su nivel de diferenciación, es decir, de más distintas a menos distintas.

Unidad 8. El DDL, Lenguaje de Definición de Datos (XVI)

8.13. Definir un índice CREATE INDEX

153

Page 154: Curso de SQL Server.docx

CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX nombre_indice

    ON <objeto> (columna [ ASC | DESC ] [ ,...n ] )

 [ ; ]

<objeto> ::=

{

    [nbBaseDatos.[nbEsquema].| nbEsquema.]nbTablaVista

}

Esta es la sintaxis simplicada de la instrucción CREATE INDEX que permite crear un índice en una tabla sobre una o varias columnas.

nbBaseDatos Es el nombre de la base de datos.

nbEsquema Es el nombre del esquema al que pertenece la tabla/vista.

nbTablaVista Es el nombre de la tabla o vista sobre la que se quiere crear el índice.

nombre_indice Es el nombre del índice que estamos creando.

Columna Es el nombre de la columna que forma parte del índice. Se pueden definir índices compuestos escribiendo entre paréntesis los nombres de las columnas separados por comas.

ASC los valores de la columna se ordenarán de forma ASCendente o DESCendente.

Por defecto se asume ASC.

UNIQUE permite definir un índice único (no admite valores repetidos).

CLUSTERED el índice será agrupado.

NONCLUSTERED (valor por defecto) el índice será no agrupado.

Ejemplos:

CREATE INDEX I_clientes_nombre ON Clientes (nombre)

Crea un índice no agrupado sobre la columna nombre de la tabla Clientes en la base de datos actual, las filas se ordenarán de forma ascendente.

CREATE INDEX I_clientes_ApeNom ON Clientes (apellidos, nombre)

Crea un índice no agrupado sobre las columnas apellidos y nombre de la tabla Clientes en la base de datos actual, las filas se ordenarán de forma ascendente por apellido y dentro del mismo apellido por nombre.

CREATE INDEX I_clientes_EdadApe ON Clientes (edad DESC,apellidos)

154

Page 155: Curso de SQL Server.docx

Crea un índice no agrupado sobre las columnas edad y apellidos de la tabla Clientes en la base de datos actual, las filas se ordenarán de forma descendente por edad y ascendente por apellido. Aparecerán los clientes de mayor a menor edad y los clientes de la misma edad se ordenarán por apellido (por orden alfabético).

CREATE CLUSTERED INDEX I_clientes_cod ON Clientes (codigo)

Crea un índice agrupado sobre la columna codigo de la tabla Clientes en la base de datos actual, las filas se ordenarán y almacenarán por orden de código.

CREATE UNIQUE INDEX U_clientes_col ON Clientes (col)

Crea un índice único sobre la columna col de la tabla Clientes en la base de datos actual, la columna col no podrá contener valores duplicados.

8.14. Eliminar un índice DROP INDEX

Para eliminar un índice tenemos la sentencia DROP INDEX. La instrucción DROP INDEX no es aplicable a los índices creados mediante la definición de restricciones PRIMARY KEY y UNIQUE. Para quitar la restricción y el índice correspondiente, se tiene que ejecutar un ALTER TABLE con la cláusula DROP CONSTRAINT.

Sintaxis simplificada:

DROP INDEX <indice> [ ,...n ] [ ; ]

<indice>::=

{

nbindice ON [nbBaseDatos.[nbEsquema].|nbEsquema.]nbTablaVista

}

nbBaseDatos Es el nombre de la base de datos.

nbEsquema Es el nombre del esquema al que pertenece la tabla/vista.

nbTablaVista Es el nombre de la tabla o vista de la que se quiere eliminar el índice.

nbindice Es el nombre del índice a eliminar.

Ejemplo:

DROP INDEX U_clientes_col ON Clientes;

Elimina el índice U_clientes_col definido sobre la tabla Clientes.

Unidad 9. Programación en TRANSACT SQL (I)

9.1. Introducción

155

Page 156: Curso de SQL Server.docx

Hasta ahora hemos estudiado sentencias SQL orientadas a realizar una determinada tarea sobre la base de datos como definir tablas, obtener información de las tablas, actualizarlas; estas sentencias las hemos ejecutado desde el editor de consultas del MSSMS de una en una o a lo sumo una a continuación de la otra dentro de la misma consulta formando un lote de instrucciones.

Las sentencias que ya conocemos son las que en principio forman parte de cualquier lenguaje SQL. Ahora veremos que TRANSACT-SQL va más allá de un lenguaje SQL cualquiera ya que aunque no permita:

Crear interfaces de usuario.

Crear aplicaciones ejecutables, sino elementos que en algún momento llegarán al servidor de datos y serán ejecutados.

Incluye características propias de cualquier lenguaje de programación, características que nos permiten definir la lógica necesaria para el tratamiento de la información:

Tipos de datos.

Definición de variables.

Estructuras de control de flujo.

Gestión de excepciones.

Funciones predefinidas.

Elementos para la visualización, que permiten mostrar mensajes definidos por el usuario gracias a la cláusula PRINT.

Estas características nos van a permitir crear bloques de código orientados a realizar operaciones más complejas. Estos bloques no son programas sino procedimientos o funciones que podrán ser llamados en cualquier momento.En SQL Server 2005 podemos definir tres tipos de bloques de código, los procedimientos almacenados, los desencadenadores (o triggers) y funciones definidas por el usuario.

Nosotros estudiaremos los dos primeros.

Empezaremos por los procedimientos almacenados, veremos primero las sentencias para crear y eliminar procedimientos almacenados, luego estudiaremos las instrucciones Transact-SQL más propias de un lenguaje de programación nombradas en el tema de Introducción al Transact-SQL  como son por ejemplo los bucles y estructuras condicionales. Estas instrucciones las utilizaremos dentro de procedimientos almacenados pero veremos que también nos servirán para definir otros bloques de código.Terminaremos esta unidad de programación estudiando los disparadores o Triggers muy similares a los procedimientos almacenados que difieren básicamente en la forma en que entran en funcionamiento.

9.2. Procedimientos almacenados STORE PROCEDURE

Un procedimiento almacenado (STORE PROCEDURE) está formado por un conjunto de instrucciones Transact-SQL que definen un determinado proceso, puede aceptar parámetros de entrada y devolver un valor o conjunto de resultados. Este procedimiento se guarda en el servidor y puede ser ejecutado en cualquier momento.

Los procedimientos almacenados se diferencian de las instrucciones SQL ordinarias y de los lotes de instrucciones SQL en que están precompilados. La primera vez que se ejecuta un procedimiento, el procesador de consultas de SQL Server lo analiza y prepara un plan de ejecución que se almacena en una tabla del sistema. Posteriormente, el procedimiento se ejecuta según el plan almacenado. Puesto que ya se ha realizado la

156

Page 157: Curso de SQL Server.docx

mayor parte del trabajo de procesamiento de consultas, los procedimientos almacenados se ejecutan casi de forma instantánea por lo que el uso de procedimientos almacenados mejora notablemente la potencia y eficacia del SQL.

SQL Server incorpora procedimientos almacenados del sistema, se encuentran en la base de datos master y se reconocen por su nombre, todos tienen un nombre que empieza por sp_. Permiten recuperar información de las tablas del sistema y pueden ejecutarse en cualquier base de datos del servidor.

También están los procedimientos de usuario, los crea cualquier usuario que tenga los permisos oportunos.

Se pueden crear también procedimiento temporales locales y globales. Un procedimiento temporal local se crea por un usuario en una conexión determinada y sólo se puede utilizar en esa sesión, un procedimiento temporal global lo pueden utilizar todos los usuarios, cualquier conexión puede ejecutar un procedimiento almacenado temporal global. Éste existe hasta que se cierra la conexión que el usuario utilizó para crearlo, y hasta que se completan todas las versiones del procedimiento que se estuvieran ejecutando mediante otras conexiones. Una vez cerrada la conexión que se utilizó para crear el procedimiento, éste ya no se puede volver a ejecutar, sólo podrán finalizar las conexiones que hayan empezado a ejecutar el procedimiento.

Tanto los procedimientos temporales como los no temporales se crean y ejecutan de la  misma forma, el nombre que le pongamos indicará de qué tipo es el procedimiento.

Los procedimientos almacenados se crean mediante la sentencia CREATE PROCEDURE y se ejecutan con EXEC (o EXECUTE). Para ejecutarlo también se puede utilizar el nombre del procedimiento almacenado sólo, siempre que sea la primera palabra del lote.  Para eliminar un procedimiento almacenado utilizamos la sentencia DROP PROCEDURE.

9.3. Eliminar procedimientos almacenados

Aunque no sabemos todavía crear un procedimiento comentaremos aquí la instrucción para eliminar procedimientos y así podremos utilizarla en los demás ejercicios.

DROP {PROC|PROCEDURE} [nombreEsquema.]nombreProcedimiento [,...n ].

Transact-SQL permite abreviar la palabra reservada PROCEDURE por PROC sin que ello afecte a la funcionalidad de la instrucción.

Ejemplos:

DROP PROCEDURE Dice_Hola;

Elimina el procedimiento llamado Dice_Hola.

DROP PROC Dice_Hola;

Es equivalente, PROC y PROCEDURE indican lo mismo.

Para eliminar varios procedimientos de golpe, indicamos sus nombres separados por comas:

157

Page 158: Curso de SQL Server.docx

DROP PROCEDURE Dice_Hola, Ventas_anuales;

Elimina los procedimientos Dice_Hola y Ventas_anuales.

Unidad 9. Programación en TRANSACT SQL (II)

9.4. Crear y ejecutar un procedimiento

CREATE PROCEDURE

Para crear un procedimiento almacenado como hemos dicho se emplea la instrucción CREATE PROCEDURE:

CREATE {PROC|PROCEDURE} [NombreEsquema.]NombreProcedimiento

    [{@parametro tipo} [VARYING] [= valorPredet] [OUT|OUTPUT] ] [,...n]

    AS { <bloque_instrucciones> [ ...n] }[;]

<bloque_instrucciones> ::=

{[BEGIN] instrucciones [END] }

Las instrucciones CREATE PROCEDURE no se pueden combinar con otras instrucciones SQL en el mismo lote.

Después del verbo CREATE PROCEDURE indicamos el nombre del procedimiento, opcionalmente podemos incluir el nombre del esquema donde queremos que se cree el procedimiento, por defecto se creará en dbo. Ya que Sqlserver utiliza el prefijo sp_ para nombrar los procedimientos del sistema se recomienda no utilizar nombres que empiecen por sp_.

Como se puede deducir de la sintaxis (no podemos indicar un nombre de base de datos asociado al nombre del procedimiento) sólo se puede crear el procedimiento almacenado en la base de datos actual, no se puede crear en otra base de datos.Si queremos definir un procedimiento temporal local el nombre deberá empezar por una almohadilla (#) y si el procedimiento es temporal global el nombre debe de empezar por ##.El nombre completo de un procedimiento almacenado o un procedimiento almacenado temporal global, incluidas ##, no puede superar los 128 caracteres. El nombre completo de un procedimiento almacenado temporal local, incluidas #, no puede superar los 116 caracteres.

Transact-SQL permite abreviar la palabra reservada PROCEDURE por PROC sin que ello afecte a la funcionalidad de la instrucción.

CREATE PROC Calcula_comision AS…

Es equivalente a

CREATE PROCEDURE calcula_comision AS…

158

Page 159: Curso de SQL Server.docx

@parametro:  representa el nombre de un parámetro. Se pueden declarar uno o más parámetros indicando para cada uno su nombre (debe de empezar  por arroba) y su tipo de datos, y opcionalmente un valor por defecto (=valorPredet) este valor será el asumido si en la llamada el usuario no pasa ningún valor para el parámetro. Un procedimiento almacenado puede tener un máximo de 2.100 parámetros.

Los parámetros son locales para el procedimiento; los mismos nombres de parámetro se pueden utilizar en otros procedimientos. De manera predeterminada, los parámetros sólo pueden ocupar el lugar de expresiones constantes; no se pueden utilizar en lugar de nombres de tabla, nombres de columna o nombres de otros objetos de base de datos.

VARYING Sólo se aplica a los parámetros de tipo cursor por lo que se explicará cuando se expliquen los cursores.

OUTPUT | OUT (son equivalentes)

Indica que se trata de un parámetro de salida. El valor de esta opción puede devolverse a la instrucción EXECUTE que realiza la llamada.

El parámetro variable OUTPUT debe definirse al crear el procedimiento y también se indicará en la llamada junto a la variable que recogerá el valor devuelto del parámetro. El nombre del parámetro y de la variable no tienen por qué coincidir; sin embargo, el tipo de datos y la posición de los parámetros deben coincidir a menos que se indique el nombre del parámetro en la llamada de la forma @parametro=valor.

Procedimiento básico

CREATE PROCEDURE  Dice_Hola

AS

PRINT ‘Hola’;

GO           –- Indicamos GO para cerrar el lote que crea el procedimiento y empezar otro lote.

EXEC Dice_Hola;  -- De esta forma llamamos al procedimiento (se ejecuta).

En este caso, como la llamada es la primera del lote (va detrás del GO) podíamos haber obviado la palabra EXEC y haber escrito directamente:

Dice_Hola

Unidad 9. Programación en TRANSACT SQL (III)

Con un parámetro de entrada (la palabra que queremos que escriba)

CREATE PROCEDURE Dice_Palabra @palabra CHAR(30)

AS

PRINT @palabra;

GO

EXEC Dice_Palabra ‘Lo que quiera’;

159

Page 160: Curso de SQL Server.docx

EXEC Dice_Palabra ‘Otra cosa’;

Aquí hemos hecho dos llamadas, una con el valor ‘Lo que quiera’ y otra con el valor ‘Otra cosa’.

Con varios parámetros

Si queremos indicar varios parámetros los separamos por comas.

USE Biblio;

--DROP PROC VerUsuariosPoblacion; --La comentamos la primera vez

GO

CREATE PROCEDURE VerUsuariosPoblacion @pob CHAR(30),@pro CHAR(30)

AS

SELECT * FROM usuarios WHERE poblacion=@pob AND provincia = @pro;

GO

EXEC VerUsuariosPoblacion Madrid, Valencia

En la llamada podemos indicar los valores de los parámetros de varias formas,indicando sólo el valor de los  parámetros (en este caso los tenemos que indicar en el mismo orden en que están definidos) como en el ejemplo anterior, o bien indicando el nombre del parámetro:

EXEC VerUsuariosPoblacion @pob=Madrid, @pro=Valencia

Indicar el nombre del parámetro en la llamada también nos permite indicar los valores en cualquier orden, la siguiente llamada es equivalente a la anterior, hemos invertido el orden y se ejecuta igual:

EXEC VerUsuariosPoblacion @pro=Valencia, @pob=Madrid

En este procedimiento todos los parámetros son obligatorios, no deja llamar con un solo parámetro.

EXEC VerUsuariosPoblacion Madrid

Da error.

Con parámetros opcionales

Para definir un parámetro opcional tenemos que asignarle un valor por defecto  en la definición del procedimiento.

DROP PROC VerUsuariosPoblacion2;

160

Page 161: Curso de SQL Server.docx

GO

CREATE PROCEDURE VerUsuariosPoblacion2 @pob CHAR(30),@pro CHAR(30)='Madrid'

AS

SELECT * FROM usuarios WHERE poblacion=@pob AND provincia = @pro;

GO

EXEC VerUsuariosPoblacion2 Madrid

En este caso, en la llamada sólo hemos indicado un valor, para el primer parámetro, el parámetro opcional no lo hemos indicado y se rellenará con el valor por defecto que indicamos en la definición.

Lo podemos hacer así porque el parámetro opcional es el último de la lista de parámetros. Cuando el parámetro opcional no es el último la llamada tiene que ser diferente, tenemos que nombrar los parámetros en la llamada, al menos a partir del parámetro opcional.

DROP PROC VerUsuariosPoblacion3;

GO

CREATE PROCEDURE VerUsuariosPoblacion3 @a CHAR(2),@pob CHAR(30)='Madrid',@pro CHAR(30)

AS

SELECT * FROM usuarios WHERE poblacion=@pob AND provincia = @pro;

GO

EXEC VerUsuariosPoblacion3  a,@pro='Madrid'

En este caso el parámetro opcional es el segundo de la lista de parámetros, cuando hacemos la llamada no podemos hacer como en otros lenguajes de dejar un hueco:

EXEC VerUsuariosPoblacion3  a, ,'Madrid'

Da error. Esta forma da error, debemos utilizar la palabra DEFAULT o indicar el nombre de todos los parámetros que van detrás del opcional.

EXEC VerUsuariosPoblacion3  a,DEFAULT,'Madrid'

Unidad 9. Programación en TRANSACT SQL (IV)

Con parámetros de salida

Un procedimiento almacenado puede también devolver resultados, definiendo el paramétro como OUTPUT o bien utilizando la instrucción RETURN que veremos en el siguiente apartado.

161

Page 162: Curso de SQL Server.docx

Para poder recoger el valor devuelto por el procedimiento, en la llamada se tiene que indicar una variable donde guardar ese valor.

Ejemplo:Definimos el procedimiento ultimo_contrato que nos devuelte la fecha en que se firmó el último contrato en una determinada oficina. El procedimiento tendrá pues dos parámetros, uno de entrada para indicar el número de la oficina a considerar y uno de salida que devolverá la fecha del contrato más reciente de entre los empleados de esa oficina.

USE Gestion

GO

CREATE PROC ultimo_contrato @ofi INT, @fecha DATETIME OUTPUT

AS

SELECT @fecha=(SELECT MAX(contrato) FROM empleados WHERE oficina=@ofi)

GO

Con @fecha DATETIME OUTPUT indicamos que el parámetro @fecha es de salida, el proceso que realice la llamada podrá recoger su valor después de ejecutar el procedimiento.

En la llamada, para los parámetros de salida, en vez de indicar un valor de entrada se indica un nombre de variable, variable que recogerá el valor devuelto por el procedimiento sin olvidar la palabra OUTPUT:

DECLARE @ultima AS DATETIME;

EXEC ultimo_contrato 12,@ultima OUTPUT;

PRINT @ultima;

RETURN

RETURN ordena salir incondicionalmente de una consulta o procedimiento, se puede utilizar en cualquier punto para salir del procedimiento y las instrucciones que siguen a RETURN no se ejecutan. Además los procedimientos almacenados pueden devolver un valor entero mediante esta orden.

RETURN [expresion_entera]

Expresion_entera es el valor entero que se devuelve.

A menos que se especifique lo contrario, todos los procedimientos almacenados del sistema devuelven el valor 0. Esto indica que son correctos y un valor distinto de cero indica que se ha producido un error.

Cuando se utiliza con un procedimiento almacenado, RETURN no puede devolver un valor NULL. Si un procedimiento intenta devolver un valor NULL (por ejemplo, al utilizar RETURN @var si @var es NULL), se genera un mensaje de advertencia y se devuelve el valor 0.

Si queremos recoger el valor de estado devuelto por el procedimiento la llamada debe ser distinta, y seguir el siguiente modelo:

162

Page 163: Curso de SQL Server.docx

EXECUTE @variable_donde_recogemos_estado = nombre_procedimiento @par, ...

Con el procedimiento del punto anterior no se puede utilizar esta forma de devolver un resultado porque lo que se devuelve es una fecha, no es un valor entero, pero si quisiéramos definir un procedimiento que nos devuelva el número de empleados de una oficina podríamos hacerlo de dos formas:

De la forma normal con un parámetro de salida:

USE Gestion

GO

CREATE PROC trabajadores @ofi INT, @num INT OUTPUT

AS

SELECT @num=(SELECT COUNT(*) FROM empleados WHERE oficina=@ofi)

GO

Para obtener en la variable @var el resultado devuelto por el procedimiento la llamada sería:

DECLARE @var INT;

EXEC trabajadores 12, @var OUTPUT

Utilizando return en vez de un parámetro de salida:

CREATE PROC trabajadores2 @ofi INT

AS

RETURN (SELECT COUNT(*) FROM empleados WHERE oficina=@ofi)

GO

Para obtener en la variable @var el resultado devuelto por el procedimiento la llamada sería:

DECLARE @var INT;

EXEC @var= trabajadores2 12

PRINT @var

Nos visualiza el número de trabajadores de la oficina número 12.

Unidad 9. Programación en TRANSACT SQL (V)

9.5. Instrucciones de control de flujo

163

Page 164: Curso de SQL Server.docx

Disponemos de diferentes elementos para el control de flujo, como pueden ser RETURN, IF... ELSE, WHILE, BREAK, CONTINUE, GO TO, EXECUTE, etc. En los siguientes apartados aprenderemos cómo utilizarlos.

9.6. IF…   ELSE

Proporciona una ejecución condicional, permite ejecutar o no ciertas instrucciones dependiendo de si se cumple o no una determinada condición.

IF condicion

     { sentencia_sql | bloque_sql }

[ ELSE

     { sentencia_sql | bloque_sql } ]

Si la condición se cumple (da como resultado TRUE) se ejecuta la instrucción SQL o bloque de instrucciones que aparecen a continuación de la condición, si la condición no se cumple se ejecutan las sentencias que aparecen después de la palabra ELSE. El bloque ELSE es opcional.

Ejemplo: Si nos queremos guardar en una consulta todos los ejemplos para probarlos en cualquier momento, es conveniente antes de los  CREATE PROCEDURE colocar un DROP PROCEDURE para que la instrucción CREATE no dé error si el procedimiento ya existe, pero la primera vez la instrucción DROP PROC nos dará error porque el procedimiento todavía no existe, así que lo mejor es ejecutar el DROP sólo si el procedimiento existe, utilizando la función object_id(‘nombre_de_objeto’,’tipo de objeto’) que nos devuelve el id del objeto y NULL si el objeto no existe.

IF object_id('trabajadores', 'P') IS NOT NULL

      DROP PROCEDURE trabajadores;

GO

CREATE PROC trabajadores….

Otro ejemplo. Ahora queremos el procedimiento y si no existe se mandará un mensaje "el procedimiento no existe":

IF object_id('trabajadores', 'P') IS NOT NULL

BEGIN

       PRINT 'Borramos el procedimiento'

       DROP PROC trabajadores

END

ELSE PRINT 'El procedimiento ya existe'

Cuando queremos definir un bloque de instrucciones utilizamos los delimitadores BEGIN..END

164

Page 165: Curso de SQL Server.docx

Se pueden anidar varias sentencias IF hasta el límite que permita la memoria.

9.7. WHILE – BREAK- CONTINUE

Esta instrucción permite definir un bucle que repite una sentencia o bloque de sentencias mientras se cumpla una determinada condición.

WHILE condicion

     { sentencia_sql | bloque_sql }

     | BREAK 

     | CONTINUE

Podemos anidar bucles, colocar un bucle WHILE dentro de otroBREAK Produce la salida del bucle WHILE más interno. La instrucción BREAK interna sale al siguiente bucle más externo. Todas las instrucciones que se encuentren después del final del bucle interno se ejecutan primero y después se reinicia el siguiente bucle más externo.CONTINUE Hace que se reinicie el bucle WHILE y omite las instrucciones que haya después de la palabra clave CONTINUE.

Por ejemplo, tenemos los siguientes bucles anidados:

WHILE condicion1                -- Bucle 1

Instrucciones_1_1

WHILE condicion2              -- Bucle 2

       Intrucciones2_1

       If condicion3 BREAK

       Instrucciones2_2

       IF condicion4 CONTINUE

       Instrucciones2_3

Instrucciones1_2

Las instrucciones se ejecutarían en este orden:

Preguntamos por condicion1:

  Si condicion1 se cumple:

           Se ejecuta el bloque Instrucciones1_1

           Preguntamos por condicon2:

           Si se cumple condicion2:

                     Se ejecuta el bloque de instrucciones Instrucciones_2_1.

                     Si condición3 se cumple:

                              Salimos del bucle 2,

165

Page 166: Curso de SQL Server.docx

                              Se ejecuta el bloque Instrucciones1_2

                              Y se vuelve a preguntar por condicion1.

                     Si condición3 no se cumple:

                              Se ejecuta el bloque instrucciones2_2

                              Si se cumple condicion4:

                                       Saltamos el bloque Instrucciones2_3

                                       Y se vuelve a preguntar por condicion2

                              Si no se cumple condicion4:

                                       Se ejecuta el bloque Instrucciones2_3

                                       Y se vuelve a preguntar por condicion2

           Si condicion2 no se cumple:

                     Se ejecuta el bloque Instrucciones 1_2

                     Se vuelve a preguntar por condicion1

  Si condicion1 no se cumple:

           Hemos terminado

Unidad 9. Programación en TRANSACT SQL (VI)

9.8. WAITFOR

Bloquea la ejecución de un lote, un procedimiento almacenado o una transacción hasta alcanzar la hora o el intervalo de tiempo especificado, o hasta que una instrucción especificada modifique o devuelva al menos una fila. Nosotros estudiaremos los dos primeros casos.

WAITFOR {DELAY 'tiempo_a_transcurrir'

        |TIME 'fechaHora_de_ejecucion'}

DELAY permite indicar un período de tiempo especificado (hasta un máximo de 24 horas) que debe transcurrir antes de la ejecución de un lote, un procedimiento almacenado o una transacción.

'tiempo_a_transcurrir' Es el período de tiempo que hay que esperar, se puede especificar en uno de los formatos aceptados para el tipo de datos datetime o como una variable local. No se pueden especificar fechas; por lo tanto, no se permite la parte de fecha del valor datetime.

TIME permite indicar la hora específica a la que se ejecuta el lote, el procedimiento almacenado o la transacción.

'fechaHora_de_ejecucion' Es la hora a la que termina la instrucción WAITFOR por tanto a la que empieza la ejecución de las instrucciones siguientes a WAITFOR. Se puede

166

Page 167: Curso de SQL Server.docx

especificar en uno de los formatos aceptados para el tipo de datos datetime o como una variable local. No se pueden especificar fechas; por lo tanto, no se permite la parte de fecha del valor datetime.

Cada instrucción WAITFOR tiene un subproceso asociado. Si se especifica un gran número de instrucciones WAITFOR en el mismo servidor, se pueden acumular muchos subprocesos a la espera de que se ejecuten estas instrucciones. SQL Server supervisa el número de subprocesos asociados con las instrucciones WAITFOR y selecciona aleatoriamente algunos de estos subprocesos para salir si el servidor empieza a experimentar la falta de subprocesos.

Ejemplo:

PRINT CONVERT(CHAR(8),Getdate(),108);

WAITFOR DELAY '00:00:03'

PRINT CONVERT(CHAR(8),Getdate(), 108);

WAITFOR DELAY '00:03'

PRINT CONVERT(CHAR(8),Getdate(), 108);

Visualiza la hora actual, espera 3 segundos y vuelve a visualizar la hora actual, después espera 3 minutos y vuelve a visualizar la hora actual. Se ha utilizado la función CONVERT con el estilo 108 para que aparezca sólo la hora y con segundos.

9.9. GOTO

Altera el flujo de ejecución y lo dirige a una etiqueta. Las etiquetas se indican mediante un nombre seguido del carácter:

GOTO NombreEtiqueta

Ejemplo:

IF Condicion GOTO etiq

----

Etiq:

----

----

Es una instrucción a evitar porque puede llevar a redactar programas no estructurados.

9.10. TRY... CATCH

Definición

La estructura TRY…CATCH implementa un mecanismo de control de errores para Transact-SQL, permite incluir un grupo de instrucciones Transact-SQL en un bloque TRY. Si se produce un error en el bloque TRY, el control se transfiere a otro grupo de instrucciones que está incluido en un bloque CATCH.

167

Page 168: Curso de SQL Server.docx

BEGIN TRY

     {sentencia_sql|bloque_sql}

END TRY

BEGIN CATCH

      [{sentencia_sql|bloque_sql}]

END CATCH [ ; ]

Una construcción TRY…CATCH no puede abarcar varios bloques de instrucciones Transact-SQL (varios bloques BEGIN…END de instrucciones Transact-SQL) ni  una construcción IF…ELSE.

Si no hay errores en el código incluido en un bloque TRY, cuando la última instrucción de este bloque ha terminado de ejecutarse, el control se transfiere a la instrucción inmediatamente posterior a la instrucción END CATCH asociada. Si hay un error en el código incluido en el bloque TRY, el control se transfiere a la primera instrucción del bloque CATCH asociado. Si la instrucción END CATCH es la última instrucción de un procedimiento almacenado o desencadenador, el control se devuelve a la instrucción que llamó al procedimiento almacenado o activó el desencadenador.

Las construcciones TRY…CATCH se pueden anidar.

Las construcciones TRY…CATCH capturan los errores no controlados de los procedimientos almacenados o desencadenadores ejecutados por el código del bloque TRY. Alternativamente, los procedimientos almacenados o desencadenadores pueden contener sus propias construcciones TRY…CATCH para controlar los errores generados por su código. Por ejemplo, cuando un bloque TRY ejecuta un procedimiento almacenado y se produce un error en éste, el error se puede controlar de las formas siguientes:

Si el procedimiento almacenado no contiene su propia construcción TRY…CATCH, el error devuelve el control al bloque CATCH asociado al bloque TRY que contiene la instrucción EXECUTE.

Si el procedimiento almacenado contiene una construcción TRY…CATCH, el error transfiere el control al bloque CATCH del procedimiento almacenado. Cuando finaliza el código del bloque CATCH, el control se devuelve a la instrucción inmediatamente posterior a la instrucción EXECUTE que llamó al procedimiento almacenado.

No se pueden utilizar instrucciones GOTO para entrar en un bloque TRY o CATCH pero se puede utilizar para saltar a una etiqueta dentro del mismo bloque TRY o CATCH, o bien para salir de un bloque TRY o CATCH.

TRY…CATCH no se puede utilizar en una función definida por el usuario.

Unidad 9. Programación en TRANSACT SQL (VII)

Recuperar información sobre errores

En el ámbito de un bloque CATCH, se pueden utilizar las siguientes funciones del sistema para obtener información acerca del error que provocó la ejecución del bloque CATCH:

ERROR_NUMBER() devuelve el número del error.

168

Page 169: Curso de SQL Server.docx

ERROR_SEVERITY() devuelve la gravedad.

ERROR_STATE() devuelve el número de estado del error.

ERROR_PROCEDURE() devuelve el nombre del procedimiento almacenado o desencadenador donde se produjo el error.

ERROR_LINE() devuelve el número de línea de la rutina que provocó el error.

ERROR_MESSAGE() devuelve el texto completo del mensaje de error. Este texto incluye los valores suministrados para los parámetros reemplazables, como longitudes, nombres de objetos u horas.

Estas funciones devuelven NULL si se las llama desde fuera del ámbito del bloque CATCH. Con ellas se puede recuperar información sobre los errores desde cualquier lugar dentro del ámbito del bloque CATCH. Por ejemplo, en la siguiente secuencia de comandos se muestra un procedimiento almacenado que contiene funciones de control de errores. Se llama al procedimiento almacenado en el bloque CATCH de una construcción TRY…CATCH y se devuelve información sobre el error.

Ejemplo, vamos a definir un procedimiento para calcular el precio unitario a partir de un importe y una cantidad:

-- Verificamos que el procedimiento que vamos a crear no existe.

IF OBJECT_ID ('CalculaPrecio', 'P' ) IS NOT NULL

    DROP PROCEDURE CalculaPrecio;

GO

-- Creamos el procedimiento

CREATE PROCEDURE CalculaPrecio @importe MONEY,@cant INT,@precio MONEY OUTPUT

AS

BEGIN TRY

    SELECT @precio=@importe/@cant;

END TRY

BEGIN CATCH

IF ERROR_NUMBER() = 8134 SELECT @precio=0

ELSE SELECT ERROR_NUMBER() as ErrorNumero,ERROR_MESSAGE() as MensajeDeError;

END CATCH;

GO

-- Lo utilizamos

DECLARE @resultado MONEY

EXEC CalculaPrecio 1000, 0, @resultado OUTPUT

SELECT 'resul', @resultado

Si al llamar al procedimiento le pasamos una cantidad igual a cero, la división provocará un error, se pasará el control al bloque CATCH, en este bloque se evalúa si el error

169

Page 170: Curso de SQL Server.docx

corresponde al error de división por cero (8134), si es así el procedimiento devuelve un precio igual a cero, sino se envía un mensaje para avisar del error.

Errores controlados por TRY…CATCH

TRY…CATCH  detecta todos los errores de ejecución que tienen una gravedad mayor de 10 y que no cierran la conexión de la base de datos.

TRY…CATCH no detecta:

Advertencias o mensajes informativos que tienen gravedad 10 o inferior.

Errores que tienen gravedad 20 o superior que detienen el procesamiento de las tareas de SQL Server Database Engine en la sesión. Si se produce un error con una gravedad 20 o superior y no se interrumpe la conexión con la base de datos, TRY…CATCH controlará el error.

Atenciones, como solicitudes de interrupción de clientes o conexiones de cliente interrumpidas.

Cuando el administrador del sistema finaliza la sesión mediante la instrucción KILL.

Un bloque CATCH no controla los siguientes tipos de errores cuando se producen en el mismo nivel de ejecución que la construcción TRY…CATCH:

Errores de compilación, como errores de sintaxis, que impiden la ejecución de un lote.

Errores que se producen durante la recompilación de instrucciones, como errores de resolución de nombres de objeto que se producen después de la compilación debido a una resolución de nombres diferida.

Estos errores se devuelven al nivel de ejecución del lote, procedimiento almacenado o desencadenador. En el ejemplo siguiente se muestra cómo la construcción TRY…CATCH no captura un error de resolución de nombre de objeto generado por una instrucción SELECT, sino que es el bloque CATCH el que lo captura cuando la misma instrucción SELECT se ejecuta dentro de un procedimiento almacenado (a un nivel inferior).

USE Gestion;

GO

BEGIN TRY

    SELECT * FROM TablaQueNoExiste;

END TRY

BEGIN CATCH

    SELECT ERROR_NUMBER() as ErrorNumero,ERROR_MESSAGE() as MensajeDeError;

END CATCH

Intentamos ejecutar una SELECT de una tabla que no existe en la base de datos. El error no se captura y el control se transfiere fuera de la construcción TRY…CATCH, al siguiente nivel superior, en este caso salta el mensaje de error del sistema.Al ejecutar la misma instrucción SELECT dentro de un procedimiento almacenado, el error se producirá en un nivel inferior al bloque TRY y la construcción TRY…CATCH controlará el error.

170

Page 171: Curso de SQL Server.docx

IF OBJECT_ID ('TablaInexistente','P') IS NOT NULL

    DROP PROCEDURE TablaInexistente;

GO

-- Creamos el procedimiento.

CREATE PROCEDURE TablaInexistente

AS

    SELECT * FROM TablaQueNoExiste;

GO

-- Utilizamos el procedimiento

BEGIN TRY

    EXECUTE TablaInexistente

END TRY

BEGIN CATCH

    SELECT ERROR_NUMBER() as ErrorNumero,ERROR_MESSAGE() as MensajeDeError;

END CATCH;

En este caso como el error se produce dentro del procedimiento, el control del error se devuelve al nivel superior (el que ha realizado el EXECUTE) por lo que es capturado por el TRY y entra en el bloque CATCH, en vez de que salte el mensaje de error del sistema saldrá el nuestro.

Unidad 9. Programación en TRANSACT SQL (VIII)

9.11. Desencadenadores o TRIGGERS

Un desencadenador (o Trigger) es una clase especial de procedimiento almacenado que se ejecuta automáticamente cuando se produce un evento en el servidor de bases de datos. SQL Server permite crear varios desencadenadores para una instrucción específica. Según el tipo de evento que los desencadena se clasifican en:

Desencadenadores DML

  Desencadenadores DDL

  Desencadenadores LOGON

Los desencadenadores DML se ejecutan cuando un usuario intenta modificar datos mediante un evento de lenguaje de manipulación de datos (DML). Los eventos DML son instrucciones INSERT, UPDATE o DELETE de una tabla o vista.

Los desencadenadores DDL se ejecutan en respuesta a una variedad de eventos de lenguaje de definición de datos (DDL). Estos eventos corresponden principalmente a

171

Page 172: Curso de SQL Server.docx

instrucciones CREATE, ALTER y DROP de Transact-SQL, y a determinados procedimientos almacenados del sistema que ejecutan operaciones de tipo DDL.

Los desencadenadores logon se activan en respuesta al evento LOGON que se genera cuando se establece la sesión de un usuario.

Nosotros limitaremos nuestro estudio a los desencadenadores DML.

9.12. CREATE TRIGGER

Esta instrucción nos permite definir un trigger:

CREATE TRIGGER [NombreEsquema.]NombreTrigger

ON {tabla | vista } [,...n] ]

{FOR|AFTER|INSTEAD OF} {[INSERT][,][UPDATE][,][DELETE]}

AS sentencia_sql  [;] [,...n ]

NombreEsquema es el nombre del esquema al que pertenece el desencadenador DML. Los desencadenadores DML se limitan al esquema de la tabla o vista en la que se crearon.NombreTrigger es el nombre que le queremos dar al desencadenador. No puede comenzar con los símbolos # o ##.

Tabla | vista es el nombre de la tabla o vista en la que se ejecuta el desencadenador. Sólo se puede hacer referencia a una vista mediante un desencadenador INSTEAD OF.

No es posible definir desencadenadores DML en tablas temporales locales o globales.DELETE  INSERT UPDATE Especifica las instrucciones de modificación de datos que activan el desencadenador cuando se intenta ejecutarlas en esta tabla o vista. Se debe especificar al menos una opción. En la definición del desencadenador se permite cualquier combinación de estas opciones, en cualquier orden.

AFTER indica que el desencadenador sólo se activa cuando todas las operaciones especificadas en la instrucción SQL desencadenadora se han ejecutado correctamente.

Además, todas las acciones referenciales en cascada y las comprobaciones de restricciones deben ser correctas para que este desencadenador se ejecute.

AFTER es el valor predeterminado cuando sólo se especifica la palabra clave FOR.

Los desencadenadores AFTER no se pueden definir en las vistas.

INSTEAD OF indica que se ejecuta el desencadenador en vez de la instrucción SQL desencadenadora, por lo que se suplantan las acciones de las instrucciones desencadenadoras. Como máximo, se puede definir un desencadenador INSTEAD OF por cada instrucción INSERT, UPDATE o DELETE en cada tabla o vista. No obstante, en las vistas es posible definir otras vistas que tengan su propio desencadenador INSTEAD OF.

Los desencadenadores INSTEAD OF no se pueden utilizar en vistas actualizables que usan WITH CHECK OPTION. Los desencadenadores INSTEAD OF DELETE/UPDATE  no se permiten en tablas que tengan una clave ajena definida con ON DELETE/UPDATE CASCADE.

CREATE TRIGGER debe ser la primera instrucción en el proceso por lotes.Un desencadenador se crea solamente en la base de datos actual; sin embargo, puede hacer referencia a objetos que están fuera de la base de datos actual.

172

Page 173: Curso de SQL Server.docx

Si se especifica el nombre del esquema del desencadenador hay que calificar también el nombre de la tabla o vista.

En un desencadenador se puede especificar cualquier instrucción SET. La opción SET seleccionada permanece en efecto durante la ejecución del desencadenador y, después, vuelve automáticamente a su configuración anterior.

Un desencadenador está diseñado para comprobar o cambiar los datos en base a una instrucción de modificación o definición de datos; no debe devolver datos al usuario por lo que se aconseja no incluir en un desencadenador instrucciones SELECT que devuelven resultados ni las instrucciones que realizan una asignación variable. Si es preciso que existan asignaciones de variable en un desencadenador, tenemos que utilizar la instrucción SET NOCOUNT al principio del mismo para impedir la devolución de cualquier conjunto de resultados.

Los desencadenadores DML usan las tablas lógicas  deleted e inserted. Son de estructura similar a la tabla en que se define el desencadenador, es decir, la tabla en que se intenta la acción del usuario. Las tablas deleted e inserted guardan los valores antiguos o nuevos de las filas que la acción del usuario puede cambiar. Si un desencadenador INSTEAD OF definido en una tabla ejecuta una instrucción en la tabla que normalmente volvería a activarlo, al desencadenador no se lo llama de forma recursiva. En su lugar, la instrucción se procesa como si la tabla no tuviera un desencadenador INSTEAD OF e inicia la cadena de operaciones de restricción y ejecuciones de desencadenadores AFTER. Por ejemplo, si para una tabla se define un desencadenador como INSTEAD OF INSERT, y éste ejecuta una instrucción INSERT en la misma tabla, la instrucción INSERT ejecutada por el desencadenador INSTEAD OF no vuelve a llamar al desencadenador. La instrucción INSERT ejecutada por el desencadenador inicia el proceso que realiza las acciones de restricción y activa cualquier desencadenador AFTER INSERT definido para la tabla.

Si un desencadenador INSTEAD OF definido en una vista ejecuta una instrucción en la vista que normalmente volvería a activarlo, no se llamará el desencadenador de forma recursiva. En su lugar, la instrucción se resuelve a modo de modificaciones en las tablas base subyacentes de la vista. En este caso, la definición de la vista debe cumplir todas las restricciones para una vista actualizable.

Aunque una instrucción TRUNCATE TABLE es en realidad un desencadenador DELETE, no puede activar un desencadenador porque la operación no registra las eliminaciones de fila individuales.

Las siguientes instrucciones Transact-SQL no están permitidas en un desencadenador DML:ALTER DATABASE       CREATE DATABASE            DROP DATABASE

Además, las siguientes instrucciones Transact-SQL no se permiten en el cuerpo de un desencadenador DML cuando éste se utiliza en la tabla o vista que es objeto de la acción desencadenadora:

CREATE INDEX          ALTER INDEX          DROP INDEX           DROP TABLE

ALTER TABLE cuando se utiliza para hacer lo siguiente:

Agregar, modificar o quitar columnas.

Cambiar particiones.

Agregar o quitar restricciones de tipo PRIMARY KEY o UNIQUE.

Ejemplo:

173

Page 174: Curso de SQL Server.docx

USE Gestion8

GO

CREATE TRIGGER ActualizaVentasEmpleados

ON pedidos FOR INSERT

AS

UPDATE empleados SET ventas=ventas+inserted.importe

FROM empleados, inserted

WHERE numemp=inserted.rep;

GO

Unidad 9. Programación en TRANSACT SQL (IX)

Cuando se INSERTe un pedido, entrará en funcionamiento el trigger ActualizaVentasEmpleado y se ejecutarán las instrucciones que aparecen después de AS, en este caso actualizará (UPDATE)  la tabla empleados sumará a las ventas del empleado (ventas) el importe del pedido insertado (inserted.importe), y sólo actualizará el empleado cuyo numemp coincida con el campo rep del pedido insertado (WHERE numemp=inserted.rep).

-- Ahora comprobamos que funciona

SELECT * FROM empleados WHERE numemp=108;

INSERT INTO pedidos (numpedido,fechapedido,rep,clie,cant,importe,fab,producto)

             VALUES (123456789,getdate(),108,2103,10,100,'Aci',41001)

SELECT * FROM empleados WHERE numemp=108;

Vemos que al insertar un pedido de 100 € del empleado 108, sus ventas han aumentado en 100€.

ALTER TRIGGER

Permite modificar la definición del desencadenador, no permite cambiar su nombre, para cambiar el nombre de un desencadenador hay que eliminarlo (DROP TRIGGER) y volver a crearlo (CREATE TRIGGER).

ALTER TRIGGER [NombreEsquema.]NombreTrigger

ON {tabla|vista}

{FOR|AFTER|INSTEAD OF} {[INSERT][,][UPDATE][,][DELETE]} [WITH APPEND]

AS sentencia_sql  [;] [,...n ]

La sintaxis es similar a la instrucción CREATE TRIGGER.

Ejemplo:

174

Page 175: Curso de SQL Server.docx

ALTER TRIGGER ActualizaVentasEmpleados

ON pedidos FOR INSERT

AS

UPDATE empleados SET ventas=ventas+inserted.importe

FROM empleados, inserted

WHERE numemp=inserted.rep AND inserted.importe IS NOT NULL;

Hemos modificado el desencadenador para que si el importe del pedido es nulo, no haga nada, no actualice con un valor nulo.

Realiza el siguiente Ejercicio Triggers para practicar la creación de desencadenadores.

9.13. DISABLE TRIGGER

En ocasiones puede ser útil inhabilitar temporalmente un desencadenador sin que por ello suponga eliminarlo, para estos casos podemos utilizar la sentencia DISABLE TRIGGER.

DISABLE TRIGGER {[NombreEsquema.]NombreTrigger [,...n] | ALL }

ON {NombreTablaVista | DATABASE | ALL SERVER} [;]

Ejemplo:

DISABLE TRIGGER ActualizaVentasEmpleado ON pedidos;

Deshabilita el desencadenador que hemos creado anteriormente, si después de ejecutar esta sentencia se introduce un nuevo pedido, el empleado correspondiente no se actualizará.Lo podemos comprobar con:

SELECT * FROM empleados WHERE numemp=108;

INSERT INTO pedidos (numpedido,fechapedido,rep,clie,cant,importe,fab,producto)

                   VALUES (123456791,getdate(),108,2103,10,300,'Aci',41001)

SELECT * FROM empleados WHERE numemp=108;

DISABLE TRIGGER ALL ON pedidos;

Deshabilita todos los desencadenadores asociados a la tabla pedidos.

DISABLE TRIGGER ALL ON DATABASE;

Deshabilita todos los desencadenadores definidos en la base de datos actual.

175

Page 176: Curso de SQL Server.docx

DISABLE TRIGGER ALL ON ALL SERVER;

Deshabilita todos los desencadenadores definidos en el servidor.

Unidad 9. Programación en TRANSACT SQL (X)

9.14. ENABLE TRIGGER

Con esta instrucción volvemos a habilitar los desencadenadores desactivados por la instrucción anterior.

ENABLE TRIGGER {[NombreEsquema.]NombreTrigger [,...n] | ALL }

ON {NombreTablaVista | DATABASE | ALL SERVER} [ ; ]

Funciona de la misma manera que DISABLE TRIGGER pero habilita en vez de deshabilitar.

Con este ejemplo lo podemos comprobar:

ENABLE TRIGGER ActualizaVentasEmpleados ON pedidos;

SELECT * FROM empleados WHERE numemp=108;

INSERT INTO pedidos (numpedido,fechapedido,rep,clie,cant,importe,fab,producto)

     VALUES (123456792,getdate(),108,2103,10,400,'Aci',41001)

SELECT * FROM empleados WHERE numemp=108;

9.15. DROP TRIGGER

Para eliminar un desencadenador tenemos la instrucción DROP TRIGGER elimina la definición del desencadenador.

DROP TRIGGER NombreEsquema.NombreTrigger [,...n] [;]

Ejemplo:

DROP TRIGGER ActualizaVentasEmpleados

Elimina el desencadenador ActualizaVentasEmpleados.

176