• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Antología de taller de base de datos 2003
 

Antología de taller de base de datos 2003

on

  • 1,847 views

 

Statistics

Views

Total Views
1,847
Views on SlideShare
1,847
Embed Views
0

Actions

Likes
2
Downloads
54
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Microsoft Word

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Antología de taller de base de datos 2003 Antología de taller de base de datos 2003 Document Transcript

    • UNIDAD I Gestor de bases de datos .1.1 Características del gestor.A lo largo de estos años Microsoft ha ido recogiendo y estudiando las diferentes solicitudes ysugerencias de administradores y desarrolladores de todo el mundo. Muchas de estas sugerenciassolicitaban mejoras en el diseño y el modo de gestionar y administrar las tareas de SQL Server.Microsoft se esforzó en tratar de cumplir con todas estas sugerencias y rediseño desde su servidorde base de datos. Como fruto de estas mejoras y otras muchas de rendimiento y estabilidad surgióSQL Server 2005.Para usuarios veteranos y nuevos en administración de bases de datos con SQL Server, sequedarán sorprendidos en comprobar que con desde una única herramienta tenemos acceso a lagestión de casi todas las tareas de SQL Server 2005. Esta herramienta que engloba todas lasfunciones, es SQL Server 2005 Management Studio.Para usuarios con experiencia ya, pueden ver que las antiguas herramientas como AnalysisManager, Administrador Corporativo y el Analizador de Consultas, están todas compactadas enSQL Server 2005 Management Studio.Si además eres desarrollador de software con .net, el entorno te resultará muy familiar al que senos presenta en Visual Studio 2005.Como es lógico la mayor parte del tiempo que dedicaremos como administradores odesarrolladores de bases de datos estará invertido en esta herramienta, por lo tanto debemosfamiliarizarnos al máximo a esta novedosa y potente herramienta.1.2 Herramientas.SQL Server Management StudioArrancamos la aplicación desde el menú de inicio tal y como vimos en el primer capítulo. Loprimero que haremos para acceder a la herramienta es conectarnos al servidor, para esotendremos la conexión que hemos configurado durante la instalación del producto, así queseleccionamos esos parámetros: "Autenticación de Windows" y pulsamos en conectar:
    • Al conectarnos se nos presenta la primera pantalla de nuestra herramienta, y observamos quetenemos la pantalla dividida en dos ventanas: • Explorador de objetos. • Resumen.
    • Hay una tercera ventana que resulta muy útil y que por defecto es posible que SQL Server nomuestre: Servidores registrados.Para mostrar esta ventana vamos al menú "Ver" y seleccionamos "Servidores registrados", de estemodo nuestra pantalla queda dividida en tres ventanas:
    • Si has desarrollado programas con Visual Studio, este entorno te será muy familiar. Visual Studiose ha convertido en el entorno de programación preferido por los desarrolladores. Parte de esteéxito se debe al diseño del entorno de esta herramienta. Ya que permite un grado depersonalización muy alto, y el desarrollador puede disponer y utilizar el espacio al máximo paratener un acceso más rápido y cómodo a sus herramientas más utilizadas.Al igual que sucede con Visual Studio, con SQL Server Management Studio podemos personalizarsu presentación, y acceder rápidamente a nuestras herramientas preferidas. Para aumentar
    • nuestro espacio de trabajo sin influir en el funcionamiento original de Management Studiotenemos las siguientes posibilidades: • Cada una de las ventanas puede cambiar a cualquier localización. • Si tenemos la suerte de trabajar con monitores compartidos, tenemos la posibilidad de desacoplar la mayoría de ventanas y arrastrarla a cualquier posición. • Las ventanas pueden ser ocultadas automáticamente, cuando una ventana permanece oculta se convierte en una pestaña en el borde de la ventana principal. Para mostrarlas de nuevo basta con colocar el puntero del ratón sobre esta ventana para que se muestre de nuevo. Para activar y desactivar esta posibilidad tenemos un botón representado por una chincheta. Otro modo de utilizar esta posibilidad es mediante el menú ventana->Ocultar automáticamente:Para activar y desactivar la posibilidad de ocultar automáticamente tenemos el botón chincheta:Botón Descripción Activada la opción "Ocultar Automáticamente". La ventana permanece fija, tenemos desactivada la opción "Ocultar automáticamente". • Tenemos la posibilidad de configurar el entorno para que nos muestre la información como fichas. Cada elemento aparece como una ficha el la localización que se encuentre, o bien como una interfaz de múltiples documentos, conocida esta opción como MDI de modo que cada documento está en su propia ventana. Para optar a esta configuración tenemos el menú Herramientas->Opciones->Entorno->General y marcar la opción Organización por fichas o Entorno MDI:
    • Los diferentes componentes de Management Studio están configurados para trabajar como untodo. Todas las herramientas están entrelazadas, lo que hace de Management Studio unaherramienta muy eficaz.Otra opción que debemos comentar es que Management Studio no tiene porque ser instalado enel mismo servidor donde estamos explotando nuestra base de datos. De hecho el modo máscomún de trabajar es tener SQL Server 2005 instalado en el servidor para explotar la base dedatos, y en un equipo a parte y personal del administrador tener instalado Management Studio,de modo que el administrador pueda trabajar con la base de datos sin la necesidad de trabajar enel servidor. Además este método de trabajo es aún más eficaz, ya que desde Management Studiopodemos estar conectados a varios servidores y administrar varias bases de datos instaladas endiferentes servidores y todo esto desde el ordenador personal del administrador.Servidores registrados.Hemos visto en el anterior capítulo que la ventana que nos presenta la información relativa a losServidores registrados puede permanecer oculta por defecto.
    • Desde esta ventana podemos organizar los servidores "favoritos" a los que accedemos con mayorfrecuencia. Entra otras opciones tenemos la posibilidad de crear grupos de servidores para facilitarla búsqueda de uno de ellos, en caso de que trabajemos con muchos servidores a la vez.En el caso de SQL Server 2005 Express Edition tenemos limitados los tipos de servidores al motorde base de datos que es con el que nos centramos en este curso. En versiones más avanzadas,aparecerían el resto de tipos de servidores que nos ofrecen.Desde esta ventana podemos pinchar con el botón derecho sobre el servidor y seleccionarConectar->Explorador de objetos, y de este modo nos conectaremos con ese servidor en concreto:Una vez que estamos conectados, vemos que el icono del servidor aparece con un triángulo confondo verde que indica que estamos conectados actualmente a ese servidor:
    • Tenemos la posibilidad de añadir un nuevo registro de servidor, para ello pulsamos con el botónderecho en el icono del tipo de servidor del cual queremos crear un nuevo registro. En nuestrocaso sólo tenemos el motor de base de datos, pulsamos con el botón derecho y seleccionamosNuevo->Registro de servidor...Dentro de la ventana de Nuevo registro de servidor tenemos dos pestañas tal y como puedes veren las siguientes figuras:Pestaña General:
    • Pestaña propiedades de conexión:
    • Desde estas ventanas tenemos la posibilidad de configurar las siguientes tareas:Pestaña General: • Modificar el modo de autenticación: Windows o SQL Server • En caso de seleccionar el modo SQL Server de autenticación podemos introducir el nombre de usuario y la contraseña. • Incluir o modificar el nombre del servidor registrado y añadir una descripción si así lo deseamos. La descripción no es obligatoria.Pestaña Propiedades de conexión: • Indicar la base de datos con la que deseamos conectar directamente al conectar con el servidor. • Seleccionar el protocolo de red con el cual conectamos.
    • • Definir el tamaño del paquete de red. • Especificar el tiempo de espera de conexión y ejecución. Se trata del tiempo que transcurrirá para conectar, una vez pasado este tiempo el Management Studio entenderá que ocurre algún problema que no permite la conexión y lanzará un error. • Activar o desactivar el cifrado de la conexión.Para agilizar el proceso de registro de servidores, tenemos la opción de importar y exportar lascaracterísticas de conexión definidas de un servidor a otro, y viceversa. Como es razonable,podremos importar y exportar estos registros siempre y cuando se traten del mismo tipo deservidores. Esta información de registro se almacena en archivos. Para llevar a cabo este proceso,es tan sencillo como pinchar con el botón derecho en un servidor o en un grupo de servidores yseleccionar del menú la opción Importar o Exportar, dependiendo de la tarea que queramosrealizar:En la ventana que se nos muestra seleccionamos el archivo de registro y seleccionamos a queservidor o grupo de servidor queremos aplicarlo, mediante el árbol de servidores:
    • Para eliminar un servidor o un grupo, lo haremos desde el menú que emerge al pulsar con elbotón derecho sobre el servidor a eliminar, nos mostrará un ventana de confirmación para evitarerrores.Para modificar el nombre o las propiedades de conexión de cualquier servidor podemos pulsar conel botón derecho y seleccionar la opción propiedades.Para finalizar vamos a mostrar una tabla con los diferentes iconos que podemos encontrar en losservidores y lo que significan:Icono Descripción No es posible realizar una conexión con el servidor. El servidor está en uso actualmente. El servidor está pausado. El servidor está detenido.
    • Agrupar servidores.Con la versión SQL Server 2000 apareció un nuevo concepto: Grupos de servidores.El objetivo de los grupos de servidores es meramente organizativos. Es una utilidad administrativaque ayuda al desarrollador a ordenar varios servidores por grupos, y no tiene ninguna influenciasobre la actividad y la estructura de nuestros servidores. Físicamente no agrupa, ni conecta losservidores que pertenezcan a un mismo grupo.Con los grupos de servidores se pueden mostrar los servidores con diferentes nombres a susreales. La ventaja de esta característica es que podemos tener nombres reales que sean complejosy utilizar nombres más descriptivos para su administración.Además los grupos de servidores pueden anidarse, es decir, podemos tener un grupo deservidores dentro de otro. Y podemos tener también un servidor en más de un grupo.Imagina que nos encargan administrar una gran empresa dividida en diferentes departamentos:Administración, Recursos Humanos y Producción.Como se trata de una gran empresa, tenemos además oficinas en Madrid y Barcelona. Cadadepartamento tiene su propio de servidor con su correspondiente servidor de base de datos queguarda la información de la actividad realizada por su departamento.En este caso podíamos organizar de varios modos nuestros servidores. El más lógico sería creardos grupos principales a los que llamaremos Madrid y Barcelona.Y a su vez dentro de los grupos Madrid y Barcelona crear otros tres grupos que almacenen losservidores de cada departamento.Vamos a crear este organigrama de servidores con SQL Server 2005:Para crear un nuevo grupo pinchamos con el botón derecho en el lugar donde queremos crear ungrupo y seleccionamos Nuevo->Grupo de servidores, podemos hacerlo en la raíz (sobre nuestromotor de base de datos) o sobre otro grupo de servidores si deseamos anidarlo.
    • Esta operación nos mostrará una ventana donde nos podremos indicar un nombre para el grupode servidores y una breve descripción para el grupo. Además nos muestra un panel con laestructura organizativa de nuestros servidores, como puedes ver en la siguiente figura:Una vez creados los grupos iremos añadiendo los registros de servidores tal y como hemos vistoen capítulos anteriores.Siguiendo estas operaciones, y anidando nuestros grupos finalmente conseguimos el siguienteesquema que nos muestra la ventana de servidores registrados:
    • Explorador de objetosOtra de las ventanas principales que nos muestra Management Studio es el Explorador de Objetos.El explorador de objetos se encuentra conectado a los diferentes tipos de servidores quetenemos. Los elementos que nos ofrece SQL Server 2005 varían en función del tipo de servidor,pero hay características de desarrollo y herramientas de administración comunes para todos.En esta ventana podemos ver una barra de herramientas que nos permite realizar unasdeterminadas tareas. En la siguiente tabla mostramos estos botones con la tarea que tienenasignada:
    • Icono Descripción Realiza una conexión con el servidor Realiza una desconexión del servidor. Detiene un proceso, sólo estará disponible durante la ejecución de uno Actualiza la lista de elementos de la carpeta que tengamos seleccionada. Realiza un filtro o selección de objetos, permanece en gris cuando no es posible filtrar.Conectar a un servidorPulsando en el botón destinado a la conexión con un servidor ( ), nos muestra la pantalla deconexión que ya conocemos:
    • En esta ventana, tenemos que dar el nombre del servidor con el que deseamos conectar, yseleccionar el tipo de autenticación con el que realizaremos la conexión. Si seleccionamosAutenticación de Windows, podremos realizar la conexión, mientras que si elegimos la opciónAutenticación SQL Server, deberemos introducir el nombre de usuario y la contraseña. Esta opcióndependerá del tipo de registro que hayamos definido durante la instalación, o de la modificaciónque hayamos realizado sobre el registro del servidor en sus propiedades.Si pulsamos sobre el botón opciones, se nos abre una nueva ventana que puedes ver en lasiguiente figura:
    • Vemos que tenemos dos pestañas, la primera de ellas "Inicio se sesión" nos muestra la ventana deconexión de la que partimos. Mientras que en la pestaña "Propiedades de conexión" nos muestrala ventana que ves en la anterior figura. Esta ventana ya la conocemos, y la información quepodemos introducir ya la hemos visto en la ventana de propiedades que hemos comentado en elanterior capítulo.Carpetas del explorador de objetos.La información y los elementos que tenemos en el explorador de objetos se organiza en carpetascon estructura de árbol.Cuando expandamos una de estas carpetas, el explorador de objetos recibe información delservidor del contenido de la carpeta para poder mostrarlo. Esta petición sólo se realiza la primeravez que expandimos una carpeta, por lo tanto, si hemos realizado alguna modificación en algúncomponente de alguna lista desde la primera vez que expandimos la carpeta, esta modificación nose mostrará en ella. Para que se muestre esa información "nueva", debemos seleccionar esa
    • carpeta y actualizarla, mediante la opción "actualizar" del menú que se muestra con el botónderecho, o mediante el botón actualizar de la barra de herramientas.Si trabajamos con bases de datos empresariales de gran tamaño, es posible que tengamos en unacarpeta un listado de objetos tan grande que no nos permita trabajar con comodidad. Lo másfrecuenta es que de ese listado, sólo nos interese trabajar con unos pocos en un determinadomomento.Para facilitar esta tarea, tenemos la opción de mostrar sólo aquellos objetos que nos interesa,mediante el botón de filtrado:Hay carpetas que no permiten realizar un filtro, nos situamos en una de las carpetas que lopermitan y pulsamos sobre el botón, para mostrar la ventana de "Configuración de filtro delexplorador de objetos":Desde esta ventana nos permite realizar filtros por el nombre, esquema (no siempre estádisponible) y la fecha de creación, teniendo la opción de elegir el operador de comparación para elfiltro (Es igual a, Contiene y Entre).Pestaña Resumen
    • La tercera ventana que nos muestra Management Studio aparece por defecto con la pestaña"Resumen":Esta pestaña es utilizada por el Explorador de Objetos para mostrar información del objeto quetengamos seleccionado. Como puedes ver, esta pestaña tiene su propia barra de herramientas conlos siguientes botones:Icono Descripción Sube un nivel en el árbol de carpetas. Actualiza el elemento seleccionado. Sincroniza la información del servidor.
    • Filtra el listado, en caso de ser posible. Tipo de vista para mostrar la información: • Lista: Listado de objetos de la carpeta seleccionada. • Detalles: Muestra información por diferentes categorías del objeto seleccionado.El modo de navegación por las carpetas de la pestaña "Resumen" es muy parecido al exploradorde Windows.Carpetas principales.En el explorador de objetos de SQL Server 2005 Express Edition (Versión avanzada) tenemos lassiguientes carpetas principales: • Bases de datos. • Seguridad. • Objetos de servidor . • Réplica. • Administración.En este curso iremos viendo la mayoría de objetos que encierran estas carpetas.
    • Carpeta de bases de datos.En esta carpeta podemos encontrar las bases de datos del sistema y las de usuarios que vayamoscreando nosotros.Dentro de las bases de datos de usuarios podemos encontrar carpetas anidadas agrupadas por losobjetos que contiene:Árbol de Bases de Datos.Base dedatos de Diagramas de bases de datos.usuario. Tablas Vistas. Sinónimos. Programación. • Procedimientos Almacenados. • Funciones. • Desencadenadores de bases de datos.
    • • Ensamblados. • Tipos. • Reglas. • Valores predeterminados. • Usuarios. • Funciones. • Esquemas. Seguridad. • Claves asimétricas. • Certificados. • Claves simétricas.Todos estos objetos puedes verlos al extender una base de datos de usuario. En este casomostramos en la siguiente figuras los nodos principales de la base de datos Northwind:
    • 1.3 Instalación y configuración del entorno operativo.Estructura físicaUna base de datos se almacena en varios ficheros o archivos en disco. Como mínimo tendremosdos ficheros que explicaremos más adelante. Tenemos la posibilidad de almacenar estos ficherosen discos que no estén ni tan siquiera formateados o que no tengan una partición hecha, pero estemétodo no es el más aconsejable. Es más razonable almacenar estos archivos en un disco yaformateado, con formato NTFS.En empresas cuyo volumen de datos es altísimo y el trabajo que se realiza sobre la base de datossoporta una actividad elevada, se almacenan los archivos en grupos de discos denominados RAIDpor hardware. Este método mejora considerablemente el rendimiento, y nos asegura que en casode fallos inesperados no perdamos esa valiosa información.Como es lógico, nosotros para realizar nuestros ejemplos, no vamos a basarnos en esta tipo deestructuras de hardware, lo almacenaremos en nuestro disco duro, aunque veremos comoasegurar nuestros datos mediante planes de mantenimiento con copias de seguridad automáticas.Como hemos mencionado, como mínimo tendremos dos archivos donde almacenar la base dedatos:· Archivo de datos.· Archivo de registro de transacciones.
    • Pero debes saber que tenemos otras posibilidades y podemos utilizar archivos extras para mejorarel rendimiento de nuestra base de datos, podemos usar varios archivos, si pensamos que nuestrabase de datos va a alcanzar un tamaño grande. O si deseamos que nuestros datos se almacenenen diferentes dispositivos de almacenamiento u ordenadores, y de este modo permitir un trabajomás rápido al poder acceder a la información en paralelo.Centrándonos en lo principal:El archivo de datos, o aquellos que añadimos como extras, son los archivos que tendránalmacenada la información, los datos. Pero recuerda que hemos dicho que SQL Server 2005 nospermite también crear en nuestras bases de datos, no sólo información, sino también una serie deobjetos que trabajan con la información. Pues bien, esta serie de objetos también se almacena enel archivo de datos.Por otro lado, tenemos el archivo de registro de transacciones. Este fichero es tan importante comoel anterior. Su importante tarea es garantizar que esa base de datos permanece integra. Gracias aestos archivos de registros (puede haber más de uno), en caso de ser necesario, podremosrecuperar la base de datos, ya que almacena las modificaciones que se producen debido a laactividad o la explotación de la base de datos.Nombres de archivos.El modo de nombrar una base de datos, parte de una base fija, de un nombre principal quegeneralmente entrega el administrador de la base de datos. Una vez que tenemos este nombreprincipal, SQL Server 2005 se encarga de añadir terminaciones y unas determinadas extensiones,a ese nombre principal. El administrador además de seleccionar el nombre principal, puede elegirel destino donde se almacenarán los ficheros que forman la base de datos.Vamos a suponer que estamos en una empresa como administradores, y estamos creando subase de datos. Nosotros como administradores le damos el nombre principal " miEmpresa ". Eseserá el nombre de la base de datos, pero los ficheros donde se almacenará su información y elregistro de transacciones, serán:· Archivo de datos: miEmpresa_Data.MDF· Archivo de registro de transacciones: miEmpresa_Log.LDFEn caso de tener archivos extras, nosotros como administradores también podremos darles sunombre principal, y la extensión que suele utilizarse es .NDFSiguiendo con nuestra tarea de administrador, ahora sería el momento de seleccionar el lugar dealmacenamiento, como ya sabes podemos seleccionar una determinada carpeta o directorio,incluso diferentes unidades físicas. Lo más aconsejable es guardar en diferentes unidades, por unlado el archivo de datos, y por otro el archivo de registro de transacciones. De modo que en casode fallo, por lo menos tengamos uno de ellos.A continuación puedes ver una figura que representa la estructura física de la base de datos,tomando como ejemplo el nombre principal "MiEmpresa".No debes quedarte con la idea de que una base de datos, se compone sencillamente de dosarchivos, es algo mucho más completo que todo eso lo que representa una base de datos comoentidad.
    • En el momento de crear la base de datos, es casi imposible conocer la cantidad de memoria quenecesitará para almacenar toda la información. Es cierto que hay ciertas técnicas que nos permitencalcular el tamaño que podrá alcanzar la base de datos, pero estas estimaciones pueden venirse abajo, por modificaciones imprevistas, como puede ser el crecimiento de la empresa y que seintensifique la actividad realizada sobre la información, por citar un ejemplo.Tampoco es nada aconsejable pecar de precavidos y reservar una cantidad de memoriaexagerada, y pensar que con esta cantidad casi infinita no tendremos problemas de espacio paranuestros datos. De acuerdo, puede que no haya problemas de espacio (o quizá sí), pero lo que esseguro es que tendremos muchísimos problemas de rendimiento, de fragmentación etc...SQL Server 2005 nos permite olvidarnos hasta cierto punto de este problema. Los archivos dedatos y de registro, crecen automáticamente. No crecen con cada dato que se añade. Nosotroscomo administradores, le daremos un tamaño inicial sencillo de estimar ( una cantidad muypequeña, unos Megabytes ), en ese momento SQL Server 2005 crea la estructura correcta para labase de datos, y una vez que nuestra base de datos está en explotación cuando alcanza el tamañolimite, lo incrementa una cantidad dada por un factor predeterminado.Visto de modo teórico puede asustar un poco, sólo estamos comenzando a crear la base de datos,y estamos mencionando varias características a tener en cuenta. No tenemos porque asustarnos,veremos como estos parámetros se pueden dar de un modo altamente sencillo mediante el interfazde SQL Server 2005, y como con pocos clicks, todos estos aspectos los realiza SQL Server pornosotros, así que no te preocupes y sigue leyendo.Unidad II1 - Crear una tabla (create table - sp_tables - sp_columns - drop table)DETALLE DEL CONCEPTOUna base de datos almacena su información en tablas.Una tabla es una estructura de datos que organiza los datos en columnas y filas; cada columna esun campo (o atributo) y cada fila, un registro. La intersección de una columna con una fila, contieneun dato específico, un solo valor.Cada registro contiene un dato por cada columna de la tabla.Cada campo (columna) debe tener un nombre. El nombre del campo hace referencia a lainformación que almacenará.Cada campo (columna) también debe definir el tipo de dato que almacenará. Las tablas formanparte de una base de datos. Nosotros trabajaremos con la base de datos llamadawi520641_sqlserverya (este nombre se debe a que las empresas de hosting es la que lo define),que ya he creado en el servidor sqlserverya.com.ar.Para ver las tablas existentes creadas por los usuarios en una base de datos usamos elprocedimiento almacenado "sp_tables @table_owner=dbo;": sp_tables @table_owner=dbo;
    • El parámetro @table_owner=dbo indica que solo muestre las tablas de usuarios y no las que creael SQL Server para administración interna.Finalizamos cada comando con un punto y coma.Al crear una tabla debemos resolver qué campos (columnas) tendrá y que tipo de datosalmacenarán cada uno de ellos, es decir, su estructura.La sintaxis básica y general para crear una tabla es la siguiente:create table NOMBRETABLA( NOMBRECAMPO1 TIPODEDATO, ... NOMBRECAMPON TIPODEDATO );La tabla debe ser definida con un nombre que la identifique y con el cual accederemos a ella.Creamos una tabla llamada "usuarios" y entre paréntesis definimos los campos y sus tipos: create table usuarios ( nombre varchar(30), clave varchar(10) );Cada campo con su tipo debe separarse con comas de los siguientes, excepto el último.Cuando se crea una tabla debemos indicar su nombre y definir al menos un campo con su tipo dedato. En esta tabla "usuarios" definimos 2 campos: • nombre: que contendrá una cadena de caracteres de 30 caracteres de longitud, que almacenará el nombre de usuario y • clave: otra cadena de caracteres de 10 de longitud, que guardará la clave de cada usuario.Cada usuario ocupará un registro de esta tabla, con su respectivo nombre y clave.Para nombres de tablas, se puede utilizar cualquier caracter permitido para nombres de directorios,el primero debe ser un caracter alfabético y no puede contener espacios. La longitud máxima es de128 caracteres.Si intentamos crear una tabla con un nombre ya existente (existe otra tabla con ese nombre),mostrará un mensaje indicando que ya hay un objeto llamado usuarios en la base de datos y lasentencia no se ejecutará. Esto es muy importante ya que cuando haga los ejercicios en este sitiopuede haber otra persona que haya creado una tabla con el nombre que usted especifique.Para ver la estructura de una tabla usamos el procedimiento almacenado "sp_columns" junto alnombre de la tabla: sp_columns usuarios;aparece mucha información que no analizaremos en detalle, como el nombre de la tabla, supropietario, los campos, el tipo de dato de cada campo, su longitud, etc.:... COLUMN_NAME TYPE_NAME LENGHT_______________________________________ nombre varchar 30 clave varchar 10Para eliminar una tabla usamos "drop table" junto al nombre de la tabla a eliminar:
    • drop table usuarios; Si intentamos eliminar una tabla que no existe, aparece un mensaje de errorindicando tal situación y la sentencia no se ejecuta. Para evitar este mensaje podemos agregar a lainstrucción lo siguiente:if object_id(usuarios) is not null drop table usuarios;En la sentencia precedente especificamos que elimine la tabla "usuarios" si existe.2 - Insertar y recuperar registros de una tabla (insert into - select)DETALLE DE CONCEPTOUn registro es una fila de la tabla que contiene los datos propiamente dichos. Cada registro tieneun dato por cada columna (campo). Nuestra tabla "usuarios" consta de 2 campos, "nombre" y"clave".Al ingresar los datos de cada registro debe tenerse en cuenta la cantidad y el orden de los campos.La sintaxis básica y general es la siguiente:insert into NOMBRETABLA (NOMBRECAMPO1, ..., NOMBRECAMPOn)values (VALORCAMPO1, ..., VALORCAMPOn);Usamos "insert into", luego el nombre de la tabla, detallamos los nombres de los campos entreparéntesis y separados por comas y luego de la cláusula "values" colocamos los valores para cadacampo, también entre paréntesis y separados por comas.Para agregar un registro a la tabla tipeamos:insert into usuarios (nombre, clave) values (Mariano,payaso);Note que los datos ingresados, como corresponden a cadenas de caracteres se colocan entrecomillas simples.Para ver los registros de una tabla usamos "select":select * from usuarios;El comando "select" recupera los registros de una tabla.Con el asterisco indicamos que muestre todos los campos de la tabla "usuarios".Es importante ingresar los valores en el mismo orden en que se nombran los campos:insert into usuarios (clave, nombre) values (River,Juan);En el ejemplo anterior se nombra primero el campo "clave" y luego el campo "nombre" por eso, losvalores también se colocan en ese orden.Si ingresamos los datos en un orden distinto al orden en que se nombraron los campos, noaparece un mensaje de error y los datos se guardan de modo incorrecto.
    • En el siguiente ejemplo se colocan los valores en distinto orden en que se nombran los campos, elvalor de la clave (la cadena "Boca") se guardará en el campo "nombre" y el valor del nombre (lacadena "Luis") en el campo "clave": insert into usuarios (nombre,clave) values (Boca,Luis);4 - Tipos de datos básicosDETALLE DE CONCEPTOYa explicamos que al crear una tabla debemos resolver qué campos (columnas) tendrá y que tipode datos almacenará cada uno de ellos, es decir, su estructura.El tipo de dato especifica el tipo de información que puede guardar un campo: caracteres,números, etc.Estos son algunos tipos de datos básicos de SQL Server (posteriormente veremos otros): • varchar: se usa para almacenar cadenas de caracteres. Una cadena es una secuencia de caracteres. Se coloca entre comillas (simples); ejemplo: Hola, Juan Perez. El tipo "varchar" define una cadena de longitud variable en la cual determinamos el máximo de caracteres entre paréntesis. Puede guardar hasta 8000 caracteres. Por ejemplo, para almacenar cadenas de hasta 30 caracteres, definimos un campo de tipo varchar(30), es decir, entre paréntesis, junto al nombre del campo colocamos la longitud. Si asignamos una cadena de caracteres de mayor longitud que la definida, la cadena no se carga, aparece un mensaje indicando tal situación y la sentencia no se ejecuta. Por ejemplo, si definimos un campo de tipo varchar(10) e intentamos asignarle la cadena Buenas tardes, aparece un mensaje de error y la sentencia no se ejecuta. • integer: se usa para guardar valores numéricos enteros, de -2000000000 a 2000000000 aprox. Definimos campos de este tipo cuando queremos representar, por ejemplo, cantidades. • float: se usa para almacenar valores numéricos con decimales. Se utiliza como separador el punto (.). Definimos campos de este tipo para precios, por ejemplo.Antes de crear una tabla debemos pensar en sus campos y optar por el tipo de dato adecuadopara cada uno de ellos.Por ejemplo, si en un campo almacenaremos números enteros, el tipo "float" sería una malaelección; si vamos a guardar precios, el tipo "float" es más adecuado, no así "integer" que no tienedecimales. Otro ejemplo, si en un campo vamos a guardar un número telefónico o un número dedocumento, usamos "varchar", no "integer" porque si bien son dígitos, con ellos no realizamosoperaciones matemáticas.3 - Recuperar algunos campos (select)DETALLE DE CONCEPTO
    • Hemos aprendido cómo ver todos los registros de una tabla, empleando la instrucción "select".La sintaxis básica y general es la siguiente: select * from NOMBRETABLA;El asterisco (*) indica que se seleccionan todos los campos de la tabla.Podemos especificar el nombre de los campos que queremos ver separándolos por comas: select titulo,autor from libros;La lista de campos luego del "select" selecciona los datos correspondientes a los camposnombrados. En el ejemplo anterior seleccionamos los campos "titulo" y "autor" de la tabla "libros",mostrando todos los registros. Los datos aparecen ordenados según la lista de selección, en dichalista los nombres de los campos se separan con comas.4 - Operadores relacionalesDESARROLLO DE CONCEPTOLos operadores son símbolos que permiten realizar operaciones matemáticas, concatenarcadenas, hacer comparaciones.SQL Server tiene 4 tipos de operadores: 1. relacionales (o de comparación) 2. aritméticos 3. de concatenación 4. lógicos.Por ahora veremos solamente los primeros.Los operadores relacionales (o de comparación) nos permiten comparar dos expresiones, quepueden ser variables, valores de campos, etc.Hemos aprendido a especificar condiciones de igualdad para seleccionar registros de una tabla;por ejemplo: select *from libros where autor=Borges;Utilizamos el operador relacional de igualdad.Los operadores relacionales vinculan un campo con un valor para que SQL Server compare cadaregistro (el campo especificado) con el valor dado.Los operadores relacionales son los siguientes:= igual<> distinto> mayor< menor>= mayor o igual<= menor o igualPodemos seleccionar los registros cuyo autor sea diferente de "Borges", para ello usamos lacondición: select * from libros where autor<>Borges;Podemos comparar valores numéricos. Por ejemplo, queremos mostrar los títulos y precios de loslibros cuyo precio sea mayor a 20 pesos: select titulo, precio from libros where precio>20;
    • Queremos seleccionar los libros cuyo precio sea menor o igual a 30: select *from libros where precio<=30;Los operadores relacionales comparan valores del mismo tipo. Se emplean para comprobar si uncampo cumple con una condición.No son los únicos, existen otros que veremos mas adelante.5 - Borrar registros (delete)DETALLE DE CONCEPTOPara eliminar los registros de una tabla usamos el comando "delete": delete from usuarios;Muestra un mensaje indicando la cantidad de registros que ha eliminado.Si no queremos eliminar todos los registros, sino solamente algunos, debemos indicar cuál ocuáles, para ello utilizamos el comando "delete" junto con la clausula "where" con la cualestablecemos la condición que deben cumplir los registros a borrar.Por ejemplo, queremos eliminar aquel registro cuyo nombre de usuario es "Marcelo": delete from usuarios where nombre=Marcelo;Si solicitamos el borrado de un registro que no existe, es decir, ningún registro cumple con lacondición especificada, ningún registro será eliminado.Tenga en cuenta que si no colocamos una condición, se eliminan todos los registros de la tablanombrada.6 - Actualizar registros (update)DETALLE DE CONCEPTODecimos que actualizamos un registro cuando modificamos alguno de sus valores.Para modificar uno o varios datos de uno o varios registros utilizamos "update" (actualizar).Por ejemplo, en nuestra tabla "usuarios", queremos cambiar los valores de todas las claves, por"RealMadrid": update usuarios set clave=RealMadrid;Utilizamos "update" junto al nombre de la tabla y "set" junto con el campo a modificar y su nuevovalor.El cambio afectará a todos los registros.Podemos modificar algunos registros, para ello debemos establecer condiciones de selección con"where".Por ejemplo, queremos cambiar el valor correspondiente a la clave de nuestro usuario llamado"Federicolopez", queremos como nueva clave "Boca", necesitamos una condición "where" queafecte solamente a este registro: update usuarios set clave=Boca where nombre=Federicolopez;Si Microsoft SQL Server no encuentra registros que cumplan con la condición del "where", no semodifica ninguno.Las condiciones no son obligatorias, pero si omitimos la cláusula "where", la actualización afectaráa todos los registros.También podemos actualizar varios campos en una sola instrucción:
    • update usuarios set nombre=Marceloduarte, clave=Marce where nombre=Marcelo;Para ello colocamos "update", el nombre de la tabla, "set" junto al nombre del campo y el nuevovalor y separado por coma, el otro nombre del campo con su nuevo valor.7 - ComentariosDETALLE DE CONCEPTOPara aclarar algunas instrucciones, en ocasiones, necesitamos agregar comentarios.Es posible ingresar comentarios en la línea de comandos, es decir, un texto que no se ejecuta;para ello se emplean dos guiones (--) al comienzo de la línea: select * from libros --mostramos los registros de libros;en la línea anterior, todo lo que está luego de los guiones (hacia la derecha) no se ejecuta.Para agregar varias líneas de comentarios, se coloca una barra seguida de un asterisco (/*) alcomienzo del bloque de comentario y al finalizarlo, un asterisco seguido de una barra (*/). select titulo, autor /*mostramos títulos y nombres de los autores*/ from libros;todo lo que está entre los símbolos "/*" y "*/" no se ejecuta.8 - Valores null (is null)DETALLE DE CONCEPTO"null" significa "dato desconocido" o "valor inexistente". No es lo mismo que un valor "0", unacadena vacía o una cadena literal "null".A veces, puede desconocerse o no existir el dato correspondiente a algún campo de un registro.En estos casos decimos que el campo puede contener valores nulos.Por ejemplo, en nuestra tabla de libros, podemos tener valores nulos en el campo "precio" porquees posible que para algunos libros no le hayamos establecido el precio para la venta.En contraposición, tenemos campos que no pueden estar vacíos jamás.Veamos un ejemplo. Tenemos nuestra tabla "libros". El campo "titulo" no debería estar vacíonunca, igualmente el campo "autor". Para ello, al crear la tabla, debemos especificar que dichoscampos no admitan valores nulos: create table libros( titulo varchar(30) not null, autor varchar(20) not null, editorial varchar(15) null, precio float );Para especificar que un campo no admita valores nulos, debemos colocar "not null" luego de ladefinición del campo.En el ejemplo anterior, los campos "editorial" y "precio" si admiten valores nulos.
    • Cuando colocamos "null" estamos diciendo que admite valores nulos (caso del campo "editorial");por defecto, es decir, si no lo aclaramos, los campos permiten valores nulos (caso del campo"precio").Si ingresamos los datos de un libro, para el cual aún no hemos definido el precio podemos colocar"null" para mostrar que no tiene precio: insert into libros (titulo,autor,editorial,precio) values(El aleph,Borges,Emece,null);Note que el valor "null" no es una cadena de caracteres, no se coloca entre comillas.Entonces, si un campo acepta valores nulos, podemos ingresar "null" cuando no conocemos elvalor.También podemos colocar "null" en el campo "editorial" si desconocemos el nombre de la editoriala la cual pertenece el libro que vamos a ingresar: insert into libros (titulo,autor,editorial,precio) values(Alicia en el pais,Lewis Carroll,null,25);Si intentamos ingresar el valor "null" en campos que no admiten valores nulos (como "titulo" o"autor"), SQL Server no lo permite, muestra un mensaje y la inserción no se realiza; por ejemplo: insert into libros (titulo,autor,editorial,precio) values(null,Borges,Siglo XXI,25);Para ver cuáles campos admiten valores nulos y cuáles no, podemos emplear el procedimientoalmacenado "sp_columns" junto al nombre de la tabla. Nos muestra mucha información, en lacolumna "IS_NULLABLE" vemos que muestra "NO" en los campos que no permiten valores nulos y"YES" en los campos que si los permiten.Para recuperar los registros que contengan el valor "null" en algún campo, no podemos utilizar losoperadores relacionales vistos anteriormente: = (igual) y <> (distinto); debemos utilizar losoperadores "is null" (es igual a null) y "is not null" (no es null): select * from libros where precio is null;La sentencia anterior tendrá una salida diferente a la siguiente: select * from libros where precio=0;Con la primera sentencia veremos los libros cuyo precio es igual a "null" (desconocido); con lasegunda, los libros cuyo precio es 0.Igualmente para campos de tipo cadena, las siguientes sentencias "select" no retornan los mismosregistros: select * from libros where editorial is null; select * from libros where editorial=;Con la primera sentencia veremos los libros cuya editorial es igual a "null", con la segunda, loslibros cuya editorial guarda una cadena vacía.Entonces, para que un campo no permita valores nulos debemos especificarlo luego de definir elcampo, agregando "not null". Por defecto, los campos permiten valores nulos, pero podemosespecificarlo igualmente agregando "null".9 - Clave primariaDETALLE DEL CONCEPTO
    • Una clave primaria es un campo (o varios) que identifica un solo registro (fila) en una tabla.Para un valor del campo clave existe solamente un registro.Veamos un ejemplo, si tenemos una tabla con datos de personas, el número de documento puedeestablecerse como clave primaria, es un valor que no se repite; puede haber personas con igualapellido y nombre, incluso el mismo domicilio (padre e hijo por ejemplo), pero su documento serásiempre distinto.Si tenemos la tabla "usuarios", el nombre de cada usuario puede establecerse como claveprimaria, es un valor que no se repite; puede haber usuarios con igual clave, pero su nombre deusuario será siempre diferente.Podemos establecer que un campo sea clave primaria al momento de crear la tabla o luego que hasido creada. Vamos a aprender a establecerla al crear la tabla. Hay 2 maneras de hacerlo, porahora veremos la sintaxis más sencilla.Tenemos nuestra tabla "usuarios" definida con 2 campos ("nombre" y "clave").La sintaxis básica y general es la siguiente: create table NOMBRETABLA( CAMPO TIPO, ... primary key (NOMBRECAMPO) );En el siguiente ejemplo definimos una clave primaria, para nuestra tabla "usuarios" paraasegurarnos que cada usuario tendrá un nombre diferente y único: create table usuarios( nombre varchar(20), clave varchar(10), primary key(nombre) );Lo que hacemos agregar luego de la definición de cada campo, "primary key" y entre paréntesis, elnombre del campo que será clave primaria.Una tabla sólo puede tener una clave primaria. Cualquier campo (de cualquier tipo) puede serclave primaria, debe cumplir como requisito, que sus valores no se repitan ni sean nulos. Por ello,al definir un campo como clave primaria, automáticamente SQL Server lo convierte a "not null".Luego de haber establecido un campo como clave primaria, al ingresar los registros, SQL Servercontrola que los valores para el campo establecido como clave primaria no estén repetidos en latabla; si estuviesen repetidos, muestra un mensaje y la inserción no se realiza. Es decir, si ennuestra tabla "usuarios" ya existe un usuario con nombre "juanperez" e intentamos ingresar unnuevo usuario con nombre "juanperez", aparece un mensaje y la instrucción "insert" no se ejecuta.Igualmente, si realizamos una actualización, SQL Server controla que los valores para el campoestablecido como clave primaria no estén repetidos en la tabla, si lo estuviese, aparece un mensajeindicando que se viola la clave primaria y la actualización no se realiza.10 - Campo con atributo IdentityDETALLE DE CONCEPTO
    • Un campo numérico puede tener un atributo extra "identity". Los valores de un campo con esteatributo genera valores secuenciales que se inician en 1 y se incrementan en 1 automáticamente.Se utiliza generalmente en campos correspondientes a códigos de identificación para generarvalores únicos para cada nuevo registro que se inserta.Sólo puede haber un campo "identity" por tabla.Para que un campo pueda establecerse como "identity", éste debe ser entero (también puede serde un subtipo de entero o decimal con escala 0, tipos que estudiaremos posteriormente).Para que un campo genere sus valores automáticamente, debemos agregar el atributo "identity"luego de su definición al crear la tabla: create table libros( codigo int identity, titulo varchar(40) not null, autor varchar(30), editorial varchar(15), precio float );Cuando un campo tiene el atributo "identity" no se puede ingresar valor para él, porque se insertaautomáticamente tomando el último valor como referencia, o 1 si es el primero.Para ingresar registros omitimos el campo definido como "identity", por ejemplo: insert into libros (titulo,autor,editorial,precio) values(El aleph,Borges,Emece,23);Este primer registro ingresado guardará el valor 1 en el campo correspondiente al código.Si continuamos ingresando registros, el código (dato que no ingresamos) se cargaráautomáticamente siguiendo la secuencia de autoincremento.No está permitido ingresar el valor correspondiente al campo "identity", por ejemplo: insert into libros (codigo,titulo,autor,editorial,precio) values(5,Martin Fierro,Jose Hernandez,Paidos,25);generará un mensaje de error."identity" permite indicar el valor de inicio de la secuencia y el incremento, pero lo veremosposteriormente.Un campo definido como "identity" generalmente se establece como clave primaria.Un campo "identity" no es editable, es decir, no se puede ingresar un valor ni actualizarlo.Un campo de identidad no permite valores nulos, aunque no se indique especificamente. Siejecutamos el procedimiento "sp_columns()" veremos que en el campo "codigo" en la columna"TYPE_NAME" aparece "int identity" y en la columna "IS_NULLABLE" aparece "NO".Los valores secuenciales de un campo "identity" se generan tomando como referencia el últimovalor ingresado; si se elimina el último registro ingresado (por ejemplo 3) y luego se inserta otroregistro, SQL Server seguirá la secuencia, es decir, colocará el valor "4".11 - Otras características del atributo IdentityDETALLE DEL CONCEPTOEl atributo "identity" permite indicar el valor de inicio de la secuencia y el incremento, para ellousamos la siguiente sintaxis: create table libros( codigo int identity(100,2), titulo varchar(20),
    • autor varchar(30), precio float );Los valores comenzarán en "100" y se incrementarán de 2 en 2; es decir, el primer registroingresado tendrá el valor "100", los siguientes "102", "104", "106", etc.La función "ident_seed()" retorna el valor de inicio del campo "identity" de la tabla que nombramos: select ident_seed(libros);La función "ident_incr()" retorna el valor de incremento del campo "identity" de la tabla nombrada: select ident_incr(libros);Hemos visto que en un campo declarado "identity" no puede ingresarse explícitamente un valor.Para permitir ingresar un valor en un campo de identidad se debe activar la opción "identity_insert": set identity_insert libros on;Es decir, podemos ingresar valor en un campo "identity" seteando la opción "identity_insert" en"on".Cuando "identity_insert" está en ON, las instrucciones "insert" deben explicitar un valor: insert into libros (codigo,titulo) values (5,Alicia en el pais de las maravillas);Si no se coloca un valor para el campo de identidad, la sentencia no se ejecuta y aparece unmensaje de error: insert into libros (titulo,autor, editorial) values (Matematica estas ahi,Paenza,Paidos);El atributo "identity" no implica unicidad, es decir, permite repetición de valores; por ello hay quetener cuidado al explicitar un valor porque se puede ingresar un valor repetido.Para desactivar la opción "identity_insert" tipeamos: set identity_insert libros off;12 - Truncate tableDETALLE DE CONCEPTOAprendimos que para borrar todos los registro de una tabla se usa "delete" sin condición "where".También podemos eliminar todos los registros de una tabla con "truncate table".Por ejemplo, queremos vaciar la tabla "libros", usamos: truncate table libros;La sentencia "truncate table" vacía la tabla (elimina todos los registros) y conserva la estructura dela tabla.La diferencia con "drop table" es que esta sentencia borra la tabla, "truncate table" la vacía.La diferencia con "delete" es la velocidad, es más rápido "truncate table" que "delete" (se notacuando la cantidad de registros es muy grande) ya que éste borra los registros uno a uno.Otra diferencia es la siguiente: cuando la tabla tiene un campo "identity", si borramos todos losregistros con "delete" y luego ingresamos un registro, al cargarse el valor en el campo de identidad,continúa con la secuencia teniendo en cuenta el valor mayor que se había guardado; si usamos"truncate table" para borrar todos los registros, al ingresar otra vez un registro, la secuencia delcampo de identidad vuelve a iniciarse en 1.Por ejemplo, tenemos la tabla "libros" con el campo "codigo" definido "identity", y el valor más altode ese campo es "2", si borramos todos los registros con "delete" y luego ingresamos un registro,éste guardará el valor de código "3"; si en cambio, vaciamos la tabla con "truncate table", alingresar un nuevo registro el valor del código se iniciará en 1 nuevamente.
    • 13 - Otros tipos de datos en SQL ServerDETALLE DE CONCEPTOYa explicamos que al crear una tabla debemos elegir la estructura adecuada, esto es, definir loscampos y sus tipos más precisos, según el caso.El tipo de dato especificado en la definición de cada campo indica los valores permitidos para cadauno de ellos.Hasta ahora hemos visto 3 tipos de datos: varchar, integer y float. Hay más tipos, incluso, subtipos.Los valores que podemos guardar son: 1. TEXTO: Para almacenar texto usamos cadenas de caracteres. Las cadenas se colocan entre comillas simples. Podemos almacenar letras, símbolos y dígitos con los que no se realizan operaciones matemáticas, por ejemplo, códigos de identificación, números de documentos, números telefónicos. SQL Server ofrece los siguientes tipos: char, nchar, varchar, nvarchar, text y ntext. 2. NUMEROS: Existe variedad de tipos numéricos para representar enteros, decimales, monedas. Para almacenar valores enteros, por ejemplo, en campos que hacen referencia a cantidades, precios, etc., usamos el tipo integer (y sus subtipos: tinyint, smallint y bigint). Para almacenar valores con decimales exactos, utilizamos: numeric o decimal (son equivalentes). Para guardar valores decimales aproximados: float y real. Para almacenar valores monetarios: money y smallmoney. 3. FECHAS y HORAS: para guardar fechas y horas SQL Server dispone de 2 tipos: datetime y smalldatetime.Existen otros tipos de datos que analizaremos en secciones próximas.Entonces, cuando creamos una tabla y definir sus campos debemos elegir el tipo de dato máspreciso. Por ejemplo, si necesitamos almacenar nombres usamos texto; si un campo numéricoalmacenará solamente valores enteros el tipo "integer" es más adecuado que, por ejemplo un"float"; si necesitamos almacenar precios, lo más lógico es utilizar el tipo "money".A continuación analizaremos en detalle cada tipo de dato básicos.17 - Tipo de dato (texto)DETALLE DE CONCEPTOYa explicamos que al crear una tabla debemos elegir la estructura adecuada, esto es, definir loscampos y sus tipos más precisos, según el caso.
    • Para almacenar TEXTO usamos cadenas de caracteres.Las cadenas se colocan entre comillas simples.Podemos almacenar letras, símbolos y dígitos con los que no se realizan operacionesmatemáticas, por ejemplo, códigos de identificación, números de documentos, númerostelefónicos.Tenemos los siguientes tipos: 1. varchar(x): define una cadena de caracteres de longitud variable en la cual determinamos el máximo de caracteres con el argumento "x" que va entre paréntesis. Si se omite el argumento coloca 1 por defecto. Su rango va de 1 a 8000 caracteres. 2. char(x): define una cadena de longitud fija determinada por el argumento "x". Si se omite el argumento coloca 1 por defecto. Su rango es de 1 a 8000 caracteres. Si la longitud es invariable, es conveniente utilizar el tipo char; caso contrario, el tipo varchar. Ocupa tantos bytes como se definen con el argumento "x". "char" viene de character, que significa caracter en inglés. 3. text: guarda datos binarios de longitud variable, puede contener hasta 2000000000 caracteres. No admite argumento para especificar su longitud. 4. nvarchar(x): es similar a "varchar", excepto que permite almacenar caracteres Unicode, su rango va de 0 a 4000 caracteres porque se emplean 2 bytes por cada caracter. 5. nchar(x): es similar a "char" excpeto que acepta caracteres Unicode, su rango va de 0 a 4000 caracteres porque se emplean 2 bytes por cada caracter. 6. ntext: es similar a "text" excepto que permite almacenar caracteres Unicode, puede contener hasta 1000000000 caracteres. No admite argumento para especificar su longitud.En general se usarán los 3 primeros.Si intentamos almacenar en un campo una cadena de caracteres de mayor longitud que ladefinida, aparece un mensaje indicando tal situación y la sentencia no se ejecuta.Por ejemplo, si definimos un campo de tipo varchar(10) y le asignamos la cadena Aprenda PHP(11 caracteres), aparece un mensaje y la sentencia no se ejecuta.Si ingresamos un valor numérico (omitiendo las comillas), lo convierte a cadena y lo ingresa comotal.Por ejemplo, si en un campo definido como varchar(5) ingresamos el valor 12345, lo toma como sihubiésemos tipeado 12345, igualmente, si ingresamos el valor 23.56, lo convierte a 23.56. Si elvalor numérico, al ser convertido a cadena supera la longitud definida, aparece un mensaje deerror y la sentencia no se ejecuta.Es importante elegir el tipo de dato adecuado según el caso, el más preciso.Para almacenar cadenas que varían en su longitud, es decir, no todos los registros tendrán lamisma longitud en un campo determinado, se emplea "varchar" en lugar de "char".Por ejemplo, en campos que guardamos nombres y apellidos, no todos los nombres y apellidostienen la misma longitud.Para almacenar cadenas que no varían en su longitud, es decir, todos los registros tendrán lamisma longitud en un campo determinado, se emplea "char".Por ejemplo, definimos un campo "codigo" que constará de 5 caracteres, todos los registrostendrán un código de 5 caracteres, ni más ni menos.Para almacenar valores superiores a 8000 caracteres se debe emplear "text".Tipo Bytes de almacenamiento_______________________________________varchar(x) 0 a 8Kchar(x) 0 a 8Ktext 0 a 2GB
    • nvarchar(x) 0 a 8Knchar(x) 0 a 8Kntext 0 a 2GB18 - Tipo de dato (numérico)DETALLE DE CONCEPTOYa explicamos que al crear una tabla debemos elegir la estructura adecuada, esto es, definir loscampos y sus tipos más precisos, según el caso.Para almacenar valores NUMERICOS SQL Server dispone de varios tipos.Para almacenar valores ENTEROS, por ejemplo, en campos que hacen referencia a cantidades,usamos:1) integer o int: su rango es de -2000000000 a 2000000000 aprox. El tipo "integer" tiene subtipos:- smallint: Puede contener hasta 5 digitos. Su rango va desde –32000 hasta 32000 aprox.- tinyint: Puede almacenar valores entre 0 y 255.- bigint: De –9000000000000000000 hasta 9000000000000000000 aprox.Para almacenar valores numéricos EXACTOS con decimales, especificando la cantidad de cifras ala izquierda y derecha del separador decimal, utilizamos:2) decimal o numeric (t,d): Pueden tener hasta 38 digitos, guarda un valor exacto. El primerargumento indica el total de dígitos y el segundo, la cantidad de decimales.Por ejemplo, si queremos almacenar valores entre -99.99 y 99.99 debemos definir el campo comotipo "decimal(4,2)". Si no se indica el valor del segundo argumento, por defecto es "0". Por ejemplo,si definimos "decimal(4)" se pueden guardar valores entre -9999 y 9999.El rango depende de los argumentos, también los bytes que ocupa.Se utiliza el punto como separador de decimales.Si ingresamos un valor con más decimales que los permitidos, redondea al más cercano; porejemplo, si definimos "decimal(4,2)" e ingresamos el valor "12.686", guardará "12.69", redondeandohacia arriba; si ingresamos el valor "12.682", guardará "12.67", redondeando hacia abajo.Para almacenar valores numéricos APROXIMADOS con decimales utilizamos:3) float y real: De 1.79E+308 hasta 1.79E+38. Guarda valores aproximados.4) real: Desde 3.40E+308 hasta 3.40E+38. Guarda valores aproximados.Para almacenar valores MONETARIOS empleamos:5) money: Puede tener hasta 19 digitos y sólo 4 de ellos puede ir luego del separador decimal;entre –900000000000000.5808 aprox y 900000000000000.5807.6) smallmoney: Entre –200000.3648 y 200000.3647 aprox.Para todos los tipos numéricos:- si intentamos ingresar un valor fuera de rango, no lo permite.- si ingresamos una cadena, SQL Server intenta convertirla a valor numérico, si dicha cadenaconsta solamente de dígitos, la conversión se realiza, luego verifica si está dentro del rango, si esasí, la ingresa, sino, muestra un mensaje de error y no ejecuta la sentencia. Si la cadena contienecaracteres que SQL Server no puede convertir a valor numérico, muestra un mensaje de error y lasentencia no se ejecuta.Por ejemplo, definimos un campo de tipo decimal(5,2), si ingresamos la cadena 12.22, la convierteal valor numérico 12.22 y la ingresa; si intentamos ingresar la cadena 1234.56, la convierte alvalor numérico 1234.56, pero como el máximo valor permitido es 999.99, muestra un mensajeindicando que está fuera de rango. Si intentamos ingresar el valor 12y.25, SQL Server no puederealizar la conversión y muestra un mensaje de error.
    • Es importante elegir el tipo de dato adecuado según el caso, el más preciso. Por ejemplo, si uncampo numérico almacenará valores positivos menores a 255, el tipo "int" no es el más adecuado,conviene el tipo "tinyint", de esta manera usamos el menor espacio de almacenamiento posible.Si vamos a guardar valores monetarios menores a 200000 conviene emplear "smallmoney" enlugar de "money".Tipo Bytes de almacenamiento_______________________________________int 4smallint 2tinyint 1bigint 8decimal 2 a 17float 4u8real 4u8money 8smallmoney 419 - Tipo de dato (fecha y hora)DETALLE DE CONCEPTOYa explicamos que al crear una tabla debemos elegir la estructura adecuada, esto es, definir loscampos y sus tipos más precisos, según el caso.Para almacenar valores de tipo FECHA Y HORA SQL Server dispone de dos tipos:1) datetime: puede almacenar valores desde 01 de enero de 1753 hasta 31 de diciembre de 9999.2) smalldatetime: el rango va de 01 de enero de 1900 hasta 06 de junio de 2079.Las fechas se ingresan entre comillas simples.Para almacenar valores de tipo fecha se permiten como separadores "/", "-" y ".".SQL Server reconoce varios formatos de entrada de datos de tipo fecha. Para establecer el ordende las partes de una fecha (dia, mes y año) empleamos "set dateformat". Estos son los formatos:-mdy: 4/15/96 (mes y día con 1 ó 2 dígitos y año con 2 ó 4 dígitos),-myd: 4/96/15,-dmy: 15/4/1996-dym: 15/96/4,-ydm: 96/15/4,-ydm: 1996/15/4,Para ingresar una fecha con formato "día-mes-año", tipeamos: set dateformat dmy;El formato por defecto es "mdy".Todos los valores de tipo "datetime" se muestran en formato "año-mes-día hora:minuto:segundo.milisegundos", independientemente del formato de ingreso que hayamos seteado.Podemos ingresar una fecha, sin hora, en tal caso la hora se guarda como "00:00:00". Por ejemplo,si ingresamos 25-12-01 (año de 2 dígitos), lo mostrará así: 2001-12-25 00:00:00.000.Podemos ingresar una hora sin fecha, en tal caso, coloca la fecha "1900-01-01". Por ejemplo, siingresamos 10:15, mostrará 1900-01-01 10:15.000.
    • Podemos emplear los operadores relacionales vistos para comparar fechas.Tipo Bytes de almacenamiento_______________________________________datetime 8smalldatetime 420 - Ingresar algunos campos (insert into)DETALLE DE CONCEPTOHemos aprendido a ingresar registros listando todos los campos y colocando valores para todos ycada uno de ellos luego de "values".Si ingresamos valores para todos los campos, podemos omitir la lista de nombres de los campos.Por ejemplo, si tenemos creada la tabla "libros" con los campos "titulo", "autor" y "editorial",podemos ingresar un registro de la siguiente manera: insert into libros values (Uno,Richard Bach,Planeta);También es posible ingresar valores para algunos campos. Ingresamos valores solamente para loscampos "titulo" y "autor": insert into libros (titulo, autor) values (El aleph,Borges);SQL Server almacenará el valor "null" en el campo "editorial", para el cual no hemos explicitado unvalor.Al ingresar registros debemos tener en cuenta:- la lista de campos debe coincidir en cantidad y tipo de valores con la lista de valores luego de"values". Si se listan más (o menos) campos que los valores ingresados, aparece un mensaje deerror y la sentencia no se ejecuta.- si ingresamos valores para todos los campos podemos obviar la lista de campos.- podemos omitir valores para los campos que NO hayan sido declarados "not null", es decir, quepermitan valores nulos (se guardará "null"); si omitimos el valor para un campo "not null", lasentencia no se ejecuta.- se DEBE omitir el valor para el campo"identity". Salvo que identity_insert este en on.- se pueden omitir valores para campos declarados "not null" siempre que tengan definido un valorpor defecto con la cláusula "default" (tema que veremos a continuación).21 - Valores por defecto (default)DETALLE DE CONCEPTOHemos visto que si al insertar registros no se especifica un valor para un campo que admitevalores nulos, se ingresa automaticamente "null" y si el campo está declarado "identity", se insertael siguiente de la secuencia. A estos valores se les denomina valores por defecto opredeterminados.Un valor por defecto se inserta cuando no está presente al ingresar un registro y en algunos casosen que el dato ingresado es inválido.Para campos de cualquier tipo no declarados "not null", es decir, que admiten valores nulos, elvalor por defecto es "null". Para campos declarados "not null", no existe valor por defecto, a menosque se declare explícitamente con la cláusula "default".
    • Para todos los tipos, excepto los declarados "identity", se pueden explicitar valores por defecto conla cláusula "default".Podemos establecer valores por defecto para los campos cuando creamos la tabla. Para elloutilizamos "default" al definir el campo. Por ejemplo, queremos que el valor por defecto del campo"autor" de la tabla "libros" sea "Desconocido" y el valor por defecto del campo "cantidad" sea "0": create table libros( codigo int identity, titulo varchar(40), autor varchar(30) not null default Desconocido, editorial varchar(20), precio decimal(5,2), cantidad tinyint default 0 );Si al ingresar un nuevo registro omitimos los valores para el campo "autor" y "cantidad", Sql Serverinsertará los valores por defecto; el siguiente valor de la secuencia en "codigo", en "autor" colocará"Desconocido" y en cantidad "0".Entonces, si al definir el campo explicitamos un valor mediante la cláusula "default", ése será elvalor por defecto.Ahora, al visualizar la estructura de la tabla con "sp_columns" podemos entender lo que informa lacolumna "COLUMN_DEF", muestra el valor por defecto del campo.También se puede utilizar "default" para dar el valor por defecto a los campos en sentencias"insert", por ejemplo: insert into libros (titulo,autor,precio,cantidad) values (El gato con botas,default,default,100);Si todos los campos de una tabla tienen valores predeterminados (ya sea por ser "identity", permitirvalores nulos o tener un valor por defecto), se puede ingresar un registro de la siguiente manera: insert into libros default values;La sentencia anterior almacenará un registro con los valores predetermiandos para cada uno desus campos.Entonces, la cláusula "default" permite especificar el valor por defecto de un campo. Si no seexplicita, el valor por defecto es "null", siempre que el campo no haya sido declarado "not null".Los campos para los cuales no se ingresan valores en un "insert" tomarán los valores por defecto:- si tiene el atributo "identity": el valor de inicio de la secuencia si es el primero o el siguiente valorde la secuencia, no admite cláusula "default";- si permite valores nulos y no tiene cláusula "default", almacenará "null";- si está declarado explícitamente "not null", no tiene valor "default" y no tiene el atributo "identity",no hay valor por defecto, así que causará un error y el "insert" no se ejecutará.- si tiene cláusula "default" (admita o no valores nulos), el valor definido como predeterminado;- para campos de tipo fecha y hora, si omitimos la parte de la fecha, el valor predeterminado parala fecha es "1900-01-01" y si omitimos la parte de la hora, "00:00:00".Un campo sólo puede tener un valor por defecto. Una tabla puede tener todos sus campos convalores por defecto. Que un campo tenga valor por defecto no significa que no admita valoresnulos, puede o no admitirlos22 - Columnas calculadas (operadores aritméticos y de concatenación)DETALLE DE CONCEPTO
    • Aprendimos que los operadores son símbolos que permiten realizar distintos tipos de operaciones.Dijimos que SQL Server tiene 4 tipos de operadores: 1) relacionales o de comparación (los vimos),2) lógicos (lo veremos más adelante, 3) aritméticos y 4) de concatenación.Los operadores aritméticos permiten realizar cálculos con valores numéricos.Son: multiplicación (*), división (/) y módulo (%) (el resto de dividir números enteros), suma (+) yresta (-).Es posible obtener salidas en las cuales una columna sea el resultado de un cálculo y no un campode una tabla.Si queremos ver los títulos, precio y cantidad de cada libro escribimos la siguiente sentencia: select titulo,precio,cantidad from libros;Si queremos saber el monto total en dinero de un título podemos multiplicar el precio por lacantidad por cada título, pero también podemos hacer que SQL Server realice el cálculo y loincluya en una columna extra en la salida: select titulo, precio,cantidad, precio*cantidad from libros;Si queremos saber el precio de cada libro con un 10% de descuento podemos incluir en lasentencia los siguientes cálculos: select titulo,precio, precio-(precio*0.1) from libros;También podemos actualizar los datos empleando operadores aritméticos: update libros set precio=precio-(precio*0.1);Todas las operaciones matemáticas retornan "null" en caso de error. Ejemplo: select 5/0;Los operadores de concatenación: permite concatenar cadenas, el más (+).Para concatenar el título, el autor y la editorial de cada libro usamos el operador de concatenación("+"): select titulo+-+autor+-+editorial from libros;Note que concatenamos además unos guiones para separar los campos.23 - AliasDETALLE DE CONCEPTOUna manera de hacer más comprensible el resultado de una consulta consiste en cambiar losencabezados de las columnas.Por ejemplo, tenemos la tabla "agenda" con un campo "nombre" (entre otros) en el cual sealmacena el nombre y apellido de nuestros amigos; queremos que al mostrar la información dedicha tabla aparezca como encabezado del campo "nombre" el texto "nombre y apellido", para ellocolocamos un alias de la siguiente manera: select nombre as NombreYApellido, domicilio,telefono from agenda;
    • Para reemplazar el nombre de un campo por otro, se coloca la palabra clave "as" seguido del textodel encabezado.Si el alias consta de una sola cadena las comillas no son necesarias, pero si contiene más de unapalabra, es necesario colocarla entre comillas simples: select nombre as Nombre y apellido, domicilio,telefono from agenda;Un alias puede contener hasta 128 caracteres.También se puede crear un alias para columnas calculadas.La palabra clave "as" es opcional en algunos casos, pero es conveniente usarla.Entonces, un "alias" se usa como nombre de un campo o de una expresión. En estos casos, sonopcionales, sirven para hacer más comprensible el resultado; en otros casos, que veremos másadelante, son obligatorios.24 – FuncionesDETALLE DE CONCEPTOUna función es un conjunto de sentencias que operan como una unidad lógica.Una función tiene un nombre, retorna un parámetro de salida y opcionalmente acepta parámetrosde entrada. Las funciones de SQL Server no pueden ser modificadas, las funciones definidas por elusuario si.SQL Server ofrece varios tipos de funciones para realizar distintas operaciones. Se puedenclasificar de la siguiente manera:1) de agregado: realizan operaciones que combinan varios valores y retornan un único valor. Son"count", "sum", "min" y "max".2) escalares: toman un solo valor y retornan un único valor. Pueden agruparse de la siguientemanera:- de configuración: retornan información referida a la configuración.Ejemplo: select @@version;retorna la fecha, versión y tipo de procesador de SQL Server.- de cursores: retornan información sobre el estado de un cursor.- de fecha y hora: operan con valores "datetime" y "smalldatetime". Reciben un parámetro de tipofecha y hora y retornan un valor de cadena, numérico o de fecha y hora.- matemáticas: realizan operaciones numéricas, geométricas y trigonométricas.- de metadatos: informan sobre las bases de datos y los objetos.- de seguridad: devuelven información referente a usuarios y funciones.- de cadena: operan con valores "char", "varchar", "nchar", "nvarchar", "binary" y "varbinary" ydevuelven un valor de cadena o numérico.- del sistema: informan sobre opciones, objetos y configuraciones del sistema. Ejemplo: select user_name();- estadísticas del sistema: retornan información referente al rendimiento del sistema.- texto e imagen: realizan operaciones con valor de entrada de tipo text o image y retornaninformación referente al mismo.3) de conjuntos de filas: retornan conjuntos de registros.Se pueden emplear las funciones del sistema en cualquier lugar en el que se permita unaexpresión en una sentencia "select".
    • Estudiaremos algunas de ellas.25 - Funciones para el manejo de cadenasDETALLE DE CONCEPTOMicrosoft SQL Server tiene algunas funciones para trabajar con cadenas de caracteres. Estas sonalgunas:- substring(cadena,inicio,longitud): devuelve una parte de la cadena especificada como primerargumento, empezando desde la posición especificada por el segundo argumento y de tantoscaracteres de longitud como indica el tercer argumento. Ejemplo: select substring(Buenas tardes,8,6);retorna "tardes".- str(numero,longitud,cantidaddecimales): convierte números a caracteres; el primer parámetroindica el valor numérico a convertir, el segundo la longitud del resultado (debe ser mayor o igual ala parte entera del número más el signo si lo tuviese) y el tercero, la cantidad de decimales. Elsegundo y tercer argumento son opcionales y deben ser positivos. String significa cadena eninglés.Ejemplo: se convierte el valor numérico "123.456" a cadena, especificando 7 de longitud y 3decimales: select str(123.456,7,3); select str(-123.456,7,3);retorna -123.46;Si no se colocan el segundo y tercer argumeno, la longitud predeterminada es 10 y la cantidad dedecimales 0 y se redondea a entero. Ejemplo: se convierte el valor numérico "123.456" a cadena: select str(123.456);retorna 123; select str(123.456,3);retorna 123;Si el segundo parámetro es menor a la parte entera del número, devuelve asteriscos (*). Ejemplo:select str(123.456,2,3);retorna "**".- stuff(cadena1,inicio,cantidad,cadena2): inserta la cadena enviada como cuarto argumento, en laposición indicada en el segundo argumento, reemplazando la cantidad de caracteres indicada porel tercer argumento en la cadena que es primer parámetro. Stuff significa rellenar en inglés.Ejemplo: select stuff(abcde,3,2,opqrs);retorna "abopqrse". Es decir, coloca en la posición 2 la cadena "opqrs" y reemplaza 2 caracteresde la primer cadena.Los argumentos numéricos deben ser positivos y menor o igual a la longitud de la primera cadena,caso contrario, retorna "null".Si el tercer argumento es mayor que la primera cadena, se elimina hasta el primer carácter.- len(cadena): retorna la longitud de la cadena enviada como argumento. "len" viene de length, quesignifica longitud en inglés. Ejemplo: select len(Hola);devuelve 4.- char(x): retorna un caracter en código ASCII del entero enviado como argumento. Ejemplo:
    • select char(65);retorna "A".- left(cadena,longitud): retorna la cantidad (longitud) de caracteres de la cadena comenzandodesde la izquierda, primer caracter. Ejemplo: select left(buenos dias,8);retorna "buenos d".- right(cadena,longitud): retorna la cantidad (longitud) de caracteres de la cadena comenzandodesde la derecha, último caracter. Ejemplo: select right(buenos dias,8);retorna "nos dias".-lower(cadena): retornan la cadena con todos los caracteres en minúsculas. lower significa reduciren inglés. Ejemplo: select lower(HOLA ESTUDIAnte);retorna "hola estudiante".-upper(cadena): retornan la cadena con todos los caracteres en mayúsculas. Ejemplo: select upper(HOLA ESTUDIAnte);-ltrim(cadena): retorna la cadena con los espacios de la izquierda eliminados. Trim significarecortar. Ejemplo: select ltrim( Hola );retorna "Hola ".- rtrim(cadena): retorna la cadena con los espacios de la derecha eliminados. Ejemplo: select rtrim( Hola );retorna " Hola".- replace(cadena,cadenareemplazo,cadenareemplazar): retorna la cadena con todas lasocurrencias de la subcadena reemplazo por la subcadena a reemplazar. Ejemplo: select replace(xxx.sqlserverya.com,x,w);retorna "www.sqlserverya.com.- reverse(cadena): devuelve la cadena invirtiendo el order de los caracteres. Ejemplo: select reverse(Hola);retorna "aloH".- patindex(patron,cadena): devuelve la posición de comienzo (de la primera ocurrencia) del patrónespecificado en la cadena enviada como segundo argumento. Si no la encuentra retorna 0.Ejemplos: select patindex(%Luis%, Jorge Luis Borges);retorna 7. select patindex(%or%, Jorge Luis Borges);retorna 2. select patindex(%ar%, Jorge Luis Borges);retorna 0.- charindex(subcadena,cadena,inicio): devuelve la posición donde comienza la subcadena en lacadena, comenzando la búsqueda desde la posición indicada por "inicio". Si el tercer argumento nose coloca, la búsqueda se inicia desde 0. Si no la encuentra, retorna 0. Ejemplos: select charindex(or,Jorge Luis Borges,5);retorna 13. select charindex(or,Jorge Luis Borges);retorna 2. select charindex(or,Jorge Luis Borges,14);retorna 0. select charindex(or, Jorge Luis Borges);
    • retorna 0.- replicate(cadena,cantidad): repite una cadena la cantidad de veces especificada. Ejemplo: select replicate (Hola,3);retorna "HolaHolaHola";- space(cantidad): retorna una cadena de espacios de longitud indicada por "cantidad", que debeser un valor positivo. Ejemplo: select Hola+space(1)+que tal;retorna "Hola que tal".Se pueden emplear estas funciones enviando como argumento el nombre de un campo de tipocaracter.26 - Funciones matemáticasDETALLE DE CONCEPTOLas funciones matemáticas realizan operaciones con expresiones numéricas y retornan unresultado, operan con tipos de datos numéricos.Microsoft SQL Server tiene algunas funciones para trabajar con números. Aquí presentamosalgunas.-abs(x): retorna el valor absoluto del argumento "x". Ejemplo: select abs(-20);retorna 20.-ceiling(x): redondea hacia arriba el argumento "x". Ejemplo: select ceiling(12.34);retorna 13.-floor(x): redondea hacia abajo el argumento "x". Ejemplo: select floor(12.34);retorna 12.- %: %: devuelve el resto de una división. Ejemplos: select 10%3;retorna 1. select 10%2;retorna 0.-power(x,y): retorna el valor de "x" elevado a la "y" potencia. Ejemplo: select power(2,3);retorna 8.-round(numero,longitud): retorna un número redondeado a la longitud especificada. "longitud" debeser tinyint, smallint o int. Si "longitud" es positivo, el número de decimales es redondeado según"longitud"; si es negativo, el número es redondeado desde la parte entera según el valor de"longitud". Ejemplos: select round(123.456,1);retorna "123.400", es decir, redondea desde el primer decimal. select round(123.456,2);retorna "123.460", es decir, redondea desde el segundo decimal. select round(123.456,-1);retorna "120.000", es decir, redondea desde el primer valor entero (hacia la izquierda). select round(123.456,-2);retorna "100.000", es decir, redondea desde el segundo valor entero (hacia la izquierda).-sign(x): si el argumento es un valor positivo devuelve 1;-1 si es negativo y si es 0, 0.
    • -square(x): retorna el cuadrado del argumento. Ejemplo: select square(3); retorna 9.-srqt(x): devuelve la raiz cuadrada del valor enviado como argumento.SQL Server dispone de funciones trigonométricas que retornan radianes.Se pueden emplear estas funciones enviando como argumento el nombre de un campo de tiponumérico27 - Funciones para el uso de fechas y horasDETALLE DE CONCEPTOMicrosoft SQL Server ofrece algunas funciones para trabajar con fechas y horas. Estas sonalgunas:- getdate(): retorna la fecha y hora actuales. Ejemplo: select getdate();- datepart(partedefecha,fecha): retorna la parte específica de una fecha, el año, trimestre, día,hora, etc.Los valores para "partedefecha" pueden ser: year (año), quarter (cuarto), month (mes), day (dia),week (semana), hour (hora), minute (minuto), second (segundo) y millisecond (milisegundo).Ejemplos: select datepart(month,getdate());retorna el número de mes actual; select datepart(day,getdate());retorna el día actual; select datepart(hour,getdate());retorna la hora actual;- datename(partedefecha,fecha): retorna el nombre de una parte específica de una fecha. Losvalores para "partedefecha" pueden ser los mismos que se explicaron anteriormente. Ejemplos: select datename(month,getdate());retorna el nombre del mes actual; select datename(day,getdate());- dateadd(partedelafecha,numero,fecha): agrega un intervalo a la fecha especificada, es decir,retorna una fecha adicionando a la fecha enviada como tercer argumento, el intervalo de tiempoindicado por el primer parámetro, tantas veces como lo indica el segundo parámetro. Los valorespara el primer argumento pueden ser: year (año), quarter (cuarto), month (mes), day (dia), week(semana), hour (hora), minute (minuto), second (segundo) y millisecond (milisegundo). Ejemplos: select dateadd(day,3,1980/11/02);retorna "1980/11/05", agrega 3 días. select dateadd(month,3,1980/11/02);retorna "1981/02/02", agrega 3 meses. select dateadd(hour,2,1980/11/02);retorna "1980/02/02 2:00:00", agrega 2 horas. select dateadd(minute,16,1980/11/02);retorna "1980/02/02 00:16:00", agrega 16 minutos.- datediff(partedelafecha,fecha1,fecha2): calcula el intervalo de tiempo (según el primer argumento)entre las 2 fechas. El resultado es un valor entero que corresponde a fecha2-fecha1. Los valoresde "partedelafecha) pueden ser los mismos que se especificaron anteriormente. Ejemplos: select datediff (day,2005/10/28,2006/10/28);retorna 365 (días).
    • select datediff(month,2005/10/28,2006/11/29);retorna 13 (meses).- day(fecha): retorna el día de la fecha especificada. Ejemplo: select day(getdate());- month(fecha): retorna el mes de la fecha especificada. Ejemplo: select month(getdate());- year(fecha): retorna el año de la fecha especificada. Ejemplo: select year(getdate());Se pueden emplear estas funciones enviando como argumento el nombre de un campo de tipodatetime o smalldatetime.28 - Ordenar registros (order by)DETALLE DE CONCEPTOPodemos ordenar el resultado de un "select" para que los registros se muestren ordenados poralgún campo, para ello usamos la cláusula "order by".La sintaxis básica es la siguiente: select *from NOMBRETABLA order by CAMPO;Por ejemplo, recuperamos los registros de la tabla "libros" ordenados por el título:select *from libros order by titulo;Aparecen los registros ordenados alfabéticamente por el campo especificado.También podemos colocar el número de orden del campo por el que queremos que se ordene enlugar de su nombre, es decir, referenciar a los campos por su posición en la lista de selección. Porejemplo, queremos el resultado del "select" ordenado por "precio": select titulo,autor,precio from libros order by 3;Por defecto, si no aclaramos en la sentencia, los ordena de manera ascendente (de menor amayor).Podemos ordenarlos de mayor a menor, para ello agregamos la palabra clave "desc": select *libros order by editorial desc;También podemos ordenar por varios campos, por ejemplo, por "titulo" y "editorial": select *from libros order by titulo,editorial;Incluso, podemos ordenar en distintos sentidos, por ejemplo, por "titulo" en sentido ascendente y"editorial" en sentido descendente: select *from libros order by titulo asc, editorial desc;Debe aclararse al lado de cada campo, pues estas palabras claves afectan al campoinmediatamente anterior.Es posible ordenar por un campo que no se lista en la selección.Se permite ordenar por valores calculados o expresiones.La cláusula "order by" no puede emplearse para campos text, ntext e image.
    • 29 - Operadores lógicos ( and - or - not)DETALLE DE CONCEPTOHasta el momento, hemos aprendido a establecer una condición con "where" utilizando operadoresrelacionales. Podemos establecer más de una condición con la cláusula "where", para elloaprenderemos los operadores lógicos.Son los siguientes:- and, significa "y",- or, significa "y/o",- not, significa "no", invierte el resultado- (), paréntesisLos operadores lógicos se usan para combinar condiciones.Si queremos recuperar todos los libros cuyo autor sea igual a "Borges" y cuyo precio no supere los20 pesos, necesitamos 2 condiciones: select *from libros where (autor=Borges) and (precio<=20);Los registros recuperados en una sentencia que une 2 condiciones con el operador "and", cumplencon las 2 condiciones.Queremos ver los libros cuyo autor sea "Borges" y/o cuya editorial sea "Planeta": select *from libros where autor=Borges or editorial=Planeta;En la sentencia anterior usamos el operador "or"; indicamos que recupere los libros en los cuales elvalor del campo "autor" sea "Borges" y/o el valor del campo "editorial" sea "Planeta", es decir,seleccionará los registros que cumplan con la primera condición, con la segunda condición o conambas condiciones.Los registros recuperados con una sentencia que une 2 condiciones con el operador "or", cumplen1 de las condiciones o ambas.Queremos recuperar los libros que NO cumplan la condición dada, por ejemplo, aquellos cuyaeditorial NO sea "Planeta": select *from libros where not editorial=Planeta;El operador "not" invierte el resultado de la condición a la cual antecede.Los registros recuperados en una sentencia en la cual aparece el operador "not", no cumplen conla condición a la cual afecta el "NOT".Los paréntesis se usan para encerrar condiciones, para que se evalúen como una sola expresión.Cuando explicitamos varias condiciones con diferentes operadores lógicos (combinamos "and","or") permite establecer el orden de prioridad de la evaluación; además permite diferenciar lasexpresiones más claramente.Por ejemplo, las siguientes expresiones devuelven un resultado diferente: select*from libros where (autor=Borges) or (editorial=Paidos and precio<20);select *from libros where (autor=Borges or editorial=Paidos) and (precio<20);
    • Si bien los paréntesis no son obligatorios en todos los casos, se recomienda utilizarlos para evitarconfusiones.El orden de prioridad de los operadores lógicos es el siguiente: "not" se aplica antes que "and" y"and" antes que "or", si no se especifica un orden de evaluación mediante el uso de paréntesis.El orden en el que se evalúan los operadores con igual nivel de precedencia es indefinido, por ellose recomienda usar los paréntesis.Entonces, para establecer más de una condición en un "where" es necesario emplear operadoreslógicos. "and" significa "y", indica que se cumplan ambas condiciones; "or" significa "y/o", indicaque se cumpla una u otra condición (o ambas); "not" significa "no", indica que no se cumpla lacondición especificada.30 - Otros operadores relacionales (is null)DETALLE DE CONCEPTOHemos aprendido los operadores relacionales "=" (igual), "<>" (distinto), ">" (mayor), "<" (menor),">=" (mayor o igual) y "<=" (menor o igual). Dijimos que no eran los únicos.Existen otro operador relacional "is null".Se emplea el operador "is null" para recuperar los registros en los cuales esté almacenado el valor"null" en un campo específico: select *from libros where editorial is null;Para obtener los registros que no contiene "null", se puede emplear "is not null", esto mostrará losregistros con valores conocidos.Siempre que sea posible, emplee condiciones de búsqueda positivas ("is null"), evite las negativas("is not null") porque con ellas se evalúan todos los registros y esto hace más lenta la recuperaciónde los datos.31 - Otros operadores relacionales (between)DETALLE DE CONCEPTOHemos visto los operadores relacionales: = (igual), <> (distinto), > (mayor), < (menor), >= (mayor oigual), <= (menor o igual), is null/is not null (si un valor es NULL o no).Otro operador relacional es "between", trabajan con intervalos de valores.Hasta ahora, para recuperar de la tabla "libros" los libros con precio mayor o igual a 20 y menor oigual a 40, usamos 2 condiciones unidas por el operador lógico "and": select *from libros where precio>=20 and precio<=40;Podemos usar "between" y así simplificar la consulta: select *from libros where precio between 20 and 40;Averiguamos si el valor de un campo dado (precio) está entre los valores mínimo y máximoespecificados (20 y 40 respectivamente)."between" significa "entre". Trabaja con intervalo de valores.Este operador se puede emplear con tipos de datos numéricos y money (en tales casos incluyenlos valores mínimo y máximo) y tipos de datos fecha y hora (incluye sólo el valor mínimo).No tiene en cuenta los valores "null".
    • Si agregamos el operador "not" antes de "between" el resultado se invierte, es decir, se recuperanlos registros que están fuera del intervalo especificado. Por ejemplo, recuperamos los libros cuyoprecio NO se encuentre entre 20 y 35, es decir, los menores a 15 y mayores a 25: select *from libros where precio not between 20 and 35;Siempre que sea posible, emplee condiciones de búsqueda positivas ("between"), evite lasnegativas ("not between") porque hace más lenta la recuperación de los datos.Entonces, se puede usar el operador "between" para reducir las condiciones "where".32 - Otros operadores relacionales (in)DETALLE DE CONCEPTOSe utiliza "in" para averiguar si el valor de un campo está incluido en una lista de valoresespecificada.En la siguiente sentencia usamos "in" para averiguar si el valor del campo autor está incluido en lalista de valores especificada (en este caso, 2 cadenas).Hasta ahora, para recuperar los libros cuyo autor sea Paenza o Borges usábamos 2 condiciones: select *from libros where autor=Borges or autor=Paenza;Podemos usar "in" y simplificar la consulta: select *from libros where autor in(Borges,Paenza);Para recuperar los libros cuyo autor no sea Paenza ni Borges usábamos: select *from libros where autor<>Borges and autor<>Paenza;También podemos usar "in" anteponiendo "not": select *from libros where autor not in (Borges,Paenza);Empleando "in" averiguamos si el valor del campo está incluido en la lista de valores especificada;con "not" antecediendo la condición, invertimos el resultado, es decir, recuperamos los valores queno se encuentran (coindicen) con la lista de valores.Los valores "null" no se consideran.Recuerde: siempre que sea posible, emplee condiciones de búsqueda positivas ("in"), evite lasnegativas ("not in") porque con ellas se evalún todos los registros y esto hace más lenta larecuperación de los datos.33 - Búsqueda de patrones (like - not like)DETALLE DE CONCEPTOExiste un operador relacional que se usa para realizar comparaciones exclusivamente de cadenas,"like" y "not like".Hemos realizado consultas utilizando operadores relacionales para comparar cadenas. Porejemplo, sabemos recuperar los libros cuyo autor sea igual a la cadena "Borges": select *from libros where autor=Borges;
    • El operador igual ("=") nos permite comparar cadenas de caracteres, pero al realizar lacomparación, busca coincidencias de cadenas completas, realiza una búsqueda exacta.Imaginemos que tenemos registrados estos 2 libros: "El Aleph", "Borges"; "Antologia poetica", "J.L. Borges";Si queremos recuperar todos los libros de "Borges" y especificamos la siguiente condición: select *from libros where autor=Borges;sólo aparecerá el primer registro, ya que la cadena "Borges" no es igual a la cadena "J.L. Borges".Esto sucede porque el operador "=" (igual), también el operador "<>" (distinto) comparan cadenasde caracteres completas. Para comparar porciones de cadenas utilizamos los operadores "like" y"not like".Entonces, podemos comparar trozos de cadenas de caracteres para realizar consultas. Pararecuperar todos los registros cuyo autor contenga la cadena "Borges" debemos tipear: select *from libros where autor like "%Borges%";El símbolo "%" (porcentaje) reemplaza cualquier cantidad de caracteres (incluyendo ningúncaracter). Es un caracter comodín. "like" y "not like" son operadores de comparación que señalanigualdad o diferencia.Para seleccionar todos los libros que comiencen con "M": select *from libros where titulo like M%;Note que el símbolo "%" ya no está al comienzo, con esto indicamos que el título debe tener comoprimera letra la "M" y luego, cualquier cantidad de caracteres.Para seleccionar todos los libros que NO comiencen con "M": select *from libros where titulo not like M%;Así como "%" reemplaza cualquier cantidad de caracteres, el guión bajo "_" reemplaza un caracter,es otro caracter comodín. Por ejemplo, queremos ver los libros de "Lewis Carroll" pero norecordamos si se escribe "Carroll" o "Carrolt", entonces tipeamos esta condición: select *from libros where autor like "%Carrol_";Otro caracter comodín es [] reemplaza cualquier carácter contenido en el conjunto especificadodentro de los corchetes.Para seleccionar los libros cuya editorial comienza con las letras entre la "P" y la "S" usamos lasiguiente sintaxis: select titulo,autor,editorial from libros where editorial like [P-S]%;Ejemplos:... like [a-cf-i]%: busca cadenas que comiencen con a,b,c,f,g,h o i;... like [-acfi]%: busca cadenas que comiencen con -,a,c,f o i;... like A[_]9%: busca cadenas que comiencen con A_9;... like A[nm]%: busca cadenas que comiencen con An o Am.El cuarto caracter comodín es [^] reemplaza cualquier caracter NO presente en el conjuntoespecificado dentro de los corchetes.Para seleccionar los libros cuya editorial NO comienza con las letras "P" ni "N" tipeamos: select titulo,autor,editorial from libros
    • where editorial like [^PN]%;"like" se emplea con tipos de datos char, nchar, varchar, nvarchar o datetime. Si empleamos "like"con tipos de datos que no son caracteres, SQL Server convierte (si es posible) el tipo de dato acaracter. Por ejemplo, queremos buscar todos los libros cuyo precio se encuentre entre 10.00 y19.99: select titulo,precio from libros where precio like 1_.%;Queremos los libros que NO incluyen centavos en sus precios: select titulo,precio from libros where precio like %.00;Para búsquedas de caracteres comodines como literales, debe incluirlo dentro de corchetes, porejemplo, si busca:... like %[%]%: busca cadenas que contengan el signo %;... like %[_]%: busca cadenas que contengan el signo _;... like %[[]%: busca cadenas que contengan el signo [;34 - Contar registros (count)DETALLE DE CONCEPTOExisten en SQL Server funciones que nos permiten contar registros, calcular sumas, promedios,obtener valores máximos y mínimos. Estas funciones se denominan funciones de agregado yoperan sobre un conjunto de valores (registros), no con datos individuales y devuelven un únicovalor.Imaginemos que nuestra tabla "libros" contiene muchos registros. Para averiguar la cantidad sinnecesidad de contarlos manualmente usamos la función "count()": select count(*) from libros;La función "count()" cuenta la cantidad de registros de una tabla, incluyendo los que tienen valornulo.También podemos utilizar esta función junto con la cláusula "where" para una consulta másespecífica. Queremos saber la cantidad de libros de la editorial "Planeta": select count(*) from libros where editorial=Planeta;Para contar los registros que tienen precio (sin tener en cuenta los que tienen valor nulo), usamosla función "count()" y en los paréntesis colocamos el nombre del campo que necesitamos contar: select count(precio) from libros;Note que "count(*)" retorna la cantidad de registros de una tabla (incluyendo los que tienen valor"null") mientras que "count(precio)" retorna la cantidad de registros en los cuales el campo "precio"no es nulo. No es lo mismo. "count(*)" cuenta registros, si en lugar de un asterisco colocamoscomo argumento el nombre de un campo, se contabilizan los registros cuyo valor en ese campoNO es nulo.35 - Contar registros (count_big)DETALLE DE CONCEPTO
    • Retorna la cantidad de registros. Es similar a la función "count(*)", la diferencia es que "count_big"retorna un valor "bigint" y "count", un "int"."count_big(*)" cuenta la cantidad de registros de una tabla, incluyendo los valores nulos yduplicados."count_big(CAMPO)" retorna la cantidad de registros cuyo valor en el campo especificado entreparéntesis no es nulo."count_big(distinct CAMPO)" retorna la cantidad de registros cuyo valor en el campo especificadono es nulo, sin considerar los repetidos.Averiguemos la cantidad de libros usando la función "count_big()": select count_big(*) from libros;Note que incluye todos los libros aunque tengan valor nulo en algún campo.Contamos los libros de editorial "Planeta": select count_big(*) from libros where editorial=Planeta;Contamos los registros que tienen precio (sin tener en cuenta los que tienen valor nulo): select count_big(precio) from libros;Contamos las editoriales (sin repetir): select count_big(distinct editorial) from libros;36 - Funciones de agrupamiento (count - sum - min - max - avg)DETALLE DE CONCEPTOHemos visto que SQL Server tiene funciones que nos permiten contar registros, calcular sumas,promedios, obtener valores máximos y mínimos, las funciones de agregado.Ya hemos aprendido una de ellas, "count()", veamos otras.Se pueden usar en una instrucción "select" y combinarlas con la cláusula "group by".Todas estas funciones retornan "null" si ningún registro cumple con la condición del "where",excepto "count" que en tal caso retorna cero.El tipo de dato del campo determina las funciones que se pueden emplear con ellas.Las relaciones entre las funciones de agrupamiento y los tipos de datos es la siguiente:- count: se puede emplear con cualquier tipo de dato.- min y max: con cualquier tipo de dato.- sum y avg: sólo en campos de tipo numérico.La función "sum()" retorna la suma de los valores que contiene el campo especificado. Siqueremos saber la cantidad total de libros que tenemos disponibles para la venta, debemos sumartodos los valores del campo "cantidad": select sum(cantidad) from libros;Para averiguar el valor máximo o mínimo de un campo usamos las funciones "max()" y "min()"respectivamente.Queremos saber cuál es el mayor precio de todos los libros: select max(precio) from libros;
    • Entonces, dentro del paréntesis de la función colocamos el nombre del campo del cuál queremosel máximo valor.La función "avg()" retorna el valor promedio de los valores del campo especificado. Queremossaber el promedio del precio de los libros referentes a "PHP": select avg(precio) from libros where titulo like %PHP%;Ahora podemos entender porque estas funciones se denominan "funciones de agrupamiento",porque operan sobre conjuntos de registros, no con datos individuales.Tratamiento de los valores nulos:Si realiza una consulta con la función "count" de un campo que contiene 18 registros, 2 de loscuales contienen valor nulo, el resultado devuelve un total de 16 filas porque no considera aquelloscon valor nulo.Todas las funciones de agregado, excepto "count(*)", excluye los valores nulos de los campos."count(*)" cuenta todos los registros, incluidos los que contienen "null".37 - Agrupar registros (group by)DETALLE DE CONCEPTOHemos aprendido que las funciones de agregado permiten realizar varios cálculos operando conconjuntos de registros.Las funciones de agregado solas producen un valor de resumen para todos los registros de uncampo. Podemos generar valores de resumen para un solo campo, combinando las funciones deagregado con la cláusula "group by", que agrupa registros para consultas detalladas.Queremos saber la cantidad de libros de cada editorial, podemos tipear la siguiente sentencia: select count(*) from libros where editorial=Planeta;y repetirla con cada valor de "editorial": select count(*) from libros where editorial=Emece; select count(*) from libros where editorial=Paidos; ...Pero hay otra manera, utilizando la cláusula "group by": select editorial, count(*) from libros group by editorial;La instrucción anterior solicita que muestre el nombre de la editorial y cuente la cantidadagrupando los registros por el campo "editorial". Como resultado aparecen los nombres de laseditoriales y la cantidad de registros para cada valor del campo.Los valores nulos se procesan como otro grupo.Entonces, para saber la cantidad de libros que tenemos de cada editorial, utilizamos la función"count()", agregamos "group by" (que agrupa registros) y el campo por el que deseamos que serealice el agrupamiento, también colocamos el nombre del campo a recuperar; la sintaxis básica esla siguiente: select CAMPO, FUNCIONDEAGREGADO from NOMBRETABLA
    • group by CAMPO;También se puede agrupar por más de un campo, en tal caso, luego del "group by" se listan loscampos, separados por comas. Todos los campos que se especifican en la cláusula "group by"deben estar en la lista de selección. select CAMPO1, CAMPO2, FUNCIONDEAGREGADO from NOMBRETABLA group by CAMPO1,CAMPO2;Para obtener la cantidad libros con precio no nulo, de cada editorial utilizamos la función "count()"enviándole como argumento el campo "precio", agregamos "group by" y el campo por el quedeseamos que se realice el agrupamiento (editorial): select editorial, count(precio) from libros group by editorial;Como resultado aparecen los nombres de las editoriales y la cantidad de registros de cada una, sincontar los que tienen precio nulo.Recuerde la diferencia de los valores que retorna la función "count()" cuando enviamos comoargumento un asterisco o el nombre de un campo: en el primer caso cuenta todos los registrosincluyendo los que tienen valor nulo, en el segundo, los registros en los cuales el campoespecificado es no nulo.Para conocer el total en dinero de los libros agrupados por editorial: select editorial, sum(precio) from libros group by editorial;Para saber el máximo y mínimo valor de los libros agrupados por editorial: select editorial, max(precio) as mayor, min(precio) as menor from libros group by editorial;Para calcular el promedio del valor de los libros agrupados por editorial: select editorial, avg(precio) from libros group by editorial;Es posible limitar la consulta con "where".Si incluye una cláusula "where", sólo se agrupan los registros que cumplen las condiciones.Vamos a contar y agrupar por editorial considerando solamente los libros cuyo precio sea menor a30 pesos: select editorial, count(*) from libros where precio<30 group by editorial;Note que las editoriales que no tienen libros que cumplan la condición, no aparecen en la salida.Para que aparezcan todos los valores de editorial, incluso los que devuelven cero o "null" en lacolumna de agregado, debemos emplear la palabra clave "all" al lado de "group by": select editorial, count(*) from libros where precio<30 group by all editorial;
    • Entonces, usamos "group by" para organizar registros en grupos y obtener un resumen de dichosgrupos. SQL Server produce una columna de valores por cada grupo, devolviendo filas por cadagrupo especificado.38 - Seleccionar grupos (having)DETALLE DE CONCEPTOAsí como la cláusula "where" permite seleccionar (o rechazar) registros individuales; la cláusula"having" permite seleccionar (o rechazar) un grupo de registros.Si queremos saber la cantidad de libros agrupados por editorial usamos la siguiente instrucción yaaprendida: select editorial, count(*) from libros group by editorial;Si queremos saber la cantidad de libros agrupados por editorial pero considerando sólo algunosgrupos, por ejemplo, los que devuelvan un valor mayor a 2, usamos la siguiente instrucción: select editorial, count(*) from libros group by editorial having count(*)>2;Se utiliza "having", seguido de la condición de búsqueda, para seleccionar ciertas filas retornadaspor la cláusula "group by".Veamos otros ejemplos. Queremos el promedio de los precios de los libros agrupados por editorial,pero solamente de aquellos grupos cuyo promedio supere los 25 pesos: select editorial, avg(precio) from libros group by editorial having avg(precio)>25;En algunos casos es posible confundir las cláusulas "where" y "having". Queremos contar losregistros agrupados por editorial sin tener en cuenta a la editorial "Planeta".Analicemos las siguientes sentencias: select editorial, count(*) from libros where editorial<>Planeta group by editorial; select editorial, count(*) from libros group by editorial having editorial<>Planeta;Ambas devuelven el mismo resultado, pero son diferentes. La primera, selecciona todos losregistros rechazando los de editorial "Planeta" y luego los agrupa para contarlos. La segunda,selecciona todos los registros, los agrupa para contarlos y finalmente rechaza fila con la cuentacorrespondiente a la editorial "Planeta".No debemos confundir la cláusula "where" con la cláusula "having"; la primera establececondiciones para la selección de registros de un "select"; la segunda establece condiciones para laselección de registros de una salida "group by".Veamos otros ejemplos combinando "where" y "having". Queremos la cantidad de libros, sinconsiderar los que tienen precio nulo, agrupados por editorial, sin considerar la editorial "Planeta":
    • select editorial, count(*) from libros where precio is not null group by editorial having editorial<>Planeta;Aquí, selecciona los registros rechazando los que no cumplan con la condición dada en "where",luego los agrupa por "editorial" y finalmente rechaza los grupos que no cumplan con la condicióndada en el "having".Se emplea la cláusula "having" con funciones de agrupamiento, esto no puede hacerlo la cláusula"where". Por ejemplo queremos el promedio de los precios agrupados por editorial, de aquellaseditoriales que tienen más de 2 libros: select editorial, avg(precio) from libros group by editorial having count(*) > 2;En una cláusula "having" puede haber hasta 128 condiciones. Cuando utilice varias condiciones,tiene que combinarlas con operadores lógicos (and, or, not).Podemos encontrar el mayor valor de los libros agrupados y ordenados por editorial y seleccionarlas filas que tengan un valor menor a 100 y mayor a 30: select editorial, max(precio) as mayor from libros group by editorial having min(precio)<100 and min(precio)>30 order by editorial;Entonces, usamos la claúsula "having" para restringir las filas que devuelve una salida "group by".Va siempre después de la cláusula "group by" y antes de la cláusula "order by" si la hubiere.39 - Modificador del group by (with rollup)DETALLE DE CONCEPTOPodemos combinar "group by" con los operadores "rollup" y "cube" para generar valores deresumen a la salida.El operador "rollup" resume valores de grupos. representan los valores de resumen de laprecedente.Tenemos la tabla "visitantes" con los siguientes campos: nombre, edad, sexo, domicilio, ciudad,telefono, montocompra.Si necesitamos la cantidad de visitantes por ciudad empleamos la siguiente sentencia: select ciudad,count(*) as cantidad from visitantes group by ciudad;Esta consulta muestra el total de visitantes agrupados por ciudad; pero si queremos además lacantidad total de visitantes, debemos realizar otra consulta: select count(*) as total from visitantes;Para obtener ambos resultados en una sola consulta podemos usar "with rollup" que nos devolveráambas salidas en una sola consulta: select ciudad,count(*) as cantidad from visitantes
    • group by ciudad with rollup;La consulta anterior retorna los registros agrupados por ciudad y una fila extra en la que la primeracolumna contiene "null" y la columna con la cantidad muestra la cantidad total.La cláusula "group by" permite agregar el modificador "with rollup", el cual agrega registros extrasal resultado de una consulta, que muestran operaciones de resumen.Si agrupamos por 2 campos, "ciudad" y "sexo": select ciudad,sexo,count(*) as cantidad from visitantes group by ciudad,sexo with rollup;La salida muestra los totales por ciudad y sexo y produce tantas filas extras como valores existendel primer campo por el que se agrupa ("ciudad" en este caso), mostrando los totales para cadavalor, con la columna correspondiente al segundo campo por el que se agrupa ("sexo" en esteejemplo) conteniendo "null", y 1 fila extra mostrando el total de todos los visitantes (con lascolumnas correspondientes a ambos campos conteniendo "null"). Es decir, por cada agrupación,aparece una fila extra con el/ los campos que no se consideran, seteados a "null".Con "rollup" se puede agrupar hasta por 10 campos.Es posible incluir varias funciones de agrupamiento, por ejemplo, queremos la cantidad devisitantes y la suma de sus compras agrupados por ciudad y sexo: select ciudad,sexo, count(*) as cantidad, sum(montocompra) as total from visitantes group by ciudad,sexo with rollup;Entonces, "rollup" es un modificador para "group by" que agrega filas extras mostrando resultadosde resumen de los subgrupos. Si se agrupa por 2 campos SQL Server genera tantas filas extrascomo valores existen del primer campo (con el segundo campo seteado a "null") y una fila extracon ambos campos conteniendo "null".Con "rollup" se puede emplear "where" y "having", pero no es compatible con "all".40 - Modificador del group by (with cube)DETALLE DE CONCEPTOHemos aprendido el modificador "rollup", que agrega filas extras mostrando resultados de resumenpor cada grupo y subgrupo.Por ejemplo, tenemos una tabla llamada "empleados" que contiene, entre otros, los campos "sexo","estadocivil" y "seccion".Si se agrupa por esos tres campos (en ese orden) y se emplea "rollup": select sexo,estadocivil,seccion, count(*) from empleados group by sexo,estadocivil,seccion with rollup;SQL Server genera varias filas extras con información de resumen para los siguientes subgrupos:- sexo y estadocivil (seccion seteado a "null"),- sexo (estadocivil y seccion seteados a "null") y- total (todos los campos seteados a "null").Si se emplea "cube":
    • select sexo,estadocivil,seccion, count(*) from empleados group by sexo,estadocivil,seccion with cube;retorna más filas extras además de las anteriores:- sexo y seccion (estadocivil seteado a "null"),- estadocivil y seccion (sexo seteado a "null"),- seccion (sexo y estadocivil seteados a "null") y- estadocivil (sexo y seccion seteados a "null"),Es decir, "cube" genera filas de resumen de subgrupos para todas las combinaciones posibles delos valores de los campos por los que agrupamos.Se pueden colocar hasta 10 campos en el "group by".Con "cube" se puede emplear "where" y "having", pero no es compatible con "all".41 - Función groupingDETALLE DE CONCEPTOLa función "grouping" se emplea con los operadores "rollup" y "cube" para distinguir los valores dedetalle y de resumen en el resultado. Es decir, permite diferenciar si los valores "null" que aparecenen el resultado son valores nulos de las tablas o si son una fila generada por los operadores"rollup" o "cube".Con esta función aparece una nueva columna en la salida, una por cada "grouping"; retorna elvalor 1 para indicar que la fila representa los valores de resumen de "rollup" o "cube" y el valor 0para representar los valores de campo.Sólo se puede emplear la función "grouping" en los campos que aparecen en la cláusula "groupby".Si tenemos una tabla "visitantes" con los siguientes registros almacenados:Nombre sexo ciudad-------------------------------Susana Molina f CordobaMarcela Mercado f CordobaRoberto Perez f nullAlberto Garcia m CordobaTeresa Garcia f Alta Graciay contamos la cantidad agrupando por ciudad (note que hay un valor nulo en dicho campo)empleando "rollup": select ciudad, count(*) as cantidad from visitantes group by ciudad with rollup;aparece la siguiente salida:ciudad cantidad-------------------------NULL 1Alta Gracia 1Cordoba 3
    • NULL 5La última fila es la de resumen generada por "rollup", pero no es posible distinguirla de la primerafila, en la cual "null" es un valor del campo. Para diferenciarla empleamos "grouping": select ciudad, count(*) as cantidad, grouping(ciudad) as resumen from visitantes group by ciudad with rollup;aparece la siguiente salida:ciudad cantidad resumen---------------------------------------NULL 1 0Alta Gracia 1 0Cordoba 3 0NULL 5 1La última fila contiene en la columna generada por "grouping" el valor 1, indicando que es la fila deresumen generada por "rollup"; la primera fila, contiene en dicha columna el valor 0, que indica queel valor "null" es un valor del campo "ciudad".Entonces, si emplea los operadores "rollup" y "cube" y los campos por los cuales agrupa admitenvalores nulos, utilice la función "grouping" para distinguir los valores de detalle y de resumen en elresultado.PROBLEMA RESUELTOProblema:Un comercio que tiene un stand en una feria registra en una tabla llamada "visitantes" algunosdatos de las personas que visitan o compran en su stand para luego enviarle publicidad de susproductos.Eliminamos la tabla si existe: if object_id(visitantes) is not null drop table visitantes;La creamos con la siguiente estructura: create table visitantes( nombre varchar(30), sexo char(1), ciudad varchar(20) );Ingresamos algunos registros: insert into visitantes values(Susana Molina, f, Cordoba); insert into visitantes values(Marcela Mercado, f,Cordoba); insert into visitantes values(Roberto Perez,f,null); insert into visitantes values(Alberto Garcia,m,Cordoba); insert into visitantes values(Teresa Garcia,f,Alta Gracia);Contamos la cantidad de visitantes agrupando por ciudad y empleando "rollup": select ciudad, count(*) as cantidad from visitantes group by ciudad
    • with rollup;Note que la última fila es la de resumen generada por "rollup", pero no es sencillo distinguirla de laprimera fila, en la cual "null" es un valor del campo. Para diferenciarla empleamos "grouping": select ciudad, count(*) as cantidad, grouping(ciudad) as resumen from visitantes group by ciudad with rollup;Note que la última fila contiene en la columna generada por "grouping" el valor 1, indicando que esla fila de resumen generada por "rollup"; la primera fila, contiene en dicha columna el valor 0, locual indica que el valor "null" es un valor del campo "ciudad".42 - Cláusulas compute y compute byDETALLE DE CONCEPTOLas cláusulas "compute" y "compute by" generan totales que aparecen en columnas extras al finaldel resultado.Produce filas de detalle y un valor único para una columna.Se usa con las funciones de agrupamiento: avg(), count(), max(), min(), sum().La sintaxis básica y general es la siguiente: select CAMPOS from TABLA compute FUNCION(CAMPO);El campo que se coloque en la cláusula "compute" debe estar incluida en la lista de campos del"select".Para ver todos los datos de los visitantes y el promedio del monto de compra de nuestra tabla"visitantes": select *from visitantes compute avg(montocompra);Produce la misma salida que las siguientes 2 sentencias: select *from visitantes; select avg(montocompra) from visitantes;En una misma instrucción se pueden colocar varias cláusulas "compute": select edad,ciudad,montocompra from visitantes compute avg(edad),sum(montocompra);"Compute by" genera cortes de control y subtotales. Se generan filas de detalle y varios valores deresumen cuando cambian los valores del campo.Con "compute by" se DEBE usar también la cláusula "order by" y los campos que se incluyan luegode "by" deben estar en el "order by". Listando varios campos luego del "by" corta un grupo ensubgrupos y aplica la función de agregado en cada nivel de agrupamiento: select nombre,ciudad,provincia from visitantes order by provincia compute count(provincia) by provincia;
    • select nombre,ciudad,provincia from visitantes order by provincia,ciudad compute count(provincia) by provincia,ciudad;Los campos que aparecen luego de la cláusula "compute by" DEBEN ser idénticos a unsubconjunto de los campos que aparecen después de "order by" y estar en el mismo orden. Si lacláusula "order by" tiene los siguientes campos:... order by a,b,c...la cláusula "compute by" puede incluir los siguientes subconjuntos de campos:... compute ... by a...o... compute ... by a,b...o... compute ... by a,b,c...En una misma instrucción se pueden colocar varias cláusulas "compute" combinadas con variascláusulas "compute by": select *from visitantes order by provincia,ciudad compute avg(edad), sum(montocompra) compute avg(montocompra),count(provincia) by provincia,ciudad;El resultado de la consulta anterior muestra el promedio de la compra y la cantidad al final de cadasubgrupo de provincia y ciudad (compute by) y el promedio de las edades y el total del monto decompras de todos (compute).Los tipos de datos ntext, text e image no se pueden incluir en una cláusula "compute" o "computeby".43 - Registros duplicados (distinct)DETALLE DE CONCEPTOCon la cláusula "distinct" se especifica que los registros con ciertos datos duplicados seanobviadas en el resultado. Por ejemplo, queremos conocer todos los autores de los cuales tenemoslibros, si utilizamos esta sentencia: select autor from libros;Aparecen repetidos. Para obtener la lista de autores sin repetición usamos: select distinct autor from libros;También podemos tipear: select autor from libros group by autor;Note que en los tres casos anteriores aparece "null" como un valor para "autor"· Si sólo queremosla lista de autores conocidos, es decir, no queremos incluir "null" en la lista, podemos utilizar lasentencia siguiente: select distinct autor from libros
    • where autor is not null;Para contar los distintos autores, sin considerar el valor "null" usamos: select count(distinct autor) from libros;Note que si contamos los autores sin "distinct", no incluirá los valores "null" pero si los repetidos: select count(autor) from libros;Esta sentencia cuenta los registros que tienen autor.Podemos combinarla con "where". Por ejemplo, queremos conocer los distintos autores de laeditorial "Planeta": select distinct autor from libros where editorial=Planeta;También puede utilizarse con "group by" para contar los diferentes autores por editorial: select editorial, count(distinct autor) from libros group by editorial;La cláusula "distinct" afecta a todos los campos presentados. Para mostrar los títulos y editorialesde los libros sin repetir títulos ni editoriales, usamos: select distinct titulo,editorial from libros order by titulo;Note que los registros no están duplicados, aparecen títulos iguales pero con editorial diferente,cada registro es diferente.La palabra clave "distinct" no está permitida con las cláusulas "compute" y "compute by".Entonces, "distinct" elimina registros duplicados.PROBLEMA RESUELTOProblema:Trabajamos con la tabla "libros" de una librería.Eliminamos la tabla, si existe: if object_id(libros) is not null drop table libros;Creamos la tabla: create table libros( codigo int identity, titulo varchar(40), autor varchar(30), editorial varchar(15), primary key(codigo) );Ingresamos algunos registros: insert into libros values(El aleph,Borges,Planeta); insert into libros values(Martin Fierro,Jose Hernandez,Emece); insert into libros values(Martin Fierro,Jose Hernandez,Planeta); insert into libros
    • values(Antologia poetica,Borges,Planeta); insert into libros values(Aprenda PHP,Mario Molina,Emece); insert into libros values(Aprenda PHP,Lopez,Emece); insert into libros values(Manual de PHP, J. Paez, null); insert into libros values(Cervantes y el quijote,null,Paidos); insert into libros values(Harry Potter y la piedra filosofal,J.K. Rowling,Emece); insert into libros values(Harry Potter y la camara secreta,J.K. Rowling,Emece); insert into libros values(Alicia en el pais de las maravillas,Lewis Carroll,Paidos); insert into libros values(Alicia en el pais de las maravillas,Lewis Carroll,Planeta); insert into libros values(PHP de la A a la Z,null,null); insert into libros values(Uno,Richard Bach,Planeta);Para obtener la lista de autores sin repetición tipeamos: select distinct autor from libros;Note que aparece "null" como un valor para "autor"· Para obtener la lista de autores conocidos, esdecir, no incluyendo "null" en la lista: select distinct autor from libros where autor is not null;Contamos los distintos autores: select count(distinct autor) from libros;Queremos los nombres de las editoriales sin repetir: select distinct editorial from libros;Queremos saber la cantidad de editoriales distintas: select count(distinct editorial) from libros;La combinamos con "where" para obtener los distintos autores de la editorial "Planeta": select distinct autor from libros where editorial=Planeta;Contamos los distintos autores que tiene cada editorial empleando "group by": select editorial,count(distinct autor) from libros group by editorial;Mostramos los títulos y editoriales de los libros sin repetir títulos ni editoriales: select distinct titulo,editorial from libros order by titulo;Note que los registros no están duplicados, aparecen títulos iguales pero con editorial diferente,cada registro es diferente.
    • 44 - Cláusula topDETALLE DE CONCEPTOLa palabra clave "top" se emplea para obtener sólo una cantidad limitada de registros, los primerosn registros de una consulta.Con la siguiente consulta obtenemos todos los datos de los primeros 2 libros de la tabla: select top 2 *from libros;Es decir, luego del "select" se coloca "top" seguido de un número entero positivo y luego secontinúa con la consulta.Se puede combinar con "order by": select top 3 titulo,autor from libros order by autor;En la consulta anterior solicitamos los títulos y autores de los 3 primeros libros, ordenados porautor.Cuando se combina con "order by" es posible emplear también la cláusula "with ties". Esta cláusulapermite incluir en la seleccion, todos los registros que tengan el mismo valor del campo por el quese ordena, que el último registro retornado si el último registro retornado (es decir, el número n)tiene un valor repetido en el registro n+1. Es decir, si el valor del campo por el cual se ordena delúltimo registro retornado (el número n) está repetido en los siguientes registros (es decir, el n+1tiene el mismo valor que n, y el n+2, etc.), lo incluye en la selección.Veamos un ejemplo: select top 3 with ties *from libros order by autor;Esta consulta solicita el retorno de los primeros 3 registros; en caso que el registro número 4 (y losposteriores), tengan el mismo valor en "autor" que el último registro retornado (número 3), tambiénaparecerán en la selección.Si colocamos un valor para "top" que supera la cantidad de registros de la tabla, SQL Servermuestra todos los registros.45 - Clave primaria compuestaDETALLE DE CONCEPTOLas claves primarias pueden ser simples, formadas por un solo campo o compuestas, más de uncampo.Recordemos que una clave primaria identifica 1 solo registro en una tabla.Para un valor del campo clave existe solamente 1 registro. Los valores no se repiten ni pueden sernulos.Existe una playa de estacionamiento que almacena cada día los datos de los vehículos queingresan en la tabla llamada "vehiculos" con los siguientes campos: - patente char(6) not null, - tipo char (1), a= auto, m=moto, - horallegada datetime, - horasalida datetime,Necesitamos definir una clave primaria para una tabla con los datos descriptos arriba. No podemosusar solamente la patente porque un mismo auto puede ingresar más de una vez en el día a laplaya; tampoco podemos usar la hora de entrada porque varios autos pueden ingresar a una
    • misma hora.Tampoco sirven los otros campos.Como ningún campo, por si sólo cumple con la condición para ser clave, es decir, debe identificarun solo registro, el valor no puede repetirse, debemos usar 2 campos.Definimos una clave compuesta cuando ningún campo por si solo cumple con la condición para serclave.En este ejemplo, un auto puede ingresar varias veces en un día a la playa, pero siempre será adistinta hora.Usamos 2 campos como clave, la patente junto con la hora de llegada, así identificamosunívocamente cada registro.Para establecer más de un campo como clave primaria usamos la siguiente sintaxis: create table vehiculos( patente char(6) not null, tipo char(1),--a=auto, m=moto horallegada datetime, horasalida datetime, primary key(patente,horallegada) );Nombramos los campos que formarán parte de la clave separados por comas.Al ingresar los registros, SQL Server controla que los valores para los campos establecidos comoclave primaria no estén repetidos en la tabla; si estuviesen repetidos, muestra un mensaje y lainserción no se realiza. Lo mismo sucede si realizamos una actualización.Entonces, si un solo campo no identifica unívocamente un registro podemos definir una claveprimaria compuesta, es decir formada por más de un campo.46 - Integridad de los datosDETALLE DE CONCEPTOEs importante, al diseñar una base de datos y las tablas que contiene, tener en cuenta la integridadde los datos, esto significa que la información almacenada en las tablas debe ser válida, coherentey exacta.Hasta el momento, hemos controlado y restringido la entrada de valores a un campo mediante eltipo de dato que le definimos (cadena, numéricos, etc.), la aceptación o no de valores nulos, elvalor por defecto. También hemos asegurado que cada registro de una tabla sea único definiendouna clave primaria y empleando la propiedad identity.SQL Server ofrece más alternativas, además de las aprendidas, para restringir y validar los datos,las veremos ordenadamente y al finalizar haremos un resumen de las mismas.Comenzamos por las restricciones.Las restricciones (constraints) son un método para mantener la integridad de los datos,asegurando que los valores ingresados sean válidos y que las relaciones entre las tablas semantenga. Se establecen a los campos y las tablas.Pueden definirse al crear la tabla ("create table") o agregarse a una tabla existente (empleando"alter table") y se pueden aplicar a un campo o a varios. Se aconseja crear las tablas y luegoagregar las restricciones.Se pueden crear, modificar y eliminar las restricciones sin eliminar la tabla y volver a crearla.El procedimiento almacenado del sistema "sp_helpconstraint" junto al nombre de la tabla, nosmuestra información acerca de las restricciones de dicha tabla.
    • Cuando se agrega una restricción a una tabla, SQL Server comprueba los datos existentes.Hay varios tipos de restricciones.47 - Restricción defaultDETALLE DE CONCEPTOLa restricción "default" especifica un valor por defecto para un campo cuando no se insertaexplícitamente en un comando "insert".Anteriormente, para establecer un valor por defecto para un campo empleábamos la cláusula"default" al crear la tabla, por ejemplo: create table libros( ... autor varchar(30) default Desconocido, ... );Cada vez que establecíamos un valor por defecto para un campo de una tabla, SQL Server creabaautomáticamente una restricción "default" para ese campo de esa tabla.Dicha restricción, a la cual no le dábamos un nombre, recibía un nombre dado por SQL Server queconsiste "DF" (por default), seguido del nombre de la tabla, el nombre del campo y letras ynúmeros aleatorios.Podemos agregar una restricción "default" a una tabla existente con la sintaxis básica siguiente: alter table NOMBRETABLA add constraint NOMBRECONSTRAINT default VALORPORDEFECTO for CAMPO;En la sentencia siguiente agregamos una restricción "default" al campo autor de la tabla existente"libros", que almacena el valor "Desconocido" en dicho campo si no ingresamos un valor en un"insert": alter table libros add constraint DF_libros_autor default Desconocido for autor;Por convención, cuando demos el nombre a las restricciones "default" emplearemos un formatosimilar al que le da SQL Server: "DF_NOMBRETABLA_NOMBRECAMPO".Solamente se permite una restricción "default" por campo y no se puede emplear junto con lapropiedad "identity". Una tabla puede tener varias restricciones "default" para sus distintos campos.La restricción "default" acepta valores tomados de funciones del sistema, por ejemplo, podemosestablecer que el valor por defecto de un campo de tipo datetime sea "getdate()".Podemos ver información referente a las restriciones de una tabla con el procedimientoalmacenado "sp_helpcontraint": sp_helpconstraint libros;aparecen varias columnas con la siguiente información:- constraint_type: el tipo de restricción y sobre qué campo está establecida (DEFAULT on column autor),- constraint_name: el nombre de la restricción (DF_libros_autor),- delete_action y update_action: no tienen valores para este tipo de restricción.- status_enabled y status_for_replication: no tienen valores para este tipo
    • de restricción.- constraint_keys: el valor por defecto (Desconocido).Entonces, la restricción "default" especifica un valor por defecto para un campo cuando no seinserta explícitamente en un "insert", se puede establecer uno por campo y no se puede emplearjunto con la propiedad "identity".48 - Restricción checkDETALLE DE CONCEPTOLa restricción "check" especifica los valores que acepta un campo, evitando que se ingresenvalores inapropiados.La sintaxis básica es la siguiente: alter table NOMBRETABLA add constraint NOMBRECONSTRAINT check CONDICION;Trabajamos con la tabla "libros" de una librería que tiene los siguientes campos: codigo, titulo,autor, editorial, preciomin (que indica el precio para los minoristas) y preciomay (que indica elprecio para los mayoristas).Los campos correspondientes a los precios (minorista y mayorista) se definen de tipo decimal(5,2),es decir, aceptan valores entre -999.99 y 999.99. Podemos controlar que no se ingresen valoresnegativos para dichos campos agregando una restricción "check": alter table libros add constraint CK_libros_precio_positivo check (preciomin>=0 and preciomay>=0);Este tipo de restricción verifica los datos cada vez que se ejecuta una sentencia "insert" o "update",es decir, actúa en inserciones y actualizaciones.Si la tabla contiene registros que no cumplen con la restricción que se va a establecer, larestricción no se puede establecer, hasta que todos los registros cumplan con dicha restricción.La condición puede hacer referencia a otros campos de la misma tabla. Por ejemplo, podemoscontrolar que el precio mayorista no sea mayor al precio minorista: alter table libros add constraint CK_libros_preciominmay check (preciomay<=preciomin);Por convención, cuando demos el nombre a las restricciones "check" seguiremos la mismaestructura: comenzamos con "CK", seguido del nombre de la tabla, del campo y alguna palabracon la cual podamos identificar fácilmente de qué se trata la restricción, por si tenemos variasrestricciones "check" para el mismo campo.Un campo puede tener varias restricciones restricciones "check" y una restricción "check" puedeincluir varios campos.Las condiciones para restricciones "check" también pueden pueden incluir un patrón o una lista devalores. Por ejemplo establecer que cierto campo conste de 4 caracteres, 2 letras y 2 dígitos: ... check (CAMPO like [A-Z][A-Z][0-9][0-9]);O establecer que cierto campo asuma sólo los valores que se listan: ... check (CAMPO in (lunes,miercoles,viernes));No se puede aplicar esta restricción junto con la propiedad "identity".
    • Si un campo permite valores nulos, "null" es un valor aceptado aunque no esté incluido en lacondición de restricción.Si intentamos establecer una restricción "check" para un campo que entra en conflicto con otrarestricción "check" establecida al mismo campo, SQL Server no lo permite.Pero si establecemos una restricción "check" para un campo que entra en conflicto con unarestricción "default" establecida para el mismo campo, SQL Server lo permite; pero al intentaringresar un registro, aparece un mensaje de error.PROBLEMA RESUELTOProblema:Trabajamos con la tabla "libros" de una librería.Eliminamos la tabla, si existe: if object_id(libros) is not null drop table libros;La creamos e ingresamos algunos registros: create table libros( codigo int identity, titulo varchar(40), autor varchar(30), editorial varchar(15), preciomin decimal(5,2), preciomay decimal(5,2) ); insert into libros values (Uno,Bach,Planeta,22,20); insert into libros values (El quijote,Cervantes,Emece,15,13); insert into libros values (Aprenda PHP,Mario Molina,Siglo XXI,48,53); insert into libros values (Java en 10 minutos,Garcia,Siglo XXI,35,40);Agregamos una restricción "check" para asegurar que los valores de los campos correspondientesa precios no puedan ser negativos: alter table libros add constraint CK_libros_precios_positivo check (preciomin>=0 and preciomay>=0);Si intentamos ingresar un valor inválido para algún campo correspondiente al precio, que vaya encontra de la restricción, por ejemplo el valor "-15" aparecerá un mensaje de error indicando quehay conflicto con la restricción creada anteriormente y la inserción no se realiza. Igualmente siintentamos actualizar un precio, que vaya en contra de la restricción.Si intentamos agregar una restricción que no permita que el precio mayorista supere el preciominorista, aparece un mensaje de error y la sentencia no se ejecuta, porque hay registros que nocumplen con la restricción que intentamos establecer. Podemos modificar los datos que nocumplen la condición de la restricción o eliminar los registros: update libros set preciomay=48 where titulo=Aprenda PHP; delete from libros where titulo=Java en 10 minutos;Ahora SQL Server si nos permite agregar la restricción "check" que impida que se ingresen valorespara "preciomay" superiores a "preciomin": alter table libros add constraint CK_libros_preciominmay
    • check (preciomay<=preciomin);Veamos las restricciones de la tabla: sp_helpconstraint libros;Ingresamos un registro con valores por defecto: insert into libros default values;Note que los campos correspondientes a precios admiten valores 0 y 999.99 (por el tipo de dato yla restricción), además del valor "null".49 - Deshabilitar restricciones (with check - nocheck)DETALLE DE CONCEPTOSabemos que si agregamos una restricción a una tabla que contiene datos, SQL Server loscontrola para asegurarse que cumplen con la condición de la restricción, si algún registro no lacumple, la restricción no se establecece.Es posible deshabilitar esta comprobación en caso de restricciones "check".Podemos hacerlo cuando agregamos la restricción "check" a una tabla para que SQL Serveracepte los valores ya almacenados que infringen la restricción. Para ello debemos incluir la opción"with nocheck" en la instrucción "alter table": alter table libros with nocheck add constraint CK_libros_precio check (precio>=0);La restricción no se aplica en los datos existentes, pero si intentamos ingresar un nuevo valor queno cumpla la restricción, SQL Server no lo permite.Entonces, para evitar la comprobación de datos existentes al crear la restricción, la sintaxis básicaes la siguiente: alter table TABLA with nocheck add constraint NOMBRERESTRICCION check (CONDICION);Por defecto, si no especificamos, la opción es "with check".También podemos deshabilitar las restricciones para agregar o actualizar datos sin comprobarla: alter table libros nocheck constraint CK_libros_precio;En el ejemplo anterior deshabilitamos la restricción "CK_libros_precio" para poder ingresar un valornegativo para "precio".Para habilitar una restricción deshabilitada se ejecuta la misma instrucción pero con la cláusula"check" o "check all": alter table libros check constraint CK_libros_precio;Si se emplea "check constraint all" no se coloca nombre de restricciones, habilita todas lasrestricciones que tiene la tabla nombrada.Para habilitar o deshabilitar restricciones la comprobación de datos en inserciones oactualizaciones, la sintaxis básica es: alter table NOMBRETABLA OPCIONdeRESTRICCION constraint NOMBRERESTRICCION;
    • Para saber si una restricción está habilitada o no, podemos ejecutar el procedimiento almacenado"sp_helpconstraint" y fijarnos lo que informa la columna "status_enabled".Entonces, las cláusulas "check" y "nocheck" permiten habilitar o deshabilitar restricciones "check"(también las restricciones "foreign key" que veremos más adelante), a las demás se las debeeliminar ("default" y las que veremos posteriormente).50 - Restricción primary keyDETALLE DE CONCEPTOHemos visto las restricciones que se aplican a los campos, "default" y "check".Ahora veremos las restricciones que se aplican a las tablas, que aseguran valores únicos paracada registro.Hay 2 tipos: 1) primary key y 2) unique.Anteriormente, para establecer una clave primaria para una tabla empleábamos la siguientesintaxis al crear la tabla, por ejemplo: create table libros( codigo int not null, titulo varchar(30), autor varchar(30), editorial varchar(20), primary key(codigo) );Cada vez que establecíamos la clave primaria para la tabla, SQL Server creaba automáticamenteuna restricción "primary key" para dicha tabla. Dicha restricción, a la cual no le dábamos unnombre, recibía un nombre dado por SQL Server que comienza con "PK" (por primary key),seguido del nombre de la tabla y una serie de letras y números aleatorios.Podemos agregar una restricción "primary key" a una tabla existente con la sintaxis básicasiguiente: alter table NOMBRETABLA add constraint NOMBRECONSTRAINT primary key (CAMPO,...);En el siguiente ejemplo definimos una restricción "primary key" para nuestra tabla "libros" paraasegurarnos que cada libro tendrá un código diferente y único: alter table libros add constraint PK_libros_codigo primary key(codigo);Con esta restricción, si intentamos ingresar un registro con un valor para el campo "codigo" que yaexiste o el valor "null", aparece un mensaje de error, porque no se permiten valores duplicados ninulos. Igualmente, si actualizamos.Por convención, cuando demos el nombre a las restricciones "primary key" seguiremos el formato"PK_NOMBRETABLA_NOMBRECAMPO".Sabemos que cuando agregamos una restricción a una tabla que contiene información, SQLServer controla los datos existentes para confirmar que cumplen las exigencias de la restricción, sino los cumple, la restricción no se aplica y aparece un mensaje de error. Por ejemplo, siintentamos definir la restricción "primary key" para "libros" y hay registros con códigos repetidos ocon un valor "null", la restricción no se establece.Cuando establecíamos una clave primaria al definir la tabla, automáticamente SQL Server redefiníael campo como "not null"; pero al agregar una restricción "primary key", los campos que son clave
    • primaria DEBEN haber sido definidos "not null" (o ser implícitamente "not null" si se definenidentity).SQL Server permite definir solamente una restricción "primary key" por tabla, que asegura launicidad de cada registro de una tabla.Si ejecutamos el procedimiento almacenado "sp_helpconstraint" junto al nombre de la tabla,podemos ver las restricciones "primary key" (y todos los tipos de restricciones) de dicha tabla.Un campo con una restricción "primary key" puede tener una restricción "check".Un campo "primary key" también acepta una restricción "default" (excepto si es identity), pero notiene sentido ya que el valor por defecto solamente podrá ingresarse una vez; si intenta ingresarsecuando otro registro ya lo tiene almacenado, aparecerá un mensaje de error indicando que seintenta duplicar la clave.51 - Restricción uniqueDETALLE DE CONCEPTOHemos visto que las restricciones aplicadas a tablas aseguran valores únicos para cada registro.Anteriormente aprendimos la restricción "primary key", otra restricción para las tablas es "unique".La restricción "unique" impide la duplicación de claves alternas (no primarias), es decir, especificaque dos registros no puedan tener el mismo valor en un campo. Se permiten valores nulos. Sepueden aplicar varias restricciones de este tipo a una misma tabla, y pueden aplicarse a uno ovarios campos que no sean clave primaria.Se emplea cuando ya se estableció una clave primaria (como un número de legajo) pero senecesita asegurar que otros datos también sean únicos y no se repitan (como número dedocumento).La sintaxis general es la siguiente: alter table NOMBRETABLA add constraint NOMBRERESTRICCION unique (CAMPO);Ejemplo: alter table alumnos add constraint UQ_alumnos_documento unique (documento);En el ejemplo anterior se agrega una restricción "unique" sobre el campo "documento" de la tabla"alumnos", esto asegura que no se pueda ingresar un documento si ya existe. Esta restricciónpermite valores nulos, asi que si se ingresa el valor "null" para el campo "documento", se acepta.Por convención, cuando demos el nombre a las restricciones "unique" seguiremos la mismaestructura: "UQ_NOMBRETABLA_NOMBRECAMPO". Quizá parezca innecesario colocar elnombre de la tabla, pero cuando empleemos varias tablas verá que es útil identificar lasrestricciones por tipo, tabla y campo.Recuerde que cuando agregamos una restricción a una tabla que contiene información, SQLServer controla los datos existentes para confirmar que cumplen la condición de la restricción, si nolos cumple, la restricción no se aplica y aparece un mensaje de error. En el caso del ejemploanterior, si la tabla contiene números de documento duplicados, la restricción no podráestablecerse; si podrá establecerse si tiene valores nulos.SQL Server controla la entrada de datos en inserciones y actualizaciones evitando que se ingresenvalores duplicados.
    • 52 - Información de restricciones (sp_helpconstraint)DETALLE DE CONCEPTOEl procedimiento almacenado "sp_helpconstraint" seguido del nombre de una tabla muestra lainformación referente a todas las restricciones establecidas en dicha tabla, devuelve las siguientescolumnas:- constraint_type: tipo de restricción. Si es una restricción de campo (default o check) indica sobrequé campo fue establecida. Si es de tabla (primary key o unique) indica el tipo de índice creado(tema que veremos posteriormente).- constraint_name: nombre de la restricción.- delete_action: solamente es aplicable para restricciones de tipo "foreign key" (la veremosposteriormente).- update_action: sólo es aplicable para restricciones de tipo "foreign key" (la veremosposteriormente).- status_enabled: solamente es aplicable para restricciones de tipo "check" y "foreign key". Indica siestá habilitada (Enabled) o no (Disabled). Indica "n/a" en cualquier restricción para la que no seaplique.- status_for_replication: solamente es aplicable para restricciones de tipo "check" y "foreign key".Indica "n/a" en cualquier restricción para la que no se aplique.- constraint_keys: Si es una restricción "check" muestra la condición de chequeo; si es unarestricción "default", el valor por defecto; si es una "primary key" o "unique" muestra el/ los camposa los que se aplicaron la restricción.PROBLEMA RESUELTOProblema:Trabajamos con la tabla "alumnos".Eliminamos la tabla, si existe:if object_id(alumnos) is not null drop table alumnos;Creamos la tabla:create table alumnos( legajo char(4) not null, apellido varchar(20), nombre varchar(20), documento char(8), domicilio varchar(30), ciudad varchar(30), notafinal decimal(4,2));Agregamos una restricción "primary" para el campo "legajo":alter table alumnosadd constraint PK_alumnos_legajoprimary key(legajo);Agregamos una restricción "unique" para el campo "documento":alter table alumnosadd constraint UQ_alumnos_documentounique (documento);
    • Agregamos una restricción "check" para que el campo "notafinal" admita solamente valores entre 0y 10: alter table alumnos add constraint CK_alumnos_nota check (notafinal>=0 and notafinal<=10);Agregamos una restricción "default" para el campo "ciudad": alter table alumnos add constraint DF_alumnos_ciudad default Cordoba for ciudad;Veamos las restricciones: sp_helpconstraint alumnos;Aparece la siguiente información:constraint_type constraint_name status_enabled constraint_keys-------------------------------------------------------------------------------------------CHECK on column notafinal CK_alumos_nota Enabled ([notafinal]>=0 and [notafinal<=10])DEFAULT on column ciudad DF_alumnos_ciudad (n/a) (Cordoba)PRIMARY KEY (clustered) PK_alumnos_legajo (n/a) legajoUNIQUE (NON-clustered) UQ_alumnos_documento (n/a) documentoDeshabilitamos la restricción "check": alter table alumnos nocheck constraint CK_alumnos_nota;Veamos la información que nos retorna "sp_helpconstraint": sp_helpconstraint alumnos;constraint_type constraint_name status_enabled constraint_keys------------------------------------------------------------------------------------------CHECK on column notafinal CK_alumos_nota Disabled ([notafinal]>=0...Note que la restricción esta deshabilitada.53 - Eliminar restricciones (alter table - drop)DETALLE DE CONCEPTOPara eliminar una restricción, la sintaxis básica es la siguiente: alter table NOMBRETABLA drop NOMBRERESTRICCION;Para eliminar la restricción "DF_libros_autor" de la tabla libros tipeamos: alter table libros drop DF_libros_autor;Pueden eliminarse varias restricciones con una sola instrucción separándolas por comas.Cuando eliminamos una tabla, todas las restricciones que fueron establecidas en ella, se eliminantambién.
    • 54 - Crear y asociar reglas (create rule - sp_bindrule)DETALLE DE CONCEPTOVimos que SQL Server ofrece varias alternativas para asegurar la integridad de datos, mediante eluso de: 1. RESTRICCIONES (constraints), que se establecen en tablas y campos y son controlados automáticamente por SQL Server. Hay 3 tipos:I) DE LOS CAMPOS (hace referencia a los valores válidos para un campo determinado). Puedenser:a) DEFAULT: especifica un valor por defecto para un campo cuando no se inserta explícitamenteen un comando "insert".b) CHECK: especifica un rango de valores que acepta un campo, se emplea en inserciones yactualizaciones ("insert" y "update").II) DE LA TABLA (asegura un identificador único para cada registro de una tabla). Hay 2 tipos:a) PRIMARY KEY: identifica unívocamente cada uno de los registros; asegura que no haya valoresduplicados ni valores nulos. Se crea un índice automáticamente.b) UNIQUE: impide la duplicación de claves alternas (no primarias). Se permiten valores nulos. Secrea un índice automáticamente.III) REFERENCIAL: lo veremos más adelante. 2. REGLAS (rules) y 3. VALORES PREDETERMINADOS (defaults).Veamos las reglas.Las reglas especifican los valores que se pueden ingresar en un campo, asegurando que los datosse encuentren en un intervalo de valores específico, coincidan con una lista de valores o sigan unpatrón.Una regla se asocia a un campo de una tabla (o a un tipo de dato definido por el usuario, tema queveremos posteriormente).Un campo puede tener solamente UNA regla asociado a él.Sintaxis básica es la siguiente: create rule NOMBREREGLA as @VARIABLE CONDICIONEntonces, luego de "create rule" se coloca el nombre de la regla, luego la palabra clave "as"seguido de una variable (a la cual la precede el signo arroba) y finalmente la condición.Por convención, nombraremos las reglas comenzando con "RG", el nombre del campo al que seasocia y alguna palabra que haga referencia a la condición.La variable puede tener cualquier nombre, pero debe estar precedido por el signo arroba (@),dicha variable será reemplazada por el valor del campo cuando se asocie.La condición se refiere a los valores permitidos para inserciones y actualizaciones y puedecontener cualquier expresión válida para una cláusula "where"; no puede hacer referencia a loscampos de una tabla.Creamos una regla para restringir los valores que se pueden ingresar en un campo "sueldo" de unatabla llamada "empleados", estableciendo un intervalo de valores: create rule RG_sueldo_intervalo as @sueldo between 100 and 1000Luego de crear la regla, debemos asociarla a un campo ejecutando un procedimiento almacenadodel sistema empleando la siguiente sintaxis básica: exec sp_bindrule NOMBREREGLA, TABLA.CAMPO;Asociamos la regla creada anteriormente al campo "sueldo" de la tabla "empleados":
    • exec sp_bindrule RG_sueldo_intervalo, empleados.sueldo;Si intentamos agregar (o actualizar) un registro con valor para el campo "sueldo" que no esté en elintervalo de valores especificado en la regla, aparece un mensaje de error indicando que hayconflicto con la regla y la inserción (o actualización) no se realiza.SQL Server NO controla los datos existentes para confirmar que cumplen con la regla como lohace al aplicar restricciones; si no los cumple, la regla se asocia igualmente; pero al ejecutar unainstrucción "insert" o "update" muestra un mensaje de error, es decir, actúa en inserciones yactualizaciones.La regla debe ser compatible con el tipo de datos del campo al cual se asocia; si esto no sucede,SQL Server no lo informa al crear la regla ni al asociarla, pero al ejecutar una instrucción "insert" o"update" muestra un mensaje de error.No se puede crear una regla para campos de tipo text, image, o timestamp.Si asocia una nueva regla a un campo que ya tiene asociada otra regla, la nueva regla reeemplazala asociación anterior; pero la primera regla no desaparece, solamente se deshace la asociación.La sentencia "create rule" no puede combinarse con otras sentencias en un lote.La función que cumple una regla es básicamente la misma que una restricción "check", lassiguientes características explican algunas diferencias entre ellas:- podemos definir varias restricciones "check" sobre un campo, un campo solamente puede teneruna regla asociada a él;- una restricción "check" se almacena con la tabla, cuando ésta se elimina, las restriccionestambién se borran. Las reglas son objetos diferentes e independientes de las tablas, si eliminamosuna tabla, las asociaciones desaparecen, pero las reglas siguen existiendo en la base de datos;- una restricción "check" puede incluir varios campos; una regla puede asociarse a distintoscampos (incluso de distintas tablas);- una restricción "check" puede hacer referencia a otros campos de la misma tabla, una regla no.Un campo puede tener reglas asociadas a él y restricciones "check". Si hay conflicto entre ellas,SQL Server no lo informa al crearlas y/o asociarlas, pero al intentar ingresar un valor que alguna deellas no permita, aparece un mensaje de error.Con "sp_helpconstraint" podemos ver las reglas asociadas a los campos de una tabla.Con "sp_help" podemos ver todos los objetos de la base de datos activa, incluyendo las reglas, ental caso en la columna "Object_type" aparece "rule".55 - Eliminar y dasasociar reglas (sp_unbindrule - drop rule)DETALLE DE CONCEPTOPara eliminar una regla, primero se debe deshacer la asociación, ejecutando el procedimientoalmacenado del sistema "sp_unbindrule": exec sp_unbindrule TABLA.CAMPO;No es posible eliminar una regla si está asociada a un campo. Si intentamos hacerlo, aparece unmensaje de error y la eliminación no se realiza.Con la instrucción "drop rule" eliminamos la regla: drop rule NOMBREREGLA;Quitamos la asociación de la regla "RG_sueldo_intervalo" con el campo "sueldo" de la tabla"empleados" tipeando: exec sp_unbindrule empleados.sueldo;Luego de quitar la asociación la eliminamos:
    • drop rule RG_sueldo_100a1000;Si eliminamos una tabla, las asociaciones de reglas de sus campos desaparecen, pero las reglassiguen existiendo.56 - Información de reglas (sp_help - sp_helpconstraint)DETALLE DE CONCEPTOPodemos utilizar el procedimiento almacenado "sp_help" con el nombre del objeto del cualqueremos información, en este caso el nombre de una regla: sp_help NOMBREREGLA;muestra nombre, propietario, tipo y fecha de creación.Con "sp_help", no sabemos si las reglas existentes están o no asociadas a algún campo."sp_helpconstraint" retorna una lista de todas las restricciones que tiene una tabla. Podemos verlas reglas asociadas a una tabla con este procedimiento almacenado: sp_helpconstraint NOMBRETABLA;muestra la siguiente información:- constraint_type: indica que es una regla con "RULE", nombrando el campo al que está asociada.- constraint_name: nombre de la regla.- constraint_keys: muestra el texto de la regla.Para ver el texto de una regla empleamos el procedimiento almacenado "sp_helptext" seguido delnombre de la regla: sp_helptext NOMBREREGLA;También se puede consultar la tabla del sistema "sysobjects", que nos muestra el nombre y variosdatos de todos los objetos de la base de datos actual. La columna "xtype" indica el tipo de objeto,en caso de ser una regla aparece el valor "R": select *from sysobjects;Si queremos ver todas las reglas creadas por nosotros, podemos tipear: select *from sysobjects where xtype=R and-- tipo regla name like RG%;--búsqueda con comodín57 - Valores predeterminados (create default)DETALLE DE CONCEPTOHemos visto que para mantener la integridad declarativa se emplean restricciones, reglas (quehemos estudiado en secciones anteriores) y valores predeterminados.Veamos los valores predeterminados.Los valores predeterminados se asocian con uno o varios campos (o tipos de datos definidos por elusuario); se definen una sola vez y se pueden usar muchas veces.Si no se coloca un valor cuando se ingresan datos, el valor predeterminado especifica el valor delcampo al que está asociado.Sintaxis básica: create default NOMBREVALORPREDETERMINADO as VALORPREDETERMINADO;
    • "VALORPREDETERMINADO" no puede hacer referencia a campos de una tabla (u otros objetos)y debe ser compatible con el tipo de datos y longitud del campo al cual se asocia; si esto nosucede, SQL Server no lo informa al crear el valor predeterminado ni al asociarlo, pero al ejecutaruna instrucción "insert" muestra un mensaje de error.En el siguiente ejemplo creamos un valor predeterminado llamado "VP_datodesconocido con elvalor "Desconocido": create default VP_datodesconocido as DesconocidoLuego de crear un valor predeterminado, debemos asociarlo a un campo (o a un tipo de datosdefinido por el usuario) ejecutando el procedimiento almacenado del sistema "sp_bindefault": exec sp_bindefault NOMBRE, NOMBRETABLA.CAMPO;La siguiente sentencia asocia el valor predeterminado creado anteriormente al campo "domicilio"de la tabla "empleados": exec sp_bindefault VP_datodesconocido, empleados.domicilio;Podemos asociar un valor predeterminado a varios campos. Asociamos el valor predeterminado"VP_datodesconocido" al campo "barrio" de la tabla "empleados": exec sp_bindefault VP_datodesconocido, empleados.barrio;La función que cumple un valor predeterminado es básicamente la misma que una restricción"default", las siguientes características explican algunas semejanzas y diferencias entre ellas:- un campo solamente puede tener definida UNA restricción "default", un campo solamente puedetener UN valor predeterminado asociado a él,- una restricción "default" se almacena con la tabla, cuando ésta se elimina, las restriccionestambién. Los valores predeterminados son objetos diferentes e independientes de las tablas, sieliminamos una tabla, las asociaciones desaparecen, pero los valores predeterminados siguenexistiendo en la base de datos.- una restricción "default" se establece para un solo campo; un valor predeterminado puedeasociarse a distintos campos (inclusive, de diferentes tablas).- una restricción "default" no puede establecerse sobre un campo "identity", tampoco un valorpredeterminado.No se puede asociar un valor predeterminado a un campo que tiene una restricción "default".Un campo con un valor predeterminado asociado puede tener reglas asociadas a él y restricciones"check". Si hay conflicto entre ellas, SQL Server no lo informa al crearlas y/o asociarlas, pero alintentar ingresar un valor que alguna de ellas no permita, aparece un mensaje de error.La sentencia "create default" no puede combinarse con otra sentencia en un mismo lote.Si asocia a un campo que ya tiene asociado un valor predeterminado otro valor predeterminado, lanueva asociación reemplaza a la anterior.Veamos otros ejemplos.Creamos un valor predeterminado que inserta el valor "0" en un campo de tipo numérico: create default VP_cero as 0;En el siguiente creamos un valor predeterminado que inserta ceros con el formato válido para unnúmero de teléfono: create default VP_telefono as (0000)0-000000;Con "sp_helpconstraint" podemos ver los valores predeterminados asociados a los campos de unatabla.Con "sp_help" podemos ver todos los objetos de la base de datos activa, incluyendo los valorespredeterminados, en tal caso en la columna "Object_type" aparece "default".
    • 58 - Desasociar y eliminar valores predeterminadosDETALLE DE CONCEPTOUn valor predeterminado no puede eliminarse si no se ha desasociado previamente.Para deshacer una asociación empleamos el procedimiento almacenado "sp_unbindefault" seguidode la tabla y campo al que está asociado: sp_unbindefault TABLA.CAMPO;Quitamos la asociación al campo "sueldo" de la tabla "empleados": sp_unbindefault empleados.sueldo;Con la instrucción "drop default" podemos eliminar un valor predeterminado: drop default NOMBREVALORPREDETERMINADO;Eliminamos el valor predeterminado llamado "VP_cero": drop default VP_cero;Si eliminamos una tabla, las asociaciones de valores predeterminados de sus camposdesaparecen, pero los valores predeterminados siguen existiendo.59 - Información de valores predeterminadosDETALLE DE CONCEPTOPara obtener información de los valores predeterminados podemos emplear los mismosprocedimientos almacenados que usamos para las reglas.Si empleamos "sp_help", vemos todos los objetos de la base de datos activa (incluyendo losvalores predeterminados); en la columna "Object_type" (tipo de objeto) muestra "default".Si al procedimiento almacenado "sp_help" le agregamos el nombre de un valor predeterminado,nos muestra el nombre, propietario, tipo y fecha de creación: sp_help NOMBREVALORPREDETERMINADO;Con "sp_help", no sabemos si los valores predeterminados existentes están o no asociadas aalgún campo."sp_helpconstraint" retorna una lista de todas las restricciones que tiene una tabla. También losvalores predeterminados asociados; muestra la siguiente información:- constraint_type: indica que es un valor predeterminado con "DEFAULT", nombrando el campo alque está asociado.- constraint_name: nombre del valor predeterminado.- constraint_keys: muestra el texto del valor predeterminado.Con "sp_helptext" seguido del nombre de un valor predeterminado podemos ver el texto decualquier valor predeterminado: sp_helptext NOMBREVALORPREDETERMINADO;También se puede consultar la tabla del sistema "sysobjects", que nos muestra el nombre y variosdatos de todos los objetos de la base de datos actual. La columna "xtype" indica el tipo de objeto,en caso de ser un valor predeterminado aparece el valor "D": select *from sysobjects;Si queremos ver todos los valores predeterminados creados por nosotros, podemos tipear: select *from sysobjects where xtype=D and-- tipo valor predeterminado name like VP%;--búsqueda con comodín60 - IndicesDETALLE DE CONCEPTOSQL Server accede a los datos de dos maneras:
    • 1. recorriendo las tablas; comenzando el principio y extrayendo los registros que cumplen las condiciones de la consulta. 2. empleando índices; recorriendo la estructura de árbol del índice para localizar los registros y extrayendo los que cumplen las condiciones de la consulta.Los índices se emplean para facilitar la obtención de información de una tabla. El indice de unatabla desempeña la misma función que el índice de un libro: permite encontrar datos rápidamente;en el caso de las tablas, localiza registros.Una tabla se indexa por un campo (o varios).Un índice posibilita el acceso directo y rápido haciendo más eficiente las búsquedas. Sin índice,SQL Server debe recorrer secuencialmente toda la tabla para encontrar un registro.El objetivo de un indice es acelerar la recuperación de información. La indexación es una técnicaque optimiza el acceso a los datos, mejora el rendimiento acelerando las consultas y otrasoperaciones. Es útil cuando la tabla contiene miles de registros, cuando se realizan operaciones deordenamiento y agrupamiento y cuando se combinan varias tablas (tema que veremos másadelante).La desventaja es que consume espacio en el disco en disco y genera costo de mantenimiento(tiempo y recursos).Los índices más adecuados son aquellos creados con campos que contienen valores únicos.Es importante identificar el o los campos por los que sería útil crear un índice, aquellos campos porlos cuales se realizan búsqueda con frecuencia: claves primarias, claves externas o campos quecombinan tablas.No se recomienda crear índices por campos que no se usan con frecuencia en consultas o nocontienen valores únicos.SQL Server permite crear dos tipos de índices: 1) agrupados y 2) no agrupados.61 - Indices agrupados y no agrupados (clustered y nonclustered)DETALLE DE CONCEPTODijimos que SQL Server permite crear dos tipos de índices: 1) agrupados (clustered) y 2) noagrupados (nonclustered).1) Un INDICE AGRUPADO es similar a una guía telefónica, los registros con el mismo valor decampo se agrupan juntos. Un índice agrupado determina la secuencia de almacenamiento de losregistros en una tabla.Se utilizan para campos por los que se realizan busquedas con frecuencia o se accede siguiendoun orden.Una tabla sólo puede tener UN índice agrupado.El tamaño medio de un índice agrupado es aproximadamente el 5% del tamaño de la tabla.2) Un INDICE NO AGRUPADO es como el índice de un libro, los datos se almacenan en un lugardiferente al del índice, los punteros indican el lugar de almacenamiento de los elementos indizadosen la tabla.Un índice no agrupado se emplea cuando se realizan distintos tipos de busquedas frecuentemente,con campos en los que los datos son únicos.Una tabla puede tener hasta 249 índices no agrupados.Si no se especifica un tipo de índice, de modo predeterminado será no agrupado.Los campos de tipo text, ntext e image no se pueden indizar.Es recomendable crear los índices agrupados antes que los no agrupados, porque los primerosmodifican el orden físico de los registros, ordenándolos secuencialmente.
    • La diferencia básica entre índices agrupados y no agrupados es que los registros de un índiceagrupado están ordenados y almacenados de forma secuencial en función de su clave.SQL Server crea automaticamente índices cuando se crea una restricción "primary key" o "unique"en una tabla.Es posible crear índices en las vistas.Resumiendo, los índices facilitan la recuperación de datos, permitiendo el acceso directo yacelerando las búsquedas, consultas y otras operaciones que optimizan el rendimiento general.62 - Creación de índicesDETALLE DE CONCEPTOPara crear índices empleamos la instrucción "create index".La sintaxis básica es la siguiente: create TIPODEINDICE index NOMBREINDICE on TABLA(CAMPO);"TIPODEINDICE" indica si es agrupado (clustered) o no agrupado (nonclustered). Si noespecificamos crea uno No agrupado. Independientemente de si es agrupado o no, también sepuede especificar que sea "unique", es decir, no haya valores repetidos. Si se intenta crear uníndice unique para un campo que tiene valores duplicados, SQL Server no lo permite.En este ejemplo se crea un índice agrupado único para el campo "codigo" de la tabla "libros": create unique clustered index I_libros_codigo on libros(codigo);Para identificar los índices fácilmente, podemos agregar un prefijo al nombre del índice, porejemplo "I" y luego el nombre de la tabla y/o campo.En este ejemplo se crea un índice no agrupado para el campo "titulo" de la tabla "libros": create nonclustered index I_libros_titulo on libros(titulo);Un índice puede tener más de un campo como clave, son índices compuestos. Los campos de uníndice compuesto tienen que ser de la misma tabla (excepto cuando se crea en una vista - temaque veremos posteriormente).Creamos un índice compuesto para el campo "autor" y "editorial": create index I_libros_autoreditorial on libros(autor,editorial);SQL Server crea automáticamente índices cuando se establece una restricción "primary key" o"unique" en una tabla. Al crear una restricción "primary key", si no se especifica, el índice seráagrupado (clustered) a menos que ya exista un índice agrupado para dicha tabla. Al crear unarestricción "unique", si no se especifica, el índice será no agrupado (non-clustered).Ahora podemos entender el resultado del procedimiento almacenado "sp_helpconstraint" cuandoen la columna "constraint_type" mostraba el tipo de índice seguido de las palabras "clustered" o"non_clustered".Puede especificarse que un índice sea agrupado o no agrupado al agregar estas restricciones.Agregamos una restricción "primary key" al campo "codigo" de la tabla "libros" especificando quecree un índice NO agrupado: alter table libros add constraint PK_libros_codigo primary key nonclustered (codigo);Para ver los indices de una tabla: sp_helpindex libros;
    • Muestra el nombre del índice, si es agrupado (o no), primary (o unique) y el campo por el cual seindexa.Todos los índices de la base de datos activa se almacenan en la tabla del sistema "sysindexes",podemos consultar dicha tabla tipeando: select name from sysindexes;Para ver todos los índices de la base de datos activa creados por nosotros podemos tipear lasiguiente consulta: select name from sysindexes where name like I_%;63 - Regenerar índicesDETALLE DE CONCEPTOVimos que para crear índices empleamos la instrucción "create index".Empleando la opción "drop_existing" junto con "create index" permite regenerar un índice, con elloevitamos eliminarlo y volver a crearlo. La sintaxis es la siguiente: create TIPODEINDICE index NOMBREINDICE on TABLA(CAMPO) with drop_existing;También podemos modificar alguna de las características de un índice con esta opción, a saber:- tipo: cambiándolo de no agrupado a agrupado (siempre que no exista uno agrupado para lamisma tabla). No se puede convertir un índice agrupado en No agrupado.- campo: se puede cambiar el campo por el cual se indexa, agregar campos, eliminar algún campode un índice compuesto.- único: se puede modificar un índice para que los valores sean únicos o dejen de serlo.En este ejemplo se crea un índice no agrupado para el campo "titulo" de la tabla "libros": create nonclustered index I_libros on libros(titulo);Regeneramos el índice "I_libros" y lo convertimos a agrupado: create clustered index I_libros on libros(titulo) with drop_existing;Agregamos un campo al índice "I_libros": create clustered index I_libros on libros(titulo,editorial) with drop_existing;Esta opción no puede emplearse con índices creados a partir de una restricción "primary key" o"unique".64 - Eliminar índicesDETALLE DE CONCEPTOLos índices creados con "create index" se eliminan con "drop index"; la siguiente es la sintaxisbásica: drop index NOMBRETABLA.NOMBREINDICE;Eliminamos el índice "I_libros_titulo":
    • drop index libros.I_libros_titulo;Los índices que SQL Server crea automáticamente al establecer una restricción "primary key" o"unique" no pueden eliminarse con "drop index", se eliminan automáticamente cuando quitamos larestricción.Podemos averiguar si existe un índice para eliminarlo, consultando la tabla del sistema"sysindexes": if exists (select name from sysindexes where name = NOMBREINDICE) drop index NOMBRETABLA.NOMBREINDICE;Eliminamos el índice "I_libros_titulo" si existe: if exists (select *from sysindexes where name = I_libros_titulo) drop index libros.I_libros_titulo;65 - Trabajar con varias tablasDETALLE DE CONCEPTOHasta el momento hemos trabajado con una sola tabla, pero generalmente, se trabaja con más deuna.Para evitar la repetición de datos y ocupar menos espacio, se separa la información en variastablas. Cada tabla almacena parte de la información que necesitamos registrar.Por ejemplo, los datos de nuestra tabla "libros" podrían separarse en 2 tablas, una llamada "libros"y otra "editoriales" que guardará la información de las editoriales.En nuestra tabla "libros" haremos referencia a la editorial colocando un código que la identifique.Veamos: create table libros( codigo int identity, titulo varchar(40) not null, autor varchar(30) not null default Desconocido, codigoeditorial tinyint not null, precio decimal(5,2), primary key (codigo) ); create table editoriales( codigo tinyint identity, nombre varchar(20) not null, primary key(codigo) );De esta manera, evitamos almacenar tantas veces los nombres de las editoriales en la tabla"libros" y guardamos el nombre en la tabla "editoriales"; para indicar la editorial de cada libroagregamos un campo que hace referencia al código de la editorial en la tabla "libros" y en"editoriales".Al recuperar los datos de los libros con la siguiente instrucción: select* from libros;
    • vemos que en el campo "editorial" aparece el código, pero no sabemos el nombre de la editorial.Para obtener los datos de cada libro, incluyendo el nombre de la editorial, necesitamos consultarambas tablas, traer información de las dos.Cuando obtenemos información de más de una tabla decimos que hacemos un "join"(combinación).Veamos un ejemplo: select *from libros join editoriales on libros.codigoeditorial=editoriales.codigo;Resumiendo: si distribuimos la información en varias tablas evitamos la redundancia de datos yocupamos menos espacio físico en el disco. Un join es una operación que relaciona dos o mástablas para obtener un resultado que incluya datos (campos y registros) de ambas; las tablasparticipantes se combinan según los campos comunes a ambas tablas.Hay hay tres tipos de combinaciones. En los siguientes capítulos explicamos cada una de ellas.66 - Combinación interna (inner join)DETALLE DE CONCEPTOUn join es una operación que relaciona dos o más tablas para obtener un resultado que incluyadatos (campos y registros) de ambas; las tablas participantes se combinan según los camposcomunes a ambas tablas.Hay tres tipos de combinaciones: 1. combinaciones internas (inner join o join), 2. combinaciones externas y 3. combinaciones cruzadas.También es posible emplear varias combinaciones en una consulta "select", incluso puedecombinarse una tabla consigo misma.La combinación interna emplea "join", que es la forma abreviada de "inner join". Se emplea paraobtener información de dos tablas y combinar dicha información en una salida.La sintaxis básica es la siguiente: select CAMPOS from TABLA1 join TABLA2 on CONDICIONdeCOMBINACION;Ejemplo: select *from libros join editoriales on codigoeditorial=editoriales.codigo;Analicemos la consulta anterior.- especificamos los campos que aparecerán en el resultado en la lista de selección;- indicamos el nombre de la tabla luego del "from" ("libros");- combinamos esa tabla con "join" y el nombre de la otra tabla ("editoriales"); se especifica quétablas se van a combinar y cómo;- cuando se combina información de varias tablas, es necesario especificar qué registro de unatabla se combinará con qué registro de la otra tabla, con "on". Se debe especificar la condiciónpara enlazarlas, es decir, el campo por el cual se combinarán, que tienen en común."on" hace coincidir registros de ambas tablas basándose en el valor de tal campo, en el ejemplo, el
    • campo "codigoeditorial" de "libros" y el campo "codigo" de "editoriales" son los que enlazaránambas tablas. Se emplean campos comunes, que deben tener tipos de datos iguales o similares.La condicion de combinación, es decir, el o los campos por los que se van a combinar (parte "on"),se especifica según las claves primarias y externas.Note que en la consulta, al nombrar el campo usamos el nombre de la tabla también. Cuando lastablas referenciadas tienen campos con igual nombre, esto es necesario para evitar confusiones yambiguedades al momento de referenciar un campo. En el ejemplo, si no especificamos"editoriales.codigo" y solamente tipeamos "codigo", SQL Server no sabrá si nos referimos al campo"codigo" de "libros" o de "editoriales" y mostrará un mensaje de error indicando que "codigo" esambiguo.Entonces, si las tablas que combinamos tienen nombres de campos iguales, DEBE especificarse aqué tabla pertenece anteponiendo el nombre de la tabla al nombre del campo, separado por unpunto (.).Si una de las tablas tiene clave primaria compuesta, al combinarla con la otra, en la cláusula "on"se debe hacer referencia a la clave completa, es decir, la condición referenciará a todos loscampos clave que identifican al registro.Se puede incluir en la consulta join la cláusula "where" para restringir los registros que retorna elresultado; también "order by", "distinct", etc..Se emplea este tipo de combinación para encontrar registros de la primera tabla que secorrespondan con los registros de la otra, es decir, que cumplan la condición del "on". Si un valorde la primera tabla no se encuentra en la segunda tabla, el registro no aparece.Para simplificar la sentencia podemos usar un alias para cada tabla: select l.codigo,titulo,autor,nombre from libros as l join editoriales as e on l.codigoeditorial=e.codigo;En algunos casos (como en este ejemplo) el uso de alias es para fines de simplificación y hacemás legible la consulta si es larga y compleja, pero en algunas consultas es absolutamentenecesario.PROBLEMA RESUELTOProblema:Una librería almacena la información de sus libros para la venta en dos tablas, "libros" y"editoriales".Eliminamos ambas tablas, si existen: if object_id(libros) is not null drop table libros; if object_id(editoriales) is not null drop table editoriales;Creamos las tablas: create table libros( codigo int identity, titulo varchar(40), autor varchar(30) default Desconocido, codigoeditorial tinyint not null, precio decimal(5,2) ); create table editoriales(
    • codigo tinyint identity, nombre varchar(20), primary key (codigo));Ingresamos algunos registros en ambas tablas: insert into editoriales values(Planeta); insert into editoriales values(Emece); insert into editoriales values(Siglo XXI); insert into libros values(El aleph,Borges,2,20); insert into libros values(Martin Fierro,Jose Hernandez,1,30); insert into libros values(Aprenda PHP,Mario Molina,3,50); insert into libros values(Java en 10 minutos,default,3,45);Recuperamos los datos de libros: select* from libros;vemos que en el campo "editorial" aparece el código, pero no sabemos el nombre de la editorial.Realizamos un join para obtener datos de ambas tablas (titulo, autor y nombre de la editorial): select titulo, autor, nombre from libros join editoriales on codigoeditorial=editoriales.codigo;Mostramos el código del libro, título, autor, nombre de la editorial y el precio realizando un join yempleando alias: select l.codigo,titulo,autor,nombre,precio from libros as l join editoriales as e on codigoeditorial=e.codigo;Note que al listar el campo "codigo" especificamos a qué tabla pertenece; si no lo hacemos SQLServer no sabrá si nos referimos al de la tabla "libros" o "editoriales". Los demás campos no tienenreferencia a la tabla porque tienen nombres que no se repiten.Realizamos la misma consulta anterior agregando un "where" para obtener solamente los libros dela editorial "Siglo XXI": select l.codigo,titulo,autor,nombre,precio from libros as l join editoriales as e on codigoeditorial=e.codigo where e.nombre=Siglo XXI;Obtenemos título, autor y nombre de la editorial, esta vez ordenados por título: select titulo,autor,nombre from libros as l join editoriales as e on codigoeditorial=e.codigo order by titulo;PROBLEMA A RESOLVERPrimer problema:Una empresa tiene registrados sus clientes en una tabla llamada "clientes", también tiene una tabla"provincias" donde registra los nombres de las provincias.
    • 1- Elimine las tablas "clientes" y "provincias", si existen: if (object_id(clientes)) is not null drop table clientes; if (object_id(provincias)) is not null drop table provincias;2- Créelas con las siguientes estructuras: create table clientes ( codigo int identity, nombre varchar(30), domicilio varchar(30), ciudad varchar(20), codigoprovincia tinyint not null, primary key(codigo) );create table provincias( codigo tinyint identity, nombre varchar(20), primary key (codigo));3- Ingrese algunos registros para ambas tablas: insert into provincias (nombre) values(Cordoba); insert into provincias (nombre) values(Santa Fe); insert into provincias (nombre) values(Corrientes);insert into clientes values (Lopez Marcos,Colon 111,Córdoba,1);insert into clientes values (Perez Ana,San Martin 222,Cruz del Eje,1);insert into clientes values (Garcia Juan,Rivadavia 333,Villa Maria,1);insert into clientes values (Perez Luis,Sarmiento 444,Rosario,2);insert into clientes values (Pereyra Lucas,San Martin 555,Cruz del Eje,1);insert into clientes values (Gomez Ines,San Martin 666,Santa Fe,2);insert into clientes values (Torres Fabiola,Alem 777,Ibera,3);4- Obtenga los datos de ambas tablas, usando alias: select c.nombre,domicilio,ciudad,p.nombre from clientes as c join provincias as p on c.codigoprovincia=p.codigo;5- Obtenga la misma información anterior pero ordenada por nombre de provincia.6- Recupere los clientes de la provincia "Santa Fe" (2 registros devueltos)
    • 67 - Combinación externa izquierda (left join)DETALLE DE CONCEPTOVimos que una combinación interna (join) encuentra registros de la primera tabla que secorrespondan con los registros de la segunda, es decir, que cumplan la condición del "on" y si unvalor de la primera tabla no se encuentra en la segunda tabla, el registro no aparece.Si queremos saber qué registros de una tabla NO encuentran correspondencia en la otra, es decir,no existe valor coincidente en la segunda, necesitamos otro tipo de combinación, "outer join"(combinación externa).Las combinaciones externas combinan registros de dos tablas que cumplen la condición, más losregistros de la segunda tabla que no la cumplen; es decir, muestran todos los registros de lastablas relacionadas, aún cuando no haya valores coincidentes entre ellas.Este tipo de combinación se emplea cuando se necesita una lista completa de los datos de una delas tablas y la información que cumple con la condición. Las combinaciones externas se realizansolamente entre 2 tablas.Hay tres tipos de combinaciones externas: "left outer join", "right outer join" y "full outer join"; sepueden abreviar con "left join", "right join" y "full join" respectivamente.Vamos a estudiar las primeras.Se emplea una combinación externa izquierda para mostrar todos los registros de la tabla de laizquierda. Si no encuentra coincidencia con la tabla de la derecha, el registro muestra los camposde la segunda tabla seteados a "null".En el siguiente ejemplo solicitamos el título y nombre de la editorial de los libros: select titulo,nombre from editoriales as e left join libros as l on codigoeditorial = e.codigo;El resultado mostrará el título y nombre de la editorial; las editoriales de las cuales no hay libros, esdecir, cuyo código de editorial no está presente en "libros" aparece en el resultado, pero con elvalor "null" en el campo "titulo".Es importante la posición en que se colocan las tablas en un "left join", la tabla de la izquierda es laque se usa para localizar registros en la tabla de la derecha.Entonces, un "left join" se usa para hacer coincidir registros en una tabla (izquierda) con otra tabla(derecha); si un valor de la tabla de la izquierda no encuentra coincidencia en la tabla de laderecha, se genera una fila extra (una por cada valor no encontrado) con todos los camposcorrespondientes a la tabla derecha seteados a "null". La sintaxis básica es la siguiente: select CAMPOS from TABLAIZQUIERDA left join TABLADERECHA on CONDICION;En el siguiente ejemplo solicitamos el título y el nombre la editorial, la sentencia es similar a laanterior, la diferencia está en el orden de las tablas: select titulo,nombre from libros as l left join editoriales as e on codigoeditorial = e.codigo;El resultado mostrará el título del libro y el nombre de la editorial; los títulos cuyo código de editorialno está presente en "editoriales" aparecen en el resultado, pero con el valor "null" en el campo"nombre".
    • Un "left join" puede tener clausula "where" que restringa el resultado de la consulta considerandosolamente los registros que encuentran coincidencia en la tabla de la derecha, es decir, cuyo valorde código está presente en "libros": select titulo,nombre from editoriales as e left join libros as l on e.codigo=codigoeditorial where codigoeditorial is not null;También podemos mostrar las editoriales que NO están presentes en "libros", es decir, que NOencuentran coincidencia en la tabla de la derecha: select titulo,nombre from editoriales as e left join libros as l on e.codigo=codigoeditorial where codigoeditorial is nullPROBLEMA RESUELTOProblema:Una librería almacena la información de sus libros para la venta en dos tablas, "libros" y"editoriales".Eliminamos ambas tablas, si existen y las creamos: if object_id(libros) is not null drop table libros; if object_id(editoriales) is not null drop table editoriales; create table libros( codigo int identity, titulo varchar(40), autor varchar(30) default Desconocido, codigoeditorial tinyint not null, precio decimal(5,2) ); create table editoriales( codigo tinyint identity, nombre varchar(20), primary key (codigo));Ingresamos algunos registros en ambas tablas: insert into editoriales values(Planeta); insert into editoriales values(Emece); insert into editoriales values(Siglo XXI);insert into libros values(El aleph,Borges,1,20);insert into libros values(Martin Fierro,Jose Hernandez,1,30);insert into libros values(Aprenda PHP,Mario Molina,2,50);insert into libros values(Java en 10 minutos,default,4,45);
    • Realizamos una combinación izquierda para obtener los datos de los libros, incluyendo el nombrede la editorial: select titulo,nombre from editoriales as e left join libros as l on codigoeditorial = e.codigo;Las editoriales de las cuales no hay libros, es decir, cuyo código de editorial no está presente en"libros" aparece en el resultado, pero con el valor "null" en el campo "titulo".Realizamos la misma consulta anterior pero cambiamos el orden de las tablas: select titulo,nombre from libros as l left join editoriales as e on codigoeditorial = e.codigo;El resultado mostrará el título del libro y el nombre de la editorial; los títulos cuyo código de editorialno está presente en "editoriales" aparecen en el resultado, pero con el valor "null" en el campo"nombre".Restringimos el resultado de una consulta considerando solamente los registros que encuentrancoincidencia en la tabla de la derecha, es decir, cuyo valor de código está presente en "libros": select titulo,nombre from editoriales as e left join libros as l on e.codigo=codigoeditorial where codigoeditorial is not null;Mostramos las editoriales que NO están presentes en "libros", es decir, que NO encuentrancoincidencia en la tabla de la derecha: select titulo,nombre from editoriales as e left join libros as l on e.codigo=codigoeditorial where codigoeditorial is null;PROBLEMA A RESOLVERPrimer problema:Una empresa tiene registrados sus clientes en una tabla llamada "clientes", también tiene una tabla"provincias" donde registra los nombres de las provincias.1- Elimine las tablas "clientes" y "provincias", si existen y cree las tablas: if (object_id(clientes)) is not null drop table clientes; if (object_id(provincias)) is not null drop table provincias;create table clientes ( codigo int identity, nombre varchar(30), domicilio varchar(30), ciudad varchar(20), codigoprovincia tinyint not null, primary key(codigo)
    • );create table provincias( codigo tinyint identity, nombre varchar(20), primary key (codigo));2- Ingrese algunos registros para ambas tablas: insert into provincias (nombre) values(Cordoba); insert into provincias (nombre) values(Santa Fe); insert into provincias (nombre) values(Corrientes);insert into clientes values (Lopez Marcos,Colon 111,Córdoba,1);insert into clientes values (Perez Ana,San Martin 222,Cruz del Eje,1);insert into clientes values (Garcia Juan,Rivadavia 333,Villa Maria,1);insert into clientes values (Perez Luis,Sarmiento 444,Rosario,2);insert into clientes values (Gomez Ines,San Martin 666,Santa Fe,2);insert into clientes values (Torres Fabiola,Alem 777,La Plata,4);insert into clientes values (Garcia Luis,Sucre 475,Santa Rosa,5);3- Muestre todos los datos de los clientes, incluido el nombre de la provincia: select c.nombre,domicilio,ciudad, p.nombre from clientes as c left join provincias as p on codigoprovincia = p.codigo;4- Realice la misma consulta anterior pero alterando el orden de las tablas: select c.nombre,domicilio,ciudad, p.nombre from provincias as p left join clientes as c on codigoprovincia = p.codigo;5- Muestre solamente los clientes de las provincias que existen en "provincias" (5 registros): select c.nombre,domicilio,ciudad, p.nombre from clientes as c left join provincias as p on codigoprovincia = p.codigo where p.codigo is not null;6- Muestre todos los clientes cuyo código de provincia NO existe en "provincias" ordenados pornombre del cliente (2 registros): select c.nombre,domicilio,ciudad, p.nombre from clientes as c left join provincias as p on codigoprovincia = p.codigo where p.codigo is null order by c.nombre;
    • 7- Obtenga todos los datos de los clientes de "Cordoba" (3 registros): select c.nombre,domicilio,ciudad, p.nombre from clientes as c left join provincias as p on codigoprovincia = p.codigo where p.nombre=Cordoba;68 - Combinación externa derecha (right join)DETALLE DE CONCEPTOVimos que una combinación externa izquierda (left join) encuentra registros de la tabla izquierdaque se correspondan con los registros de la tabla derecha y si un valor de la tabla izquierda no seencuentra en la tabla derecha, el registro muestra los campos correspondientes a la tabla de laderecha seteados a "null".Una combinación externa derecha ("right outer join" o "right join") opera del mismo modo sólo quela tabla derecha es la que localiza los registros en la tabla izquierda.En el siguiente ejemplo solicitamos el título y nombre de la editorial de los libros empleando un"right join": select titulo,nombre from libros as l right join editoriales as e on codigoeditorial = e.codigo;El resultado mostrará el título y nombre de la editorial; las editoriales de las cuales no hay libros, esdecir, cuyo código de editorial no está presente en "libros" aparece en el resultado, pero con elvalor "null" en el campo "titulo".Es FUNDAMENTAL tener en cuenta la posición en que se colocan las tablas en los "outer join". Enun "left join" la primera tabla (izquierda) es la que busca coincidencias en la segunda tabla(derecha); en el "right join" la segunda tabla (derecha) es la que busca coincidencias en la primeratabla (izquierda).En la siguiente consulta empleamos un "left join" para conseguir el mismo resultado que el "rightjoin" anterior": select titulo,nombre from editoriales as e left join libros as l on codigoeditorial = e.codigo;Note que la tabla que busca coincidencias ("editoriales") está en primer lugar porque es un "leftjoin"; en el "right join" precedente, estaba en segundo lugar.Un "right join" hace coincidir registros en una tabla (derecha) con otra tabla (izquierda); si un valorde la tabla de la derecha no encuentra coincidencia en la tabla izquierda, se genera una fila extra(una por cada valor no encontrado) con todos los campos correspondientes a la tabla izquierdaseteados a "null". La sintaxis básica es la siguiente: select CAMPOS from TABLAIZQUIERDA right join TABLADERECHA on CONDICION;Un "right join" también puede tener cláusula "where" que restringa el resultado de la consultaconsiderando solamente los registros que encuentran coincidencia en la tabla izquierda: select titulo,nombre
    • from libros as l right join editoriales as e on e.codigo=codigoeditorial where codigoeditorial is not null;Mostramos las editoriales que NO están presentes en "libros", es decir, que NO encuentrancoincidencia en la tabla de la derecha empleando un "right join": select titulo,nombre from libros as l rightjoin editoriales as e on e.codigo=codigoeditorial where codigoeditorial is null;PROBLEMA RESUELTOProblema:Una librería almacena la información de sus libros para la venta en dos tablas, "libros" y"editoriales".Eliminamos ambas tablas, si existen y las creamos: if object_id(libros) is not null drop table libros; if object_id(editoriales) is not null drop table editoriales; create table libros( codigo int identity, titulo varchar(40), autor varchar(30) default Desconocido, codigoeditorial tinyint not null, precio decimal(5,2) ); create table editoriales( codigo tinyint identity, nombre varchar(20), primary key (codigo));Ingresamos algunos registros en ambas tablas: insert into editoriales values(Planeta); insert into editoriales values(Emece); insert into editoriales values(Siglo XXI);insert into libros values(El aleph,Borges,1,20);insert into libros values(Martin Fierro,Jose Hernandez,1,30);insert into libros values(Aprenda PHP,Mario Molina,2,50);insert into libros values(Java en 10 minutos,default,4,45);Solicitamos el título y nombre de la editorial de los libros empleando un "right join": select titulo,nombre from libros as l right join editoriales as e on codigoeditorial = e.codigo;
    • Las editoriales de las cuales no hay libros, es decir, cuyo código de editorial no está presente en"libros" aparece en el resultado, pero con el valor "null" en el campo "titulo".Realizamos la misma consulta anterior agregando un "where" que restringa el resultadoconsiderando solamente los registros que encuentran coincidencia en la tabla izquierda: select titulo,nombre from libros as l right join editoriales as e on e.codigo=codigoeditorial where codigoeditorial is not null;Mostramos las editoriales que NO están presentes en "libros" (que NO encuentran coincidencia en"editoriales"): select titulo,nombre from libros as l right join editoriales as e on e.codigo=codigoeditorial where codigoeditorial is null;PROBLEMA A RESOLVERPrimer problema:Una empresa tiene registrados sus clientes en una tabla llamada "clientes", también tiene unatabla "provincias" donde registra los nombres de las provincias.1- Elimine las tablas "clientes" y "provincias", si existen y cree las tablas: if (object_id(clientes)) is not null drop table clientes; if (object_id(provincias)) is not null drop table provincias;create table clientes ( codigo int identity, nombre varchar(30), domicilio varchar(30), ciudad varchar(20), codigoprovincia tinyint not null, primary key(codigo));create table provincias( codigo tinyint identity, nombre varchar(20), primary key (codigo));2- Ingrese algunos registros para ambas tablas: insert into provincias (nombre) values(Cordoba); insert into provincias (nombre) values(Santa Fe); insert into provincias (nombre) values(Corrientes);insert into clientes values (Lopez Marcos,Colon 111,Córdoba,1);
    • insert into clientes values (Perez Ana,San Martin 222,Cruz del Eje,1);insert into clientes values (Garcia Juan,Rivadavia 333,Villa Maria,1);insert into clientes values (Perez Luis,Sarmiento 444,Rosario,2);insert into clientes values (Gomez Ines,San Martin 666,Santa Fe,2);insert into clientes values (Torres Fabiola,Alem 777,La Plata,4);insert into clientes values (Garcia Luis,Sucre 475,Santa Rosa,5);3- Muestre todos los datos de los clientes, incluido el nombre de la provincia empleando un "rightjoin".4- Obtenga la misma salida que la consulta anterior pero empleando un "left join".5- Empleando un "right join", muestre solamente los clientes de las provincias que existen en"provincias" (5 registros)6- Muestre todos los clientes cuyo código de provincia NO existe en "provincias" ordenados porciudad (2 registros)69 - Combinación externa completa (full join)DETALLE DE CONCEPTOVimos que un "left join" encuentra registros de la tabla izquierda que se correspondan con losregistros de la tabla derecha y si un valor de la tabla izquierda no se encuentra en la tabla derecha,el registro muestra los campos correspondientes a la tabla de la derecha seteados a "null".Aprendimos también que un "right join" opera del mismo modo sólo que la tabla derecha es la quelocaliza los registros en la tabla izquierda.Una combinación externa completa ("full outer join" o "full join") retorna todos los registros deambas tablas. Si un registro de una tabla izquierda no encuentra coincidencia en la tabla derecha,las columnas correspondientes a campos de la tabla derecha aparecen seteadas a "null", y si latabla de la derecha no encuentra correspondencia en la tabla izquierda, los campos de esta últimaaparecen conteniendo "null".Veamos un ejemplo: select titulo,nombre from editoriales as e full join libros as l on codigoeditorial = e.codigo;La salida del "full join" precedente muestra todos los registros de ambas tablas, incluyendo loslibros cuyo código de editorial no existe en la tabla "editoriales" y las editoriales de las cuales nohay correspondencia en "libros".PROBLEMA RESUELTOProblema:
    • Una librería almacena la información de sus libros para la venta en dos tablas, "libros" y"editoriales".Eliminamos ambas tablas, si existen y las creamos: if object_id(libros) is not null drop table libros; if object_id(editoriales) is not null drop table editoriales; create table libros( codigo int identity, titulo varchar(40), autor varchar(30) default Desconocido, codigoeditorial tinyint not null, precio decimal(5,2) ); create table editoriales( codigo tinyint identity, nombre varchar(20), primary key (codigo));Ingresamos algunos registros en ambas tablas: insert into editoriales values(Planeta); insert into editoriales values(Emece); insert into editoriales values(Siglo XXI); insert into libros values(El aleph,Borges,1,20); insert into libros values(Martin Fierro,Jose Hernandez,1,30); insert into libros values(Aprenda PHP,Mario Molina,2,50); insert into libros values(Java en 10 minutos,default,4,45);Realizamos una combinación externa completa para obtener todos los registros de ambas tablas,incluyendo los libros cuyo código de editorial no existe en la tabla "editoriales" y las editoriales delas cuales no hay correspondencia en "libros": select titulo,nombre from editoriales as e full join libros as l on codigoeditorial = e.codigo;PROBLEMA A RESOLVERPrimer problema:Un club dicta clases de distintos deportes. Almacena la información en una tabla llamada"deportes"en la cual incluye el nombre del deporte y el nombre del profesor y en otra tabla llamada"inscriptos" que incluye el documento del socio que se inscribe, el deporte y si la matricula estápaga o no.1- Elimine las tablas si existen y cree las tablas: if (object_id(deportes)) is not null drop table deportes; if (object_id(inscriptos)) is not null
    • drop table inscriptos;create table deportes( codigo tinyint identity, nombre varchar(30), profesor varchar(30), primary key (codigo));create table inscriptos( documento char(8), codigodeporte tinyint not null, matricula char(1) --s=paga n=impaga);2- Ingrese algunos registros para ambas tablas: insert into deportes values(tenis,Marcelo Roca); insert into deportes values(natacion,Marta Torres); insert into deportes values(basquet,Luis Garcia); insert into deportes values(futbol,Marcelo Roca);insert into inscriptos values(22222222,3,s);insert into inscriptos values(23333333,3,s);insert into inscriptos values(24444444,3,n);insert into inscriptos values(22222222,2,s);insert into inscriptos values(23333333,2,s);insert into inscriptos values(22222222,4,n);insert into inscriptos values(22222222,5,n);3- Muestre todos la información de la tabla "inscriptos", y consulte la tabla "deportes" paraobtener el nombre de cada deporte (6 registros)4- Empleando un "left join" con "deportes" obtenga todos los datos de los inscriptos (7 registros)5- Obtenga la misma salida anterior empleando un "rigth join".6- Muestre los deportes para los cuales no hay inscriptos, empleando un "left join" (1 registro)7- Muestre los documentos de los inscriptos a deportes que no existen en la tabla "deportes" (1registro)8- Emplee un "full join" para obtener todos los datos de ambas tablas, incluyendo las inscripcionesa deportes inexistentes en "deportes" y los deportes que no tienen inscriptos (8 registros)70 - Combinaciones cruzadas (cross join)DETALLE DE CONCEPTOVimos que hay tres tipos de combinaciones: 1) combinaciones internas (join), 2) combinacionesexternas (left, right y full join) y 3) combinaciones cruzadas.Las combinaciones cruzadas (cross join) muestran todas las combinaciones de todos los registrosde las tablas combinadas. Para este tipo de join no se incluye una condición de enlace. Se genera
    • el producto cartesiano en el que el número de filas del resultado es igual al número de registros dela primera tabla multiplicado por el número de registros de la segunda tabla, es decir, si hay 5registros en una tabla y 6 en la otra, retorna 30 filas.La sintaxis básica es ésta: select CAMPOS from TABLA1 cross join TABLA2;Veamos un ejemplo. Un pequeño restaurante almacena los nombres y precios de sus comidas enuna tabla llamada "comidas" y en una tabla denominada "postres" los mismos datos de suspostres.Si necesitamos conocer todas las combinaciones posibles para un menú, cada comida con cadapostre, empleamos un "cross join": select c.nombre as plato principal, p.nombre as postre from comidas as c cross join postres as p;La salida muestra cada plato combinado con cada uno de los postres.Como cualquier tipo de "join", puede emplearse una cláusula "where" que condicione la salida.PROBLEMA RESUELTOProblema:Un pequeño restaurante tiene almacenados los nombres y precios de sus comidas en una tablallamada "comidas" y en una tabla denominada "postres" los mismos datos de sus postres.Eliminamos las tablas, si existen: if object_id(comidas) is not null drop table comidas; if object_id(postres) is not null drop table postres;Creamos las tablas: create table comidas( codigo tinyint identity, nombre varchar(30), precio decimal(4,2) ); create table postres( codigo tinyint identity, nombre varchar(30), precio decimal(4,2) );Ingresamos algunos registros: insert into comidas values(ravioles,5); insert into comidas values(tallarines,4); insert into comidas values(milanesa,7); insert into comidas values(cuarto de pollo,6);insert into postres values(flan,2.5);insert into postres values(porcion torta,3.5);
    • El restaurante quiere combinar los registros de ambas tablas para mostrar los distintos menúesque ofrece. Lo hacemos usando un "cross join": select c.nombre as plato principal, p.nombre as postre, c.precio+p.precio as total from comidas as c cross join postres as p;La salida muestra cada plato combinado con cada uno de los postres, agregamos una columnaque calcula el precio total de cada menú. Se obtienen 8 registros.PROBLEMA A RESOLVERPrimer problema:Una agencia matrimonial almacena la información de sus clientes de sexo femenino en una tablallamada "mujeres" y en otra la de sus clientes de sexo masculino llamada "varones".1- Elimine las tablas si existen y créelas: if object_id(mujeres) is not null drop table mujeres; if object_id(varones) is not null drop table varones; create table mujeres( nombre varchar(30), domicilio varchar(30), edad int ); create table varones( nombre varchar(30), domicilio varchar(30), edad int );2- Ingrese los siguientes registros: insert into mujeres values(Maria Lopez,Colon 123,45); insert into mujeres values(Liliana Garcia,Sucre 456,35); insert into mujeres values(Susana Lopez,Avellaneda 98,41);insert into varones values(Juan Torres,Sarmiento 755,44);insert into varones values(Marcelo Oliva,San Martin 874,56);insert into varones values(Federico Pereyra,Colon 234,38);insert into varones values(Juan Garcia,Peru 333,50);3- La agencia necesita la combinación de todas las personas de sexo femenino con las de sexomasculino. Use un "cross join" (12 registros)4- Realice la misma combinación pero considerando solamente las personas mayores de 40 años(6registros)5- Forme las parejas pero teniendo en cuenta que no tengan una diferencia superior a 10 años (8
    • registros)71 - AutocombinaciónDETALLE DE CONCEPTODijimos que es posible combinar una tabla consigo misma.Un pequeño restaurante tiene almacenadas sus comidas en una tabla llamada "comidas" queconsta de los siguientes campos:- nombre varchar(20),- precio decimal (4,2) y- rubro char(6)-- que indica con plato si es un plato principal y postre si es postre.Podemos obtener la combinación de platos empleando un "cross join" con una sola tabla: select c1.nombre as plato principal, c2.nombre as postre, c1.precio+c2.precio as total from comidas as c1 cross join comidas as c2;En la consulta anterior aparecen filas duplicadas, para evitarlo debemos emplear un "where": select c1.nombre as plato principal, c2.nombre as postre, c1.precio+c2.precio as total from comidas as c1 cross join comidas as c2 where c1.rubro=plato and c2.rubro=postre;En la consulta anterior se empleó un "where" que especifica que se combine "plato" con "postre".En una autocombinación se combina una tabla con una copia de si misma. Para ello debemosutilizar 2 alias para la tabla. Para evitar que aparezcan filas duplicadas, debemos emplear un"where".También se puede realizar una autocombinación con "join": select c1.nombre as plato principal, c2.nombre as postre, c1.precio+c2.precio as total from comidas as c1 join comidas as c2 on c1.codigo<>c2.codigo where c1.rubro=plato and c2.rubro=postre;Para que no aparezcan filas duplicadas se agrega un "where".PROBLEMA RESUELTOProblema:Un pequeño restaurante tiene almacenados los nombres, precios y rubro de sus comidas en unatabla llamada "comidas".Eliminamos la tabla, si existe: if object_id(comidas) is not null
    • drop table comidas;Creamos la tabla: create table comidas( codigo int identity, nombre varchar(30), precio decimal(4,2), rubro char(6),-- plato=plato principal, postre=postre primary key(codigo) );Ingresamos algunos registros: insert into comidas values(ravioles,5,plato); insert into comidas values(tallarines,4,plato); insert into comidas values(milanesa,7,plato); insert into comidas values(cuarto de pollo,6,plato); insert into comidas values(flan,2.5,postre); insert into comidas values(porcion torta,3.5,postre);Realizamos un "cross join": select c1.nombre as plato principal, c2.nombre as postre, c1.precio+c2.precio as total from comidas as c1 cross join comidas as c2;Note que aparecen filas duplicadas, por ejemplo, "ravioles" se combina con "ravioles" y lacombinación "ravioles- flan" se repite como "flan- ravioles". Debemos especificar que combine elrubro "plato" con "postre": select c1.nombre as plato principal, c2.nombre as postre, c1.precio+c2.precio as total from comidas as c1 cross join comidas as c2 where c1.rubro=plato and c2.rubro=postre;La salida muestra cada plato combinado con cada postre, y una columna extra que calcula el totaldel menú.También se puede realizar una autocombinación con "join": select c1.nombre as plato principal, c2.nombre as postre, c1.precio+c2.precio as total from comidas as c1 join comidas as c2 on c1.codigo<>c2.codigo where c1.rubro=plato and c2.rubro=postre;Para que no aparezcan filas duplicadas se agrega un "where".PROBLEMA A RESOLVERPrimer problema:Una agencia matrimonial almacena la información de sus clientes en una tabla llamada "clientes".
    • 1- Elimine la tabla si existe y créela: if object_id(clientes) is not null drop table clientes;create table clientes( nombre varchar(30), sexo char(1),--f=femenino, m=masculino edad int, domicilio varchar(30));2- Ingrese los siguientes registros: insert into clientes values(Maria Lopez,f,45,Colon 123); insert into clientes values(Liliana Garcia,f,35,Sucre 456); insert into clientes values(Susana Lopez,f,41,Avellaneda 98); insert into clientes values(Juan Torres,m,44,Sarmiento 755); insert into clientes values(Marcelo Oliva,m,56,San Martin 874); insert into clientes values(Federico Pereyra,m,38,Colon 234); insert into clientes values(Juan Garcia,m,50,Peru 333);3- La agencia necesita la combinación de todas las personas de sexo femenino con las de sexomasculino. Use un "cross join" (12 registros)4- Obtenga la misma salida enterior pero realizando un "join".5- Realice la misma autocombinación que el punto 3 pero agregue la condición que las parejas notengan una diferencia superior a 5 años (5 registros).72 - Combinaciones y funciones de agrupamientoDETALLE DE CONCEPTOPodemos usar "group by" y las funciones de agrupamiento con combinaciones de tablas.Para ver la cantidad de libros de cada editorial consultando la tabla "libros" y "editoriales",tipeamos: select nombre as editorial, count(*) as cantidad from editoriales as e join libros as l on codigoeditorial=e.codigo group by e.nombre;Note que las editoriales que no tienen libros no aparecen en la salida porque empleamos un "join".Empleamos otra función de agrupamiento con "left join". Para conocer el mayor precio de los librosde cada editorial usamos la función "max()", hacemos un "left join" y agrupamos por nombre de laeditorial: select nombre as editorial, max(precio) as mayor precio from editoriales as e
    • left join libros as l on codigoeditorial=e.codigo group by nombre;En la sentencia anterior, mostrará, para la editorial de la cual no haya libros, el valor "null" en lacolumna calculada.PROBLEMA RESUELTOProblema:Una librería almacena la información de sus libros para la venta en dos tablas, "libros" y"editoriales".Eliminamos ambas tablas, si existen y las creamos: if object_id(libros) is not null drop table libros; if object_id(editoriales) is not null drop table editoriales; create table libros( codigo int identity, titulo varchar(40), autor varchar(30), codigoeditorial tinyint not null, precio decimal(5,2) ); create table editoriales( codigo tinyint identity, nombre varchar(20), primary key (codigo));Ingresamos algunos registros en ambas tablas: insert into editoriales values(Planeta); insert into editoriales values(Emece); insert into editoriales values(Siglo XXI);insert into libros values(El aleph,Borges,1,20);insert into libros values(Martin Fierro,Jose Hernandez,1,30);insert into libros values(Aprenda PHP,Mario Molina,3,50);insert into libros values(Uno,Richard Bach,3,15);insert into libros values(Java en 10 minutos,default,4,45);Contamos la cantidad de libros de cada editorial consultando ambas tablas:select nombre as editorial, count(*) as cantidad from editoriales as e join libros as l on codigoeditorial=e.codigo group by e.nombre;Buscamos el libro más costoso de cada editorial con un "left join":select nombre as editorial, max(precio) as mayor precio
    • from editoriales as e left join libros as l on codigoeditorial=e.codigo group by nombre;PROBLEMA A RESOLVERPrimer problema:Un comercio que tiene un stand en una feria registra en una tabla llamada "visitantes" algunosdatosde las personas que visitan o compran en su stand para luego enviarle publicidad de sus productosyen otra tabla llamada "ciudades" los nombres de las ciudades.1- Elimine las tablas si existen: if object_id(visitantes) is not null drop table visitantes; if object_id(ciudades) is not null drop table ciudades;2- Cree las tablas: create table visitantes( nombre varchar(30), edad tinyint, sexo char(1) default f, domicilio varchar(30), codigociudad tinyint not null, mail varchar(30), montocompra decimal (6,2) );create table ciudades( codigo tinyint identity, nombre varchar(20));3- Ingrese algunos registros: insert into ciudades values(Cordoba); insert into ciudades values(Carlos Paz); insert into ciudades values(La Falda); insert into ciudades values(Cruz del Eje);insert into visitantes values (Susana Molina, 35,f,Colon 123, 1, null,59.80);insert into visitantes values (Marcos Torres, 29,m,Sucre 56, 1, marcostorres@hotmail.com,150.50);insert into visitantes values (Mariana Juarez, 45,f,San Martin 111,2,null,23.90);insert into visitantes values (Fabian Perez,36,m,Avellaneda 213,3,fabianperez@xaxamail.com,0);
    • insert into visitantes values (Alejandra Garcia,28,f,null,2,null,280.50);insert into visitantes values (Gaston Perez,29,m,null,5,gastonperez1@gmail.com,95.40);insert into visitantes values (Mariana Juarez,33,f,null,2,null,90);4- Cuente la cantidad de visitas por ciudad mostrando el nombre de la ciudad (3 filas)5- Muestre el promedio de gastos de las visitas agrupados por ciudad y sexo (4 filas)6- Muestre la cantidad de visitantes con mail, agrupados por ciudad (3 filas)7- Obtenga el monto de compra más alto de cada ciudad (3 filas)73 - Combinación de más de dos tablasDETALLE DE CONCEPTOPodemos hacer un "join" con más de dos tablas.Cada join combina 2 tablas. Se pueden emplear varios join para enlazar varias tablas. Cadaresultado de un join es una tabla que puede combinarse con otro join.La librería almacena los datos de sus libros en tres tablas: libros, editoriales y autores.En la tabla "libros" un campo "codigoautor" hace referencia al autor y un campo "codigoeditorial"referencia la editorial.Para recuperar todos los datos de los libros empleamos la siguiente consulta: select titulo,a.nombre,e.nombre from autores as a join libros as l on codigoautor=a.codigo join editoriales as e on codigoeditorial=e.codigo;Analicemos la consulta anterior. Indicamos el nombre de la tabla luego del "from" ("autores"),combinamos esa tabla con la tabla "libros" especificando con "on" el campo por el cual secombinarán; luego debemos hacer coincidir los valores para el enlace con la tabla "editoriales"enlazándolas por los campos correspondientes. Utilizamos alias para una sentencia más sencilla ycomprensible.Note que especificamos a qué tabla pertenecen los campos cuyo nombre se repiten en las tablas,esto es necesario para evitar confusiones y ambiguedades al momento de referenciar un campo.Note que no aparecen los libros cuyo código de autor no se encuentra en "autores" y cuya editorialno existe en "editoriales", esto es porque realizamos una combinación interna.Podemos combinar varios tipos de join en una misma sentencia: select titulo,a.nombre,e.nombre from autores as a right join libros as l on codigoautor=a.codigo left join editoriales as e on codigoeditorial=e.codigo;
    • En la consulta anterior solicitamos el título, autor y editorial de todos los libros que encuentren o nocoincidencia con "autores" ("right join") y a ese resultado lo combinamos con "editoriales",encuentren o no coincidencia.Es posible realizar varias combinaciones para obtener información de varias tablas. Las tablasdeben tener claves externas relacionadas con las tablas a combinar.En consultas en las cuales empleamos varios "join" es importante tener en cuenta el orden de lastablas y los tipos de "join"; recuerde que la tabla resultado del primer join es la que se combina conel segundo join, no la segunda tabla nombrada. En el ejemplo anterior, el "left join" no se realizaentre las tablas "libros" y "editoriales" sino entre el resultado del "right join" y la tabla "editoriales".PROBLEMA RESUELTOProblema:Una librería almacena la información de sus libros para la venta en tres tablas, "libros", "autores" y"editoriales".Eliminamos las tablas, si existen y las creamos: if object_id(libros) is not null drop table libros; if object_id(autores) is not null drop table autores; if object_id(editoriales) is not null drop table editoriales;create table libros( codigo int identity, titulo varchar(40), codigoautor int not null, codigoeditorial tinyint not null, precio decimal(5,2), primary key(codigo));create table autores( codigo int identity, nombre varchar(20), primary key (codigo)); create table editoriales( codigo tinyint identity, nombre varchar(20), primary key (codigo) );Ingresamos algunos registros: insert into editoriales values(Planeta); insert into editoriales values(Emece); insert into editoriales values(Siglo XXI); insert into editoriales values(Plaza);
    • insert into autores values (Richard Bach);insert into autores values (Borges);insert into autores values (Jose Hernandez);insert into autores values (Mario Molina);insert into autores values (Paenza); insert into libros values(El aleph,2,2,20); insert into libros values(Martin Fierro,3,1,30); insert into libros values(Aprenda PHP,4,3,50); insert into libros values(Uno,1,1,15); insert into libros values(Java en 10 minutos,0,3,45); insert into libros values(Matematica estas ahi,0,0,15); insert into libros values(Java de la A a la Z,4,0,50);Recuperamos todos los datos de los libros consultando las tres tablas: select titulo,a.nombre,e.nombre,precio from autores as a join libros as l on codigoautor=a.codigo join editoriales as e on codigoeditorial=e.codigo;Los libros cuyo código de autor no se encuentra en "autores" (caso de "Java en 10 minutos" y"Matematica estas ahi") y cuya editorial no existe en "editoriales" (caso de "Matematica estas ahi" y"Java de la A a la Z"), no aparecen porque realizamos una combinación interna.Podemos combinar varios tipos de join en una misma sentencia: select titulo,a.nombre,e.nombre,precio from autores as a right join libros as l on codigoautor=a.codigo left join editoriales as e on codigoeditorial=e.codigo;En la consulta anterior solicitamos el título, autor y editorial de todos los libros que encuentren o nocoincidencia con "autores" ("right join") y a ese resultado lo combinamos con "editoriales",encuentren o no coincidencia.PROBLEMA A RESOLVERPrimer problema:Un club dicta clases de distintos deportes. En una tabla llamada "socios" guarda los datos de lossocios, en una tabla llamada "deportes" la información referente a los diferentes deportes que sedictan y en una tabla denominada "inscriptos", las inscripciones de los socios a los distintosdeportes.Un socio puede inscribirse en varios deportes el mismo año. Un socio no puede inscribirse en elmismo deporte el mismo año. Distintos socios se inscriben en un mismo deporte en el mismo año.1- Elimine las tablas si existen: if object_id(socios) is not null drop table socios; if object_id(deportes) is not null drop table deportes; if object_id(inscriptos) is not null
    • drop table inscriptos;2- Cree las tablas con las siguientes estructuras: create table socios( documento char(8) not null, nombre varchar(30), domicilio varchar(30), primary key(documento) ); create table deportes( codigo tinyint identity, nombre varchar(20), profesor varchar(15), primary key(codigo) ); create table inscriptos( documento char(8) not null, codigodeporte tinyint not null, anio char(4), matricula char(1),--s=paga, n=impaga primary key(documento,codigodeporte,anio) );3- Ingrese algunos registros en "socios": insert into socios values(22222222,Ana Acosta,Avellaneda 111); insert into socios values(23333333,Betina Bustos,Bulnes 222); insert into socios values(24444444,Carlos Castro,Caseros 333); insert into socios values(25555555,Daniel Duarte,Dinamarca 44);4- Ingrese algunos registros en "deportes": insert into deportes values(basquet,Juan Juarez); insert into deportes values(futbol,Pedro Perez); insert into deportes values(natacion,Marina Morales); insert into deportes values(tenis,Marina Morales);5- Inscriba a varios socios en el mismo deporte en el mismo año: insert into inscriptos values (22222222,3,2006,s); insert into inscriptos values (23333333,3,2006,s); insert into inscriptos values (24444444,3,2006,n);6- Inscriba a un mismo socio en el mismo deporte en distintos años: insert into inscriptos values (22222222,3,2005,s); insert into inscriptos values (22222222,3,2007,n);7- Inscriba a un mismo socio en distintos deportes el mismo año: insert into inscriptos values (24444444,1,2006,s); insert into inscriptos values (24444444,2,2006,s);8- Ingrese una inscripción con un código de deporte inexistente y un documento de socio que noexista en "socios":
    • insert into inscriptos values (26666666,0,2006,s);9- Muestre el nombre del socio, el nombre del deporte en que se inscribió y el año empleandodiferentes tipos de join.10- Muestre todos los datos de las inscripciones (excepto los códigos) incluyendo aquellasinscripciones cuyo código de deporte no existe en "deportes" y cuyo documento de socio no seencuentra en "socios".11- Muestre todas las inscripciones del socio con documento "22222222".74 - Combinaciones con update y deleteDETALLE DE CONCEPTOLas combinaciones no sólo se utilizan con la sentencia "select", también podemos emplearlas con"update" y "delete".Podemos emplear "update" o "delete" con "join" para actualizar o eliminar registros de una tablaconsultando otras tablas.En el siguiente ejemplo aumentamos en un 10% los precios de los libros de cierta editorial,necesitamos un "join" para localizar los registros de la editorial "Planeta" en la tabla "libros": update libros set precio=precio+(precio*0.1) from libros join editoriales as e on codigoeditorial=e.codigo where nombre=Planeta;Eliminamos todos los libros de editorial "Emece": delete libros from libros join editoriales on codigoeditorial = editoriales.codigo where editoriales.nombre=Emece;PROBLEMA RESUELTOProblema:Una librería almacena la información de sus libros para la venta en dos tablas, "libros" y"editoriales".Eliminamos ambas tablas, si existen: if object_id(libros) is not null drop table libros; if object_id(editoriales) is not null drop table editoriales;Creamos las tablas: create table libros( codigo int identity, titulo varchar(40),
    • autor varchar(30) default Desconocido, codigoeditorial tinyint not null, precio decimal(5,2) ); create table editoriales( codigo tinyint identity, nombre varchar(20), primary key (codigo));Ingresamos algunos registros en ambas tablas: insert into editoriales values(Planeta); insert into editoriales values(Emece); insert into editoriales values(Siglo XXI);insert into libros values(El aleph,Borges,2,20);insert into libros values(Martin Fierro,Jose Hernandez,1,30);insert into libros values(Aprenda PHP,Mario Molina,3,50);insert into libros values(Java en 10 minutos,default,3,45);Aumentamos en un 10% los precios de los libros de editorial "Planeta":update libros set precio=precio+(precio*0.1) from libros join editoriales as e on codigoeditorial=e.codigo where nombre=Planeta;Veamos el resultado:select titulo,autor,e.nombre,precio from libros as l join editoriales as e on codigoeditorial=e.codigo;Eliminamos todos los libros de editorial "Emece":delete libros from libros join editoriales on codigoeditorial = editoriales.codigo where editoriales.nombre=Emece;Veamos si se eliminaron:select titulo,autor,e.nombre,precio from libros as l join editoriales as e on codigoeditorial=e.codigo;75 - Clave foráneaDETALLE DE CONCEPTOUn campo que no es clave primaria en una tabla y sirve para enlazar sus valores con otra tabla enla cual es clave primaria se denomina clave foránea, externa o ajena.En el ejemplo de la librería en que utilizamos las tablas "libros" y "editoriales" con estos campos: libros: codigo (clave primaria), titulo, autor, codigoeditorial, precio y
    • editoriales: codigo (clave primaria), nombre.el campo "codigoeditorial" de "libros" es una clave foránea, se emplea para enlazar la tabla "libros"con "editoriales" y es clave primaria en "editoriales" con el nombre "codigo".Las claves foráneas y las claves primarias deben ser del mismo tipo para poder enlazarse. Simodificamos una, debemos modificar la otra para que los valores se correspondan.Cuando alteramos una tabla, debemos tener cuidado con las claves foráneas. Si modificamos eltipo, longitud o atributos de una clave foránea, ésta puede quedar inhabilitada para hacer losenlaces.Entonces, una clave foránea es un campo (o varios) empleados para enlazar datos de 2 tablas,para establecer un "join" con otra tabla en la cual es clave primaria.76 - Restricciones (foreign key)DETALLE DE CONCEPTOHemos visto que una de las alternativas que SQL Server ofrece para asegurar la integridad dedatos es el uso de restricciones (constraints). Aprendimos que las restricciones se establecen entablas y campos asegurando que los datos sean válidos y que las relaciones entre las tablas semantengan; vimos que existen distintos tipos de restricciones:1) de los campos: default y check2) de la tabla: primary key y unique.3) referencial: foreign key, la analizaremos ahora.Con la restricción "foreign key" se define un campo (o varios) cuyos valores coinciden con la claveprimaria de la misma tabla o de otra, es decir, se define una referencia a un campo con unarestricción "primary key" o "unique" de la misma tabla o de otra.La integridad referencial asegura que se mantengan las referencias entre las claves primarias y lasexternas. Por ejemplo, controla que si se agrega un código de editorial en la tabla "libros", talcódigo exista en la tabla "editoriales".También controla que no pueda eliminarse un registro de una tabla ni modificar la clave primaria siuna clave externa hace referencia al registro. Por ejemplo, que no se pueda eliminar o modificar uncódigo de "editoriales" si existen libros con dicho código.La siguiente es la sintaxis parcial general para agregar una restricción "foreign key": alter table NOMBRETABLA1 add constraint NOMBRERESTRICCION foreign key (CAMPOCLAVEFORANEA) references NOMBRETABLA2 (CAMPOCLAVEPRIMARIA);Analicémosla:- NOMBRETABLA1 referencia el nombre de la tabla a la cual le aplicamos la restricción,- NOMBRERESTRICCION es el nombre que le damos a la misma,- luego de "foreign key", entre paréntesis se coloca el campo de la tabla a la que le aplicamos larestricción que será establecida como clave foránea,- luego de "references" indicamos el nombre de la tabla referenciada y el campo que es claveprimaria en la misma, a la cual hace referencia la clave foránea. La tabla referenciada debe tenerdefinida una restricción "primary key" o "unique"; si no la tiene, aparece un mensaje de error.Para agregar una restricción "foreign key" al campo "codigoeditorial" de "libros", tipeamos: alter table libros add constraint FK_libros_codigoeditorial foreign key (codigoeditorial)
    • references editoriales(codigo);En el ejemplo implementamos una restricción "foreign key" para asegurarnos que el código de laeditorial de la de la tabla "libros" ("codigoeditorial") esté asociada con un código válido en la tabla"editoriales" ("codigo").Cuando agregamos cualquier restricción a una tabla que contiene información, SQL Servercontrola los datos existentes para confirmar que cumplen con la restricción, si no los cumple, larestricción no se aplica y aparece un mensaje de error. Por ejemplo, si intentamos agregar unarestricción "foreign key" a la tabla "libros" y existe un libro con un valor de código para editorial queno existe en la tabla "editoriales", la restricción no se agrega.Actúa en inserciones. Si intentamos ingresar un registro (un libro) con un valor de clave foránea(codigoeditorial) que no existe en la tabla referenciada (editoriales), SQL server muestra unmensaje de error. Si al ingresar un registro (un libro), no colocamos el valor para el campo claveforánea (codigoeditorial), almacenará "null", porque esta restricción permite valores nulos (a menosque se haya especificado lo contrario al definir el campo).Actúa en eliminaciones y actualizaciones. Si intentamos eliminar un registro o modificar un valor declave primaria de una tabla si una clave foránea hace referencia a dicho registro, SQL Server no lopermite (excepto si se permite la acción en cascada, tema que veremos posteriormente). Porejemplo, si intentamos eliminar una editorial a la que se hace referencia en "libros", aparece unmensaje de error.Esta restricción (a diferencia de "primary key" y "unique") no crea índice automaticamente.La cantidad y tipo de datos de los campos especificados luego de "foreign key" DEBEN coincidircon la cantidad y tipo de datos de los campos de la cláusula "references".Esta restricción se puede definir dentro de la misma tabla (lo veremos más adelante) o entredistintas tablas.Una tabla puede tener varias restricciones "foreign key".No se puede eliminar una tabla referenciada en una restricción "foreign key", aparece un mensajede error.Una restriccion "foreign key" no puede modificarse, debe eliminarse y volverse a crear.Para ver información acerca de esta restricción podemos ejecutar el procedimiento almacenado"sp_helpconstraint" junto al nombre de la tabla. Nos muestra el tipo, nombre, la opción paraeliminaciones y actualizaciones, el estado (temas que veremos más adelante), el nombre delcampo y la tabla y campo que referencia.También informa si la tabla es referenciada por una clave foránea.77 - Restricciones foreign key en la misma tablaDETALLE DE CONCEPTOLa restricción "foreign key", que define una referencia a un campo con una restricción "primary key"o "unique" se puede definir entre distintas tablas (como hemos aprendido) o dentro de la mismatabla.Veamos un ejemplo en el cual definimos esta restricción dentro de la misma tabla.Una mutual almacena los datos de sus afiliados en una tabla llamada "afiliados". Algunos afiliadosinscriben a sus familiares. La tabla contiene un campo que hace referencia al afiliado que loincorporó a la mutual, del cual dependen.La estructura de la tabla es la siguiente: create table afiliados( numero int identity not null,
    • documento char(8) not null, nombre varchar(30), afiliadotitular int, primary key (documento), unique (numero) );En caso que un afiliado no haya sido incorporado a la mutual por otro afiliado, el campo"afiliadotitular" almacenará "null".Establecemos una restricción "foreign key" para asegurarnos que el número de afiliado que seingrese en el campo "afiliadotitular" exista en la tabla "afiliados": alter table afiliados add constraint FK_afiliados_afiliadotitular foreign key (afiliadotitular) references afiliados (numero);La sintaxis es la misma, excepto que la tabla se autoreferencia.Luego de aplicar esta restricción, cada vez que se ingrese un valor en el campo "afiliadotitular",SQL Server controlará que dicho número exista en la tabla, si no existe, mostrará un mensaje deerror.Si intentamos eliminar un afiliado que es titular de otros afiliados, no se podrá hacer, a menos quese haya especificado la acción en cascada (próximo tema).78 - Restricciones foreign key (acciones)DETALLE DE CONCEPTOContinuamos con la restricción "foreign key".Si intentamos eliminar un registro de la tabla referenciada por una restricción "foreign key" cuyovalor de clave primaria existe referenciada en la tabla que tiene dicha restricción, la acción no seejecuta y aparece un mensaje de error. Esto sucede porque, por defecto, para eliminaciones, laopción de la restricción "foreign key" es "no action". Lo mismo sucede si intentamos actualizar unvalor de clave primaria de una tabla referenciada por una "foreign key" existente en la tablaprincipal.La restricción "foreign key" tiene las cláusulas "on delete" y "on update" que son opcionales.Estas cláusulas especifican cómo debe actuar SQL Server frente a eliminaciones y modificacionesde las tablas referenciadas en la restricción.Las opciones para estas cláusulas son las siguientes:- "no action": indica que si intentamos eliminar o actualizar un valor de la clave primaria de la tablareferenciada (TABLA2) que tengan referencia en la tabla principal (TABLA1), se genere un error yla acción no se realice; es la opción predeterminada.- "cascade": indica que si eliminamos o actualizamos un valor de la clave primaria en la tablareferenciada (TABLA2), los registros coincidentes en la tabla principal (TABLA1), también seeliminen o modifiquen; es decir, si eliminamos o modificamos un valor de campo definido con unarestricción "primary key" o "unique", dicho cambio se extiende al valor de clave externa de la otratabla (integridad referencial en cascada).La sintaxis completa para agregar esta restricción a una tabla es la siguiente: alter table TABLA1 add constraint NOMBRERESTRICCION foreign key (CAMPOCLAVEFORANEA)
    • references TABLA2(CAMPOCLAVEPRIMARIA) on delete OPCION on update OPCION;Sintetizando, si al agregar una restricción foreign key:- no se especifica acción para eliminaciones (o se especifica "no_action"), y se intenta eliminar unregistro de la tabla referenciada (editoriales) cuyo valor de clave primaria (codigo) existe en la tablaprincipal (libros), la acción no se realiza.- se especifica "cascade" para eliminaciones ("on delete cascade") y elimina un registro de la tablareferenciada (editoriales) cuyo valor de clave primaria (codigo) existe en la tabla principal(libros), laeliminación de la tabla referenciada (editoriales) se realiza y se eliminan de la tabla principal (libros)todos los registros cuyo valor coincide con el registro eliminado de la tabla referenciada(editoriales).- no se especifica acción para actualizaciones (o se especifica "no_action"), y se intenta modificarun valor de clave primaria (codigo) de la tabla referenciada (editoriales) que existe en el campoclave foránea (codigoeditorial) de la tabla principal (libros), la acción no se realiza.- se especifica "cascade" para actualizaciones ("on update cascade") y se modifica un valor declave primaria (codigo) de la tabla referenciada (editoriales) que existe en la tabla principal (libros),SQL Server actualiza el registro de la tabla referenciada (editoriales) y todos los registroscoincidentes en la tabla principal (libros).Veamos un ejemplo. Definimos una restricción "foreign key" a la tabla "libros" estableciendo elcampo "codigoeditorial" como clave foránea que referencia al campo "codigo" de la tabla"editoriales". La tabla "editoriales" tiene como clave primaria el campo "codigo". Especificamos laacción en cascada para las actualizaciones y eliminaciones: alter table libros add constraint FK_libros_codigoeditorial foreign key (codigoeditorial) references editoriales(codigo) on update cascade on delete cascade;Si luego de establecer la restricción anterior, eliminamos una editorial de "editoriales" de las cualeshay libros, se elimina dicha editorial y todos los libros de tal editorial. Y si modificamos el valor decódigo de una editorial de "editoriales", se modifica en "editoriales" y todos los valores iguales de"codigoeditorial" de libros también se modifican.79 - Restricciones foreign key deshabilitar y eliminar (with check - nocheck)DETALLE DE CONCEPTOSabemos que si agregamos una restricción a una tabla que contiene datos, SQL Server loscontrola para asegurarse que cumplen con la restricción; es posible deshabilitar estacomprobación.Podemos hacerlo al momento de agregar la restricción a una tabla con datos, incluyendo la opción"with nocheck" en la instrucción "alter table"; si se emplea esta opción, los datos no van a cumplirla restricción.Se pueden deshabilitar las restricciones "check" y "foreign key", a las demás se las debe eliminar.La sintaxis básica al agregar la restriccción "foreign key" es la siguiente: alter table NOMBRETABLA1 with OPCIONDECHEQUEO add constraint NOMBRECONSTRAINT
    • foreign key (CAMPOCLAVEFORANEA) references NOMBRETABLA2 (CAMPOCLAVEPRIMARIA) on update OPCION on delete OPCION;La opción "with OPCIONDECHEQUEO" especifica si se controlan los datos existentes o no con"check" y "nocheck" respectivamente. Por defecto, si no se especifica, la opción es "check".En el siguiente ejemplo agregamos una restricción "foreign key" que controla que todos los códigosde editorial tengan un código válido, es decir, dicho código exista en "editoriales". La restricción nose aplica en los datos existentes pero si en los siguientes ingresos, modificaciones yactualizaciones: alter table libros with nocheck add constraint FK_libros_codigoeditorial foreing key (codigoeditorial) references editoriales(codigo);La comprobación de restricciones se puede deshabilitar para modificar, eliminar o agregar datos auna tabla sin comprobar la restricción. La sintaxis general es: alter table NOMBRETABLA OPCIONDECHEQUEO constraint NOMBRERESTRICCION;En el siguiente ejemplo deshabilitamos la restricción creada anteriormente: alter table libros nocheck constraint FK_libros_codigoeditorial;Para habilitar una restricción deshabilitada se ejecuta la misma instrucción pero con la cláusula"check" o "check all": alter table libros check constraint FK_libros_codigoeditorial;Si se emplea "check constraint all" no se coloca nombre de restricciones, habilita todas lasrestricciones que tiene la tabla nombrada ("check" y "foreign key").Para saber si una restricción está habilitada o no, podemos ejecutar el procedimiento almacenado"sp_helpconstraint" y entenderemos lo que informa la columna "status_enabled".Entonces, las cláusulas "check" y "nocheck" permiten habilitar o deshabilitar restricciones "foreignkey" (y "check"). Pueden emplearse para evitar la comprobación de datos existentes al crear larestricción o para deshabilitar la comprobación de datos al ingresar, actualizar y eliminar algúnregistro que infrinja la restricción.Podemos eliminar una restricción "foreign key" con "alter table". La sintaxis básica es la misma quepara cualquier otra restricción: alter table TABLA drop constraint NOMBRERESTRICCION;Eliminamos la restricción de "libros": alter table libros drop constraint FK_libros_codigoeditorial;No se puede eliminar una tabla si una restricción "foreign key" hace referencia a ella.Cuando eliminamos una tabla que tiene una restricción "foreign key", la restricción también seelimina.PROBLEMA RESUELTOProblema:
    • Una librería almacena la información de sus libros para la venta en dos tablas, "libros" y"editoriales".Eliminamos ambas tablas, si existen: if object_id(libros) is not null drop table libros; if object_id(editoriales) is not null drop table editoriales;Creamos las tablas: create table libros( codigo int not null, titulo varchar(40), autor varchar(30), codigoeditorial tinyint, primary key (codigo) ); create table editoriales( codigo tinyint not null, nombre varchar(20), primary key (codigo) );Ingresamos algunos registros: insert into editoriales values(1,Planeta); insert into editoriales values(2,Emece); insert into editoriales values(3,Paidos); insert into libros values(1,Uno,Richard Bach,1); insert into libros values(2,El aleph,Borges,2); insert into libros values(3,Aprenda PHP,Mario Molina,5);Agregamos una restricción "foreign key" a la tabla "libros" para evitar que se ingresen códigos deeditoriales inexistentes en "editoriales". Incluimos la opción "with nocheck" para evitar lacomprobación de la restricción en los datos existentes (note que hay un libro que tiene un códigode editorial inválido): alter table libros with nocheck add constraint FK_libros_codigoeditorial foreign key (codigoeditorial) references editoriales(codigo);La deshabilitación de la comprobación de la restricción no afecta a los siguientes ingresos,modificaciones y actualizaciones. Para poder ingresar, modificar o eliminar datos a una tabla sinque SQL Server compruebe la restricción debemos deshabilitarla: alter table libros nocheck constraint FK_libros_codigoeditorial;Veamos si la restricción está habilitada o no:sp_helpconstraint libros;En la columna "status_enabled" de la restricción "foreign key" aparece "Disabled".Veamos las restricciones de "editoriales":sp_helpconstraint editoriales;Aparece la restricción "primary key" y nos informa que hay una restricción "foreign key" que hacereferencia a ella de la tabla "libros" (aunque esté deshabilitada).
    • Ahora podemos ingresar un registro en "libros" con código inválido:insert into libros values(4,Ilusiones,Richard Bach,6);También podemos modificar:update editoriales set codigo=8 where codigo=1;También realizar eliminaciones:delete from editoriales where codigo=2;Habilitamos la restricción:alter table libros check constraint FK_libros_codigoeditorial;Veamos si la restricción está habilitada o no:sp_helpconstraint libros;En la columna "status_enabled" aparece "Enabled".Eliminamos la restricción:alter table libros drop constraint FK_libros_codigoeditorial;Ejecutamos el procedimiento almacenado sp_helpconstraint para ver si la restricción se eliminó:sp_helpconstraint libros;No aparece la restricción "foreign key".Vemos las restricciones de "editoriales":sp_helpconstraint editoriales;No aparece la restricción "foreign key" que hace referencia a esta tabla.80 - Restricciones foreign key (información)DETALLE DE CONCEPTOEl procedimiento almacenado "sp_helpconstraint" devuelve las siguientes columnas:- constraint_type: tipo de restricción. Si es una restricción de campo (default o check) indica sobrequé campo fue establecida. Si es de tabla (primary key o unique) indica el tipo de índice creado. Sies una "foreign key" lo indica.- constraint_name: nombre de la restricción.- delete_action: solamente es aplicable para restricciones de tipo "foreign key". Indica si la acciónde eliminación actúa, no actúa o es en cascada. Indica "n/a" en cualquier restricción para la que nose aplique; "No Action" si no actúa y "Cascade" si es en cascada.- update_action: sólo es aplicable para restricciones de tipo "foreign key". Indica si la acción deactualización es: No Action, Cascade, or n/a. Indica "n/a" en cualquier restricción para la que no seaplique.- status_enabled: solamente es aplicable para restricciones de tipo "check" y "foreign key". Indica siestá habilitada (Enabled) o no (Disabled). Indica "n/a" en cualquier restricción para la que no seaplique.- status_for_replication: solamente es aplicable para restricciones de tipo "check" y "foreign key".Indica "n/a" en cualquier restricción para la que no se aplique.- constraint_keys: Si es una restricción "default" muestra la condición de chequeo; si es unarestricción "default", el valor por defecto; si es una "primary key", "unique" o "foreign key" muestrael/ los campos a los que se aplicaron la restricción. En caso de valores predeterminados y reglas,el texto que lo define.
    • 81 - Restricciones al crear la tablaDETALLE DE CONCEPTOHasta el momento hemos agregado restricciones a tablas existentes con "alter table" (maneraaconsejada), también pueden establecerse al momento de crear una tabla (en la instrucción"create table").Podemos aplicar restricciones a nivel de campo (restricción de campo) o a nivel de tabla(restricción de tabla).En el siguiente ejemplo creamos la tabla "libros" con varias restricciones: create table libros( codigo int identity, titulo varchar(40), codigoautor int not null, codigoeditorial tinyint not null, precio decimal(5,2) constraint DF_precio default (0), constraint PK_libros_codigo primary key clustered (codigo), constraint UQ_libros_tituloautor unique (titulo,codigoautor), constraint FK_libros_editorial foreign key (codigoeditorial) references editoriales(codigo) on update cascade, constraint FK_libros_autores foreign key (codigoautor) references autores(codigo) on update cascade, constraint CK_precio_positivo check (precio>=0));En el ejemplo anterior creamos:- una restricción "default" para el campo "precio" (restricción a nivel de campo);- una restricción "primary key" con índice agrupado para el campo "codigo" (a nivel de tabla);- una restricción "unique" con índice no agrupado (por defecto) para los campos "titulo" y"codigoautor" (a nivel de tabla);- una restricción "foreign key" para establecer el campo "codigoeditorial" como clave externa quehaga referencia al campo "codigo" de "editoriales y permita actualizaciones en cascada y noeliminaciones (por defecto "no action");- una restricción "foreign key" para establecer el campo "codigoautor" como clave externa que hagareferencia al campo "codigo" de "autores" y permita actualizaciones en cascada y no eliminaciones;- una restricción "check" para el campo "precio" que no admita valores negativos;Si definimos una restricción "foreign key" al crear una tabla, la tabla referenciada debe existir.PROBLEMA RESUELTOProblema:Trabajamos con las tablas "libros", "autores" y "editoriales" de una librería:Eliminamos las tablas si existen:if object_id(libros) is not null drop table libros;
    • if object_id(editoriales) is not null drop table editoriales; if object_id(autores) is not null drop table autores;Creamos la tabla "editoriales" con una restricción "primary key": create table editoriales( codigo tinyint not null, nombre varchar(30), constraint PK_editoriales primary key (codigo));Creamos la tabla "autores" con una restricción "primary key", una "unique" y una "check": create table autores( codigo int not null constraint CK_autores_codigo check (codigo>=0), nombre varchar(30) not null, constraint PK_autores_codigo primary key (codigo), constraint UQ_autores_nombre unique (nombre),);Aplicamos varias restricciones cuando creamos la tabla "libros": create table libros( codigo int identity, titulo varchar(40), codigoautor int not null, codigoeditorial tinyint not null, precio decimal(5,2) constraint DF_libros_precio default (0), constraint PK_libros_codigo primary key clustered (codigo), constraint UQ_libros_tituloautor unique (titulo,codigoautor), constraint FK_libros_editorial foreign key (codigoeditorial) references editoriales(codigo) on update cascade, constraint FK_libros_autores foreign key (codigoautor) references autores(codigo) on update cascade, constraint CK_libros_precio_positivo check (precio>=0));Veamos las restricciones de "editoriales": sp_helpconstraint editoriales;Aparece la restricción "primary key" para el campo "codigo" y la restricción "foreign key" de "libros""FK_libros_editorial" que referencia esta tabla.Veamos las restricciones de "autores": sp_helpconstraint autores;
    • Aparecen 4 restricciones: una restricción "check" para el campo "codigo", una restricción "primarykey" para el campo "codigo", una restricción "unique" para el campo "nombre" y la restricción"foreign key" de "libros" "FK_libros_autores" que referencia esta tabla.Veamos las restricciones de "libros": sp_helpconstraint libros;Aparecen 6 restricciones: una restricción "check" sobre el campo "precio", una "default" sobre elcampo "precio", una restricción "foreign key" que establece el campo "codigoeditorial" como claveexterna que hace referencia al campo "codigo" de "editoriales" y permite actualizaciones encascada y no eliminaciones, una restricción "foreign key" que establece el campo "codigoautor"como clave externa que hace referencia al campo "codigo" de "autores" y permite actualizacionesen cascada y no eliminaciones, una restricción "primary key" con índice agrupado para el campo"codigo" y una restricción "unique" con índice no agrupado para los campos "titulo" y "codigoautor".Recuerde que si definimos una restricción "foreign key" al crear una tabla, la tabla referenciadadebe existir, por ello creamos las tablas "editoriales" y "autores" antes que "libros".También debemos ingresar registros en las tablas "autores" y "editoriales" antes que en "libros", amenos que deshabilitemos la restricción "foreign key".82 - UniónDETALLE DE CONCEPTOEl operador "union" combina el resultado de dos o más instrucciones "select" en un únicoresultado.Se usa cuando los datos que se quieren obtener pertenecen a distintas tablas y no se puedeacceder a ellos con una sola consulta.Es necesario que las tablas referenciadas tengan tipos de datos similares, la misma cantidad decampos y el mismo orden de campos en la lista de selección de cada consulta. No se incluyen lasfilas duplicadas en el resultado, a menos que coloque la opción "all".Se deben especificar los nombres de los campos en la primera instrucción "select".Puede emplear la cláusula "order by".Puede dividir una consulta compleja en varias consultas "select" y luego emplear el operador"union" para combinarlas.Una academia de enseñanza almacena los datos de los alumnos en una tabla llamada "alumnos" ylos datos de los profesores en otra denominada "profesores".La academia necesita el nombre y domicilio de profesores y alumnos para enviarles una tarjeta deinvitación.Para obtener los datos necesarios de ambas tablas en una sola consulta necesitamos realizar unaunión: select nombre, domicilio from alumnos union select nombre, domicilio from profesores;El primer "select" devuelve el nombre y domicilio de todos los alumnos; el segundo, el nombre ydomicilio de todos los profesores.Los encabezados del resultado de una unión son los que se especifican en el primer "select".PROBLEMA RESUELTO
    • Problema:Una academia de enseñanza almacena los datos de los alumnos en una tabla llamada "alumnos" ylos datos de los profesores en otra denominada "profesores".Eliminamos las tablas si existen: if object_id(alumnos) is not null drop table alumnos; if object_id(profesores) is not null drop table profesores;Creamos las tablas: create table profesores( documento varchar(8) not null, nombre varchar (30), domicilio varchar(30), primary key(documento) ); create table alumnos( documento varchar(8) not null, nombre varchar (30), domicilio varchar(30), primary key(documento) );Ingresamos algunos registros: insert into alumnos values(30000000,Juan Perez,Colon 123); insert into alumnos values(30111111,Marta Morales,Caseros 222); insert into alumnos values(30222222,Laura Torres,San Martin 987); insert into alumnos values(30333333,Mariano Juarez,Avellaneda 34); insert into alumnos values(23333333,Federico Lopez,Colon 987); insert into profesores values(22222222,Susana Molina,Sucre 345); insert into profesores values(23333333,Federico Lopez,Colon 987);La academia necesita el nombre y domicilio de profesores y alumnos para enviarles una tarjeta deinvitación.Empleamos el operador "union" para obtener dicha información de ambas tablas: select nombre, domicilio from alumnos union select nombre, domicilio from profesores;Note que existe un profesor que también está presente en la tabla "alumnos"; dicho registroaparece una sola vez en el resultado de "union". Si queremos que las filas duplicadas aparezcan,debemos emplear "all": select nombre, domicilio from alumnos union all select nombre, domicilio from profesores;Ordenamos por domicilio: select nombre, domicilio from alumnos union select nombre, domicilio from profesores order by domicilio;Podemos agregar una columna extra a la consulta con el encabezado "condicion" en la queaparezca el literal "profesor" o "alumno" según si la persona es uno u otro: select nombre, domicilio, alumno as condicion from alumnos
    • union select nombre, domicilio,profesor from profesores order by condicion;83 - Agregar y eliminar campos ( alter table - add - drop)DETALLE DE CONCEPTO"alter table" permite modificar la estructura de una tabla.Podemos utilizarla para agregar, modificar y eliminar campos de una tabla.Para agregar un nuevo campo a una tabla empleamos la siguiente sintaxis básica: alter table NOMBRETABLA add NOMBRENUEVOCAMPO DEFINICION;En el siguiente ejemplo agregamos el campo "cantidad" a la tabla "libros", de tipo tinyint, queacepta valores nulos: alter table libros add cantidad tinyint;Puede verificarse la alteración de la estructura de la tabla ejecutando el procedimiento almacenado"sp_columns".SQL Server no permite agregar campos "not null" a menos que se especifique un valor por defecto: alter table libros add autor varchar(20) not null default Desconocido;En el ejemplo anterior, se agregó una restricción "default" para el nuevo campo, que puedeverificarse ejecutando el procedimiento almacenado "sp_helpconstraint".Al agregar un campo puede especificarse que sea "identity" (siempre que no exista otro campoidentity).Para eliminar campos de una tabla la sintaxis básica es la siguiente: alter table NOMBRETABLA drop column NOMBRECAMPO;En el siguiente ejemplo eliminamos el campo "precio" de la tabla "libros": alter table libros drop column precio;No pueden eliminarse los campos que son usados por un índice o tengan restricciones. No puedeeliminarse un campo si es el único en la tabla.Podemos eliminar varios campos en una sola sentencia: alter table libros drop column editorial,edicion;84 - Alterar campos (alter table - alter)DETALLE DE CONCEPTOHemos visto que "alter table" permite modificar la estructura de una tabla. También podemosutilizarla para modificar campos de una tabla.La sintaxis básica para modificar un campo existente es la siguiente: alter table NOMBRETABLA alter column CAMPO NUEVADEFINICION;Modificamos el campo "titulo" extendiendo su longitud y para que NO admita valores nulos: alter table libros
    • alter column titulo varchar(40) not null;En el siguiente ejemplo alteramos el campo "precio" de la tabla "libros" que fue definido"decimal(6,2) not null" para que no acepte valores nulos: alter table libros alter column precio decimal(6,2) null;SQL Server tiene algunas excepciones al momento de modificar los campos. No permite modificar:- campos de tipo text, image, ntext y timestamp.- un campo que es usado en un campo calculado.- campos que son parte de índices o tienen restricciones, a menos que el cambio no afecte alíndice o a la restricción, por ejemplo, se puede ampliar la longitud de un campo de tipo caracter.- agregando o quitando el atributo "identity".- campos que afecten a los datos existentes cuando una tabla contiene registros (ejemplo: uncampo contiene valores nulos y se pretende redefinirlo como "not null"; un campo int guarda unvalor 300 y se pretende modificarlo a tinyint, etc.).85 - Agregar campos y restricciones (alter table)DETALLE DE CONCEPTOPodemos agregar un campo a una tabla y en el mismo momento aplicarle una restricción.Para agregar un campo y establecer una restricción, la sintaxis básica es la siguiente:alter table TABLAadd CAMPO DEFINICIONconstraint NOMBRERESTRICCION TIPO;Agregamos a la tabla "libros", el campo "titulo" de tipo varchar(30) y una restricción "unique" coníndice agrupado:alter table librosadd titulo varchar(30)constraint UQ_libros_autor unique clustered;Agregamos a la tabla "libros", el campo "codigo" de tipo int identity not null y una restricción"primary key" con índice no agrupado:alter table librosadd codigo int identity not nullconstraint PK_libros_codigo primary key nonclustered;Agregamos a la tabla "libros", el campo "precio" de tipo decimal(6,2) y una restricción "check":alter table librosadd precio decimal(6,2)constraint CK_libros_precio check (precio>=0);PROBLEMA RESUELTO
    • Problema:Trabajamos con la tabla "libros" de una librería.Eliminamos la tabla, si existe:if object_id(libros) is not null drop table libros;Creamos la tabla con la siguiente estructura:create table libros( autor varchar(30), editorial varchar(15));Agregamos el campo "titulo" de tipo varchar(30) y una restricción "unique" con índice agrupado:alter table librosadd titulo varchar(30)constraint UQ_libros_autor unique clustered;Veamos si la estructura cambió:sp_columns libros;Agregamos el campo "codigo" de tipo int identity not null y en la misma sentencia una restricción"primary key" con índice no agrupado:alter table librosadd codigo int identity not nullconstraint PK_libros_codigo primary key nonclustered;Agregamos el campo "precio" de tipo decimal(6,2) y una restricción "check" que no permita valoresnegativos para dicho campo:alter table librosadd precio decimal(6,2)constraint CK_libros_precio check (precio>=0);Vemos las restricciones:sp_helpconstraint libros;86 - Campos calculadosDETALLE DE CONCEPTOUn campo calculado es un campo que no se almacena físicamente en la tabla. SQL Server empleauna fórmula que detalla el usuario al definir dicho campo para calcular el valor según otros camposde la misma tabla.
    • Un campo calculado no puede:- definirse como "not null".- ser una subconsulta.- tener restricción "default" o "foreign key".- insertarse ni actualizarse.Puede ser empleado como llave de un índice o parte de restricciones "primary key" o "unique" si laexpresión que la define no cambia en cada consulta.Creamos un campo calculado denominado "sueldototal" que suma al sueldo básico de cadaempleado la cantidad abonada por los hijos (100 por cada hijo):create table empleados( documento char(8), nombre varchar(10), domicilio varchar(30), sueldobasico decimal(6,2), cantidadhijos tinyint default 0, sueldototal as sueldobasico + (cantidadhijos*100));También se puede agregar un campo calculado a una tabla existente:alter table NOMBRETABLAadd NOMBRECAMPOCALCULADO as EXPRESION;alter table empleadosadd sueldototal as sueldo+(cantidadhijos*100);Los campos de los cuales depende el campo calculado no pueden eliminarse, se debe eliminarprimero el campo calculado.PROBLEMA RESUELTOProblema:Trabajamos con la tablas "empleados".Eliminamos la tabla, si existe, y la creamos:if object_id(empleados) is not null drop table empleados;create table empleados( documento char(8), nombre varchar(10), domicilio varchar(30),
    • sueldobasico decimal(6,2), hijos tinyint not null default 0, sueldototal as sueldobasico + (hijos*100));El campo "sueldototal" es un campo calculado que suma al sueldo básico de cada empleado y lacantidad abonada por los hijos (100 por cada hijo).No puede ingresarse valor para dicho campo:insert into empleados values(22222222,Juan Perez,Colon 123,300,2);insert into empleados values(23333333,Ana Lopez,Sucre 234,500,0);Veamos los registros:select *from empleados;Veamos lo que sucede si actualizamos un registro:update empleados set hijos=1 where documento=23333333;select *from empleados;Recuperamos los registros:select *from empleados;el campo calculado "sueldototal" recalcula los valores para cada registro automáticamente.Agregamos un campo calculado:alter table empleadosadd salariofamiliar as hijos*100;Veamos la estructura de la tabla:sp_columns empleados;Recuperemos los registros:select *from empleados;87 - Tipo de dato definido por el usuario (crear - informacion)DETALLE DE CONCEPTOCuando definimos un campo de una tabla debemos especificar el tipo de datos, sabemos que lostipos de datos especifican el tipo de información (caracteres, números, fechas) que puedenalmacenarse en un campo. SQL Server proporciona distintos tipos de datos del sistema (char,
    • varchar, int, decimal, datetime, etc.) y permite tipos de datos definidos por el usuario siempre quese basen en los tipos de datos existentes.Se pueden crear y eliminar tipos de datos definidos por el usuario.Se emplean cuando varias tablas deben almacenar el mismo tipo de datos en un campo y sequiere garantizar que todas tengan el mismo tipo y longitud.Para darle un nombre a un tipo de dato definido por el usuario debe considerar las mismas reglasque para cualquier identificador. No puede haber dos objetos con igual nombre en la misma basede datos.Para crear un tipo de datos definido por el usuario se emplea el procedimiento almacenado delsistema "sp_addtype". Sintaxis básica:exec sp_addtype NOMBRENUEVOTIPO, TIPODEDATODELSISTEMA, OPCIONNULL;Creamos un tipo de datos definido por el usuario llamado "tipo_documento" que admite valoresnulos:exec sp_addtype tipo_documento, char(8), null;Ejecutando el procedimiento almacenado "sp_help" junto al nombre del tipo de dato definido por elusuario se obtiene información del mismo (nombre, el tipo de dato en que se basa, la longitud, siacepta valores nulos, si tiene valor por defecto y reglas asociadas).También podemos consultar la tabla "systypes" en la cual se almacena información de todos lostipos de datos:select name from systypes;88 - Tipo de dato definido por el usuario (asociación de reglas)DETALLE DE CONCEPTOSe puede asociar una regla a un tipo de datos definido por el usuario. Luego de crear la regla seestablece la asociación; la sintaxis es la siguiente:exec sp_bindrule NOMBREREGLA, TIPODEDATODEFINIDOPORELUSUARIO, futureonly;El parámetro "futureonly" es opcional, especifica que si existen campos (de cualquier tabla) coneste tipo de dato, no se asocien a la regla; si creamos una nueva tabla con este tipo de dato, sideberán cumplir la regla. Si no se especifica este parámetro, todos los campos de este tipo dedato, existentes o que se creen posteriormente (de cualquier tabla), quedan asociados a la regla.Recuerde que SQL Server NO controla los datos existentes para confirmar que cumplen con laregla, si no los cumple, la regla se asocia igualmente; pero al ejecutar una instrucción "insert" o"update" muestra un mensaje de error.
    • Si asocia una regla a un tipo de dato definido por el usuario que tiene otra regla asociada, estaúltima la reemplaza.Para quitar la asociación, empleamos el mismo procedimiento almacenado que aprendimoscuando quitamos asociaciones a campos, ejecutamos el procedimiento almacenado"sp_unbindrule" seguido del nombre del tipo de dato al que está asociada la regla:exec sp_unbindrule TIPODEDATODEFINIDOPORELUSUARIO;Si asocia una regla a un campo cuyo tipo de dato definido por el usuario ya tiene una reglaasociada, la nueva regla se aplica al campo, pero el tipo de dato continúa asociado a la regla. Laregla asociada al campo prevalece sobre la asociada al tipo de dato. Por ejemplo, tenemos uncampo "precio" de un tipo de dato definido por el usuario "tipo_precio", este tipo de dato tieneasociada una regla "RG_precio0a99" (precio entre 0 y 99), luego asociamos al campo "precio" laregla "RG_precio100a500" (precio entre 100 y 500); al ejecutar una instrucción "insert" admitirávalores entre 100 y 500, es decir, tendrá en cuenta la regla asociada al campo, aunque vaya contrala regla asociada al tipo de dato.Un tipo de dato definido por el usuario puede tener una sola regla asociada.Cuando obtenemos información del tipo da dato definido por el usuario ejecutando "sp_help", en lacolumna "rule_name" se muestra el nombre de la regla asociada a dicho tipo de dato; muestran"none" cuando no tiene regla asociada.PROBLEMA RESUELTOProblema:Una academia de enseñanza almacena los datos de sus alumnos en una tabla llamada "alumnos"y en otra tabla denominada "docentes" los datos de los profesores.Eliminamos ambas tablas, si existen:if object_id(alumnos) is not null drop table alumnos;if object_id(docentes) is not null drop table docentes;Queremos definir un nuevo tipo de dato llamado "tipo_documento". Primero debemos eliminarlo, siexiste para volver a crearlo. Para ello empleamos esta sentencia que explicaremos próximamente:if exists (select *from systypes where name = tipo_documento) exec sp_droptype tipo_documento;Creamos un tipo de dato definido por el usuario llamado "tipo_documento" basado en el tipo "char"que permita 8 caracteres y valores nulos:
    • exec sp_addtype tipo_documento, char(8), null;Ejecutamos el procedimiento almacenado "sp_help" junto al nombre del tipo de dato definidoanteriormente para obtener información del mismo:sp_help tipo_documento;Aparecen varias columnas que nos informan, entre otras cosas: el nombre (tipo_documento), eltipo de dato en que se basa (char), la longitud (8), si acepta valores nulos (yes); las columnas"default_name" y "rule_name" muestran "none" porque no tiene valores predeterminados ni reglasasociados.Creamos la tabla "alumnos" con 2 campos: documento (del tipo de dato definido anteriormente) ynombre (30 caracteres):create table alumnos( documento tipo_documento, nombre varchar(30));Eliminamos si existe, la regla "RG_documento":if object_id (RG_documento) is not null drop rule RG_documento;Creamos la regla que permita 8 caracteres que solamente pueden ser dígitos del 0 al 5 para elprimer dígito y de 0 al 9 para los siguientes:create rule RG_documento as @documento like [0-5][0-9][0-9][0-9][0-9][0-9][0-9][0-9];Asociamos la regla al tipo de datos "tipo_documento" especificando que solamente se aplique a losfuturos campos de este tipo:exec sp_bindrule RG_documento, tipo_documento, futureonly;Ejecutamos el procedimiento almacenado "sp_helpconstraint" para verificar que no se aplicó a latabla "alumnos" porque especificamos la opción "futureonly":sp_helpconstraint alumnos;Creamos la tabla "docentes" con 2 campos: documento (del tipo de dato definido anteriormente) ynombre (30 caracteres):create table docentes( documento tipo_documento, nombre varchar(30));
    • Verificamos que se aplicó la regla en la nueva tabla:sp_helpconstraint docentes;Ingresamos registros en "alumnos" con valores para documento que infrinjan la regla:insert into alumnos values(a111111,Ana Acosta);Lo acepta porque en esta tabla no se aplica la regla. Pero no podríamos ingresar un valor como elanterior en la tabla "docentes" la cual si tiene asociada la regla.Quitamos la asociación:exec sp_unbindrule tipo_documento;Volvemos a asociar la regla, ahora sin el parámetro "futureonly":exec sp_bindrule RG_documento, tipo_documento;Note que hay valores que no cumplen la regla, recuerde que SQL Server NO controla los datosexistentes al momento de asociar una regla; pero si al ejecutar un "insert" o "update".Verificamos que se aplicó la regla en ambas tablas:sp_helpconstraint docentes;exec sp_helpconstraint alumnos;Eliminamos si existe, la regla "RG_documento2":if object_id (RG_documento2) is not null drop rule RG_documento2;Creamos la regla llamada "RG_documento2" que permita 8 caracteres que solamente pueden serdígitos del 0 al 9 para todas las posiciones:create rule RG_documento2 as @documento like [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9];Asociamos la regla al tipo de datos "tipo_documento" (ya tiene una regla asociada):exec sp_bindrule RG_documento2, tipo_documento;Veamos si la asociación fue reemplazada en el tipo de datos:sp_help tipo_documento;Note que ahora en la columna "Rule_name" muestra "RG_documento2".
    • Veamos si la asociación fue reemplazada en las tablas:sp_helpconstraint alumnos;exec sp_helpconstraint docentes;Note que ahora la regla asociada es "RG_documento2".Asociamos la regla "RG_documento" al campo "documento" de "alumnos":exec sp_bindrule RG_documento, alumnos.documento;Verificamos que "documento" de "alumnos" tiene asociada la regla "RG_documento":sp_helpconstraint alumnos;Verificamos que el tipo de dato "tipo_documento" tiene asociada la regla "RG_documento2":sp_help tipo_documento;Intente ingresar un valor para "documento" aceptado por la regla asociada al tipo de dato pero nopor la regla asociada al campo:insert into alumnos values (77777777,Juan Lopez);No lo permite.Ingrese un valor para "documento" aceptado por la regla asociada al campo:insert into alumnos values (55555555,Juan Lopez);PROBLEMA A RESOLVERPrimer problema:Un comercio almacena los datos de sus empleados en una tabla denominada "empleados" y enotrallamada "clientes" los datos de sus clientes".1- Elimine ambas tablas, si existen: if object_id (empleados) is not null drop table empleados; if object_id (clientes) is not null drop table clientes;2- Defina un nuevo tipo de dato llamado "tipo_año". Primero debe eliminarlo, si existe, para volvera crearlo. Para ello emplee esta sentencia que explicaremos en el siguiente capítulo: if exists (select *from systypes where name = tipo_año) exec sp_droptype tipo_año;3- Cree un tipo de dato definido por el usuario llamado "tipo_año" basado en el tipo "int" que
    • permita valores nulos: exec sp_addtype tipo_año, int,null;4- Ejecute el procedimiento almacenado "sp_help" junto al nombre del tipo de dato definidoanteriormente para obtener información del mismo: sp_help tipo_año;5- Cree la tabla "empleados" con 3 campos: documento (char de 8), nombre (30 caracteres) yañoingreso (tipo_año): create table empleados( documento char(8), nombre varchar(30), añoingreso tipo_año );6- Elimine la regla llamada "RG_año" si existe: if object_id (RG_año) is not null drop rule RG_año;7- Cree la regla que permita valores integer desde 1990 (año en que se inauguró el comercio) y elaño actual: create rule RG_año as @año between 1990 and datepart(year,getdate());8- Asocie la regla al tipo de datos "tipo_año" especificando que solamente se aplique a los futuroscampos de este tipo: exec sp_bindrule RG_año, tipo_año, futureonly;9- Vea si se aplicó a la tabla empleados: sp_helpconstraint empleados;No se aplicó porque especificamos la opción "futureonly":10- Cree la tabla "clientes" con 3 campos: nombre (30 caracteres), añoingreso (tipo_año) ydomicilio(30 caracteres): create table clientes( documento char(8), nombre varchar(30), añoingreso tipo_año );11- Vea si se aplicó la regla en la nueva tabla: sp_helpconstraint clientes;Si aparece.12- Ingrese registros con valores para el año que infrinjan la regla en la tabla "empleados": insert into empleados values(11111111,Ana Acosta,2050); select *from empleados;Lo acepta porque en esta tabla no se aplica la regla.
    • 13- Intente ingresar en la tabla "clientes" un valor de fecha que infrinja la regla: insert into clientes values(22222222,Juan Perez,2050);No lo permite.14- Quite la asociación de la regla con el tipo de datos: exec sp_unbindrule tipo_año;15- Vea si se quitó la asociación: sp_helpconstraint clientes;Si se quitó.16- Vuelva a asociar la regla, ahora sin el parámetro "futureonly": exec sp_bindrule RG_año, tipo_año;Note que hay valores que no cumplen la regla pero SQL Server NO lo verifica al momento deasociaruna regla.17- Intente agregar una fecha de ingreso fuera del intervalo que admite la regla en cualquiera delas tablas (ambas tienen la asociación): insert into empleados values(33333333,Romina Guzman,1900);Mensaje de error.18- Vea la información del tipo de dato: exec sp_help tipo_año;En la columna que hace referencia a la regla asociada aparece "RG_año".19- Elimine la regla llamada "RG_añonegativo", si existe: if object_id (RG_añonegativo) is not null drop rule RG_añonegativo;20- Cree una regla llamada "RG_añonegativo" que admita valores entre -2000 y -1: create rule RG_añonegativo as @año between -2000 and -1;21- Asocie la regla "RG_añonegativo" al campo "añoingreso" de la tabla "clientes": exec sp_bindrule RG_añonegativo, clientes.añoingreso;22- Vea si se asoció: sp_helpconstraint clientes;Se asoció.23- Verifique que no está asociada al tipo de datos "tipo_año": sp_help tipo_año;No, tiene asociada la regla "RG_año".24- Intente ingresar un registro con valor -1900 para el campo "añoingreso" de "empleados": insert into empleados values(44444444,Pedro Perez,-1900);No lo permite por la regla asociada al tipo de dato.
    • 25- Ingrese un registro con valor -1900 para el campo "añoingreso" de "clientes" y recupere losregistros de dicha tabla: insert into clientes values(44444444,Pedro Perez,-1900); select *from clientes;Note que se ingreso, si bien el tipo de dato de "añoingreso" tiene asociada una regla que no admitetal valor, el campo tiene asociada una regla que si lo admite y ésta prevalece.89 - Tipo de dato definido por el usuario (valores predeterminados)DETALLE DE CONCEPTOSe puede asociar un valor predeterminado a un tipo de datos definido por el usuario. Luego decrear un valor predeterminado, se puede asociar a un tipo de dato definido por el usuario con lasiguiente sintaxis: exec sp_bindefault NOMBREVALORPREDETERMINADO,TIPODEDATODEFINIDOPORELUSUARIO,futureonly;El parámetro "futureonly" es opcional, especifica que si existen campos (de cualquier tabla) coneste tipo de dato, no se asocien al valor predeterminado; si creamos una nueva tabla con este tipode dato, si estará asociado al valor predeterminado. Si no se especifica este parámetro, todos loscampos de este tipo de dato, existentes o que se creen posteriormente (de cualquier tabla),quedan asociados al valor predeterminado.Si asocia un valor predeterminado a un tipo de dato definido por el usuario que tiene otro valorpredeterminado asociado, el último lo reemplaza.Para quitar la asociación, empleamos el mismo procedimiento almacenado que aprendimoscuando quitamos asociaciones a campos:sp_unbindefault TIPODEDATODEFINIDOPORELUSUARIO;Debe tener en cuenta que NO se puede aplicar una restricción "default" en un campo con un tipode datos definido por el usuario si dicho campo o tipo de dato tienen asociado un valorpredeterminado.Si un campo de un tipo de dato definido por el usuario tiene una restricción "default" y luego seasocia un valor predeterminado al tipo de dato, el valor predeterminado no queda asociado en elcampo que tiene la restricción "default".Un tipo de dato definido por el usuario puede tener un solo valor predeterminado asociado.Cuando obtenemos información del tipo da dato definido por el usuario ejecutando "sp_help", en lacolumna "default_name" se muestra el nombre del valor predeterminado asociado a dicho tipo dedato; muestra "none" cuando no tiene ningún valor predeterminado asociado.PROBLEMA RESUELTOProblema:
    • Una academia de enseñanza almacena los datos de sus alumnos en una tabla llamada "alumnos"y en otra tabla denominada "docentes" los datos de los profesores.Eliminamos ambas tablas, si existen:if object_id(alumnos) is not null drop table alumnos;if object_id(docentes) is not null drop table docentes;Queremos definir un nuevo tipo de dato llamado "tipo_documento". Primero debemos eliminarlo, siexiste para volver a crearlo. Para ello empleamos esta sentencia que explicaremos próximamente:if exists (select *from systypes where name = tipo_documento) exec sp_droptype tipo_documento;Creamos un tipo de dato definido por el usuario llamado "tipo_documento" basado en el tipo "char"que permita 8 caracteres y valores nulos:exec sp_addtype tipo_documento, char(8), null;Ejecutamos el procedimiento almacenado "sp_help" junto al nombre del tipo de dato definidoanteriormente para obtener información del mismo:sp_help tipo_documento;Aparecen varias columnas que nos informan, entre otras cosas: el nombre (tipo_documento), eltipo de dato en que se basa (char), la longitud (8), si acepta valores nulos (yes); las columnas"default_name" y "rule_name" muestran "none" porque no tiene valores predeterminados ni reglasasociados.Creamos la tabla "alumnos" con 2 campos: documento (del tipo de dato definido anteriormente) ynombre (30 caracteres):create table alumnos( documento tipo_documento, nombre varchar(30));Eliminamos si existe, el valor predeterminado "VP_documento0":if object_id (VP_documento0) is not null drop default VP_documento0;Creamos el valor predeterminado "VP_documento0" que almacene el valor 00000000:create default VP_documento0 as 00000000;
    • Asociamos el valor predeterminado al tipo de datos "tipo_documento" especificando que solamentese aplique a los futuros campos de este tipo:exec sp_bindefault VP_documento0, tipo_documento, futureonly;Ejecutamos el procedimiento almacenado "sp_helpconstraint" para verificar que no se aplicó a latabla "alumnos" porque especificamos la opción "futureonly":sp_helpconstraint alumnos;Creamos la tabla "docentes" con 2 campos: documento (del tipo de dato definido anteriormente) ynombre (30 caracteres):create table docentes( documento tipo_documento, nombre varchar(30));Verificamos que se aplicó el valor predeterminado creado anteriormente al campo "documento" dela nueva tabla:sp_helpconstraint docentes;Ingresamos un registro en "alumnos" sin valor para documento y vemos qué se almacenó:insert into alumnos default values;select *from alumnos;En esta tabla no se aplica el valor predeterminado por ello almacena "null", que es el valor pordefecto.Si ingresamos en la tabla "docentes" un registro con valores por defecto:insert into docentes default values;select *from docentes;Si se almacena el valor predeterminado porque está asociado.Quitamos la asociación:exec sp_unbindefault tipo_documento;Volvemos a asociar el valor predeterminado, ahora sin el parámetro "futureonly":exec sp_bindefault VP_documento0, tipo_documento;Ingresamos un registro en "alumnos" y en "docentes" sin valor para documento y vemos qué sealmacenó:
    • insert into alumnos default values;select *from alumnos;insert into docentes default values;select *from docentes;En ambas se almacenó 00000000.Eliminamos si existe, el valor predeterminado "VP_documentoDesconocido":if object_id (VP_documentoDesconocido) is not null drop default VP_documentoDesconocido;Creamos el valor predeterminado llamado "VP_documentoDesconocido" que almacene el valorSinDatos:create default VP_documentoDesconocido as SinDatos;Asociamos el valor predeterminado al tipo de datos "tipo_documento" (ya tiene otro valorpredeterminado asociado):exec sp_bindefault VP_DocumentoDesconocido, tipo_documento;Veamos si la asociación fue reemplazada en el tipo de datos:exec sp_help tipo_documento;Note que ahora en la columna "default_name" muestra "VP_documentoDesconocido".Veamos si la asociación fue reemplazada en la tabla "alumnos":sp_helpconstraint alumnos;Note que ahora el valor predeterminado asociado es "VP_documentoDesconocido".Quitamos la asociación del valor predeterminado:sp_unbindefault tipo_documento;Veamos si se quitó de ambas tablas:exec sp_helpconstraint alumnos;exec sp_helpconstraint docentes;Ingresamos un registro en "alumnos" y vemos qué se almacenó en el campo "documento":insert into alumnos default values;select *from alumnos;
    • Agregue a la tabla "docentes" una restricción "default" para el campo "documento":alter table docentesadd constraint DF_docentes_documentodefault --------for documento;Ingrese un registro en "docentes" con valores por defecto y vea qué se almacenó en "documento"recuperando los registros:insert into docentes default values;select *from docentes;Asocie el valor predeterminado "VP_documento0" al tipo de datos "tipo_documento":exec sp_bindefault VP_documento0, tipo_documento;Vea qué informa "sp_helpconstraint" acerca de la tabla "docentes":sp_helpconstraint docentes;Tiene asociado el valor por defecto establecido con la restricción "default".Ingrese un registro en "docentes" con valores por defecto y vea qué se almacenó en "documento":insert into docentes default values;select *from docentes;Note que guarda el valor por defecto establecido con la restricción.Eliminamos la restricción:alter table docentesdrop DF_docentes_documento;Vea qué informa "sp_helpconstraint" acerca de la tabla "docentes":sp_helpconstraint docentes;No tiene ningún valor por defecto asociado.Asociamos el valor predeterminado "VP_documento0" al tipo de datos "tipo_documento":exec sp_bindefault VP_documento0, tipo_documento;Intente agregar una restricción "default" al campo "documento" de "docentes":alter table docentesadd constraint DF_docentes_documento
    • default --------for documento;SQL Server no lo permite porque el tipo de dato de ese campo ya tiene un valor predeterminadoasociado.PROBLEMA A RESOLVERPrimer problema:Un comercio almacena los datos de sus empleados en una tabla denominada "empleados" y enotrallamada "clientes" los datos de sus clientes".1- Elimine ambas tablas, si existen: if object_id (empleados) is not null drop table empleados; if object_id (clientes) is not null drop table clientes;2- Defina un nuevo tipo de dato llamado "tipo_año". Primero debe eliminarlo, si existe, para volvera crearlo. Para ello emplee esta sentencia que explicaremos en el siguiente capítulo: if exists (select *from systypes where name = tipo_año) exec sp_droptype tipo_año;3- Cree un tipo de dato definido por el usuario llamado "tipo_año" basado en el tipo "int" quepermita valores nulos: exec sp_addtype tipo_año, int,null;4- Ejecute el procedimiento almacenado "sp_help" junto al nombre del tipo de dato definidoanteriormente para obtener información del mismo: sp_help tipo_año;5- Cree la tabla "empleados" con 3 campos: documento (char de 8), nombre (30 caracteres) yañoingreso (tipo_año): create table empleados( documento char(8), nombre varchar(30), añoingreso tipo_año );6- Elimine el valor predeterminado "VP_añoactual" si existe: if object_id (VP_añoactual) is not null drop default VP_añoactual;7- Cree el valor predeterminado "VP_añoactual" que almacene el año actual: create default VP_añoactual as datepart(year,getdate());
    • 8- Asocie el valor predeterminado al tipo de datos "tipo_año" especificando que solamente seapliquea los futuros campos de este tipo: exec sp_bindefault VP_añoactual, tipo_año, futureonly;9- Vea si se aplicó a la tabla empleados: sp_helpconstraint empleados;No se aplicó porque especificamos la opción "futureonly":10- Cree la tabla "clientes" con 3 campos: nombre (30 caracteres), añoingreso (tipo_año) ydomicilio(30 caracteres): create table clientes( documento char(8), nombre varchar(30), añoingreso tipo_año );11- Vea si se aplicó la regla en la nueva tabla: sp_helpconstraint clientes;Si se aplicó.12- Ingrese un registro con valores por defecto en la tabla "empleados" y vea qué se almacenó en"añoingreso": insert into empleados default values; select *from empleados;Se almacenó "null" porque en esta tabla no se aplica el valor predeterminado.13- Ingrese en la tabla "clientes" un registro con valores por defecto y recupere los registros: insert into clientes default values; select *from clientes;Se almacenó el valor predeterminado.14- Elimine el valor predeterminado llamado "VP_año2000", si existe: if object_id (VP_año2000) is not null drop default Vp_año2000;15- Cree un valor predeterminado llamado "VP_año2000" con el valor 2000: create default VP_año2000 as 2000;16- Asócielo al tipo de dato definido sin especificar "futureonly": exec sp_bindefault VP_año2000, tipo_año;17- Verifique que se asoció a la tabla "empleados": sp_helpconstraint empleados;18- Verifique que reemplazó al valor predeterminado anterior en la tabla "clientes": sp_helpconstraint clientes;
    • 18- Ingrese un registro en ambas tablas con valores por defecto y vea qué se almacenó en el añodeingreso: insert into empleados default values; select *from empleados; insert into clientes default values; select *from clientes;19- Vea la información del tipo de dato: exec sp_help tipo_año;La columna que hace referencia al valor predeterminado asociado muestra "VP_año2000".20- Intente agregar a la tabla "empleados" una restricción "default": alter table empleados add constraint DF_empleados_año default 1990 for añoingreso;No lo permite porque el tipo de dato del campo ya tiene un valor predeterminado asociado.21- Quite la asociación del valor predeterminado al tipo de dato: sp_unbindefault tipo_año;22- Agregue a la tabla "empleados" una restricción "default": alter table empleados add constraint DF_empleados_año default 1990 for añoingreso;23- Asocie el valor predeterminado "VP_añoactual" al tipo de dato "tipo_año": exec sp_bindefault VP_añoactual, tipo_año;24- Verifique que el tipo de dato tiene asociado el valor predeterminado: sp_help tipo_año;25- Verifique que la tabla "clientes" tiene asociado el valor predeterminado: sp_helpconstraint clientes;26- Verifique que la tabla "empleados" no tiene asociado el valor predeterminado "VP_añoactual"asociado al tipo de dato y tiene la restricción "default": sp_helpconstraint empleados;90 - Tipo de dato definido por el usuario (eliminar)DETALLE DE CONCEPTOPodemos eliminar un tipo de dato definido por el usuario con el procedimiento almacenado"sp_droptype":
    • exec sp_droptype TIPODEDATODEFINIDOPORELUSUARIO;Eliminamos el tipo de datos definido por el usuario llamado "tipo_documento":exec sp_droptype tipo_documento;Si intentamos eliminar un tipo de dato inexistente, aparece un mensaje indicando que no existe.Los tipos de datos definidos por el usuario se almacenan en la tabla del sistema "systypes".Podemos averiguar si un tipo de dato definido por el usuario existe para luego eliminarlo:if exists (select *from systypes where name = NOMBRETIPODEDATODEFINIDOPORELUSUARIO) exec sp_droptype TIPODEDATODEFINIDOPORELUSUARIO;Consultamos la tabla "systypes" para ver si existe el tipo de dato "tipo_documento", si es así, loeliminamos:if exists (select *from systypes where name = tipo_documento) exec sp_droptype tipo_documento;No se puede eliminar un tipo de datos definido por el usuario si alguna tabla (u otro objeto) haceuso de él; por ejemplo, si una tabla tiene un campo definido con tal tipo de dato.Si eliminamos un tipo de datos definido por el usuario, desaparecen las asociaciones de las reglasy valores predeterminados, pero tales reglas y valores predeterminados, no se eliminan, siguenexistiendo en la base de datos.91 - SubconsultasDETALLE DE CONCEPTOUna subconsulta (subquery) es una sentencia "select" anidada en otra sentencia "select", "insert","update" o "delete" (o en otra subconsulta).Las subconsultas se emplean cuando una consulta es muy compleja, entonces se la divide envarios pasos lógicos y se obtiene el resultado con una única instrucción y cuando la consultadepende de los resultados de otra consulta.Generalmente, una subconsulta se puede reemplazar por combinaciones y estas últimas son máseficientes.Las subconsultas se DEBEN incluir entre paréntesis.Puede haber subconsultas dentro de subconsultas, se admiten hasta 32 niveles de anidación.Se pueden emplear subconsultas:
    • - en lugar de una expresión, siempre que devuelvan un solo valor o una lista de valores.- que retornen un conjunto de registros de varios campos en lugar de una tabla o para obtener elmismo resultado que una combinación (join).Hay tres tipos básicos de subconsultas:las que retornan un solo valor escalar que se utiliza con un operador de comparación o en lugar deuna expresión.las que retornan una lista de valores, se combinan con "in", o los operadores "any", "some" y "all".los que testean la existencia con "exists".Reglas a tener en cuenta al emplear subconsultas:- la lista de selección de una subconsulta que va luego de un operador de comparación puedeincluir sólo una expresión o campo (excepto si se emplea "exists" y "in").- si el "where" de la consulta exterior incluye un campo, este debe ser compatible con el campo enla lista de selección de la subconsulta.- no se pueden emplear subconsultas que recuperen campos de tipos text o image.- las subconsultas luego de un operador de comparación (que no es seguido por "any" o "all") nopueden incluir cláusulas "group by" ni "having".- "distinct" no puede usarse con subconsultas que incluyan "group by".- no pueden emplearse las cláusulas "compute" y "compute by".- "order by" puede emplearse solamente si se especifica "top" también.- una vista creada con una subconsulta no puede actualizarse.- una subconsulta puede estar anidada dentro del "where" o "having" de una consulta externa odentro de otra subconsulta.- si una tabla se nombra solamente en un subconsulta y no en la consulta externa, los campos noserán incluidos en la salida (en la lista de selección de la consulta externa).92 - Subconsultas como expresiónDETALLE DE CONCEPTOUna subconsulta puede reemplazar una expresión. Dicha subconsulta debe devolver un valorescalar (o una lista de valores de un campo).Las subconsultas que retornan un solo valor escalar se utiliza con un operador de comparación oen lugar de una expresión:
    • select CAMPOS from TABLA where CAMPO OPERADOR (SUBCONSULTA);select CAMPO OPERADOR (SUBCONSULTA) from TABLA;Si queremos saber el precio de un determinado libro y la diferencia con el precio del libro máscostoso, anteriormente debíamos averiguar en una consulta el precio del libro más costoso y luego,en otra consulta, calcular la diferencia con el valor del libro que solicitamos. Podemos conseguirloen una sola sentencia combinando dos consultas:select titulo,precio, precio-(select max(precio) from libros) as diferencia from libros where titulo=Uno;En el ejemplo anterior se muestra el título, el precio de un libro y la diferencia entre el precio dellibro y el máximo valor de precio.Queremos saber el título, autor y precio del libro más costoso:select titulo,autor, precio from libros where precio= (select max(precio) from libros);Note que el campo del "where" de la consulta exterior es compatible con el valor retornado por laexpresión de la subconsulta.Se pueden emplear en "select", "insert", "update" y "delete".Para actualizar un registro empleando subconsulta la sintaxis básica es la siguiente:update TABLA set CAMPO=NUEVOVALORwhere CAMPO= (SUBCONSULTA);Para eliminar registros empleando subconsulta empleamos la siguiente sintaxis básica:delete from TABLAwhere CAMPO=(SUBCONSULTA);Recuerde que la lista de selección de una subconsulta que va luego de un operador decomparación puede incluir sólo una expresión o campo (excepto si se emplea "exists" o "in").No olvide que las subconsultas luego de un operador de comparación (que no es seguido por "any"o "all") no pueden incluir cláusulas "group by".
    • 93 - Subconsultas con inDETALLE DE CONCEPTOVimos que una subconsulta puede reemplazar una expresión. Dicha subconsulta debe devolver unvalor escalar o una lista de valores de un campo; las subconsultas que retornan una lista devalores reemplazan a una expresión en una cláusula "where" que contiene la palabra clave "in".El resultado de una subconsulta con "in" (o "not in") es una lista. Luego que la subconsulta retornaresultados, la consulta exterior los usa.La sintaxis básica es la siguiente:...where EXPRESION in (SUBCONSULTA);Este ejemplo muestra los nombres de las editoriales que ha publicado libros de un determinadoautor:select nombre from editoriales where codigo in (select codigoeditorial from libros where autor=Richard Bach);La subconsulta (consulta interna) retorna una lista de valores de un solo campo (codigo) que laconsulta exterior luego emplea al recuperar los datos.Podemos reemplazar por un "join" la consulta anterior:select distinct nombre from editoriales as e join libros on codigoeditorial=e.codigo where autor=Richard Bach;Una combinación (join) siempre puede ser expresada como una subconsulta; pero una subconsultano siempre puede reemplazarse por una combinación que retorne el mismo resultado. Si esposible, es aconsejable emplear combinaciones en lugar de subconsultas, son más eficientes.Se recomienda probar las subconsultas antes de incluirlas en una consulta exterior, así puedeverificar que retorna lo necesario, porque a veces resulta difícil verlo en consultas anidadas.También podemos buscar valores No coincidentes con una lista de valores que retorna unasubconsulta; por ejemplo, las editoriales que no han publicado libros de un autor específico:select nombre from editoriales where codigo not in (select codigoeditorial
    • from libros where autor=Richard Bach);94 - Subconsultas any - some - allDETALLE DE CONCEPTO"any" y "some" son sinónimos. Chequean si alguna fila de la lista resultado de una subconsulta seencuentra el valor especificado en la condición.Compara un valor escalar con los valores de un campo y devuelven "true" si la comparación concada valor de la lista de la subconsulta es verdadera, sino "false".El tipo de datos que se comparan deben ser compatibles.La sintaxis básica es:...VALORESCALAR OPERADORDECOMPARACION ANY (SUBCONSULTA);Queremos saber los títulos de los libros de "Borges" que pertenecen a editoriales que hanpublicado también libros de "Richard Bach", es decir, si los libros de "Borges" coinciden conALGUNA de las editoriales que publicó libros de "Richard Bach":select titulo from libros where autor=Borges and codigoeditorial = any (select e.codigo from editoriales as e join libros as l on codigoeditorial=e.codigo where l.autor=Richard Bach);La consulta interna (subconsulta) retorna una lista de valores de un solo campo (puede ejecutar lasubconsulta como una consulta para probarla), luego, la consulta externa compara cada valor de"codigoeditorial" con cada valor de la lista devolviendo los títulos de "Borges" que coinciden."all" también compara un valor escalar con una serie de valores. Chequea si TODOS los valores dela lista de la consulta externa se encuentran en la lista de valores devuelta por la consulta interna.Sintaxis: VALORESCALAR OPERADORDECOMPARACION all (SUBCONSULTA);Queremos saber si TODAS las editoriales que publicaron libros de "Borges" coinciden con TODASlas editoriales que publicaron libros de "Richard Bach":select titulo
    • from libros where autor=Borges and codigoeditorial = all (select e.codigo from editoriales as e join libros as l on codigoeditorial=e.codigo where l.autor=Richard Bach);La consulta interna (subconsulta) retorna una lista de valores de un solo campo (puede ejecutar lasubconsulta como una consulta para probarla), luego, la consulta externa compara cada valor de"codigoeditorial" con cada valor de la lista, si TODOS coinciden, devuelve los títulos.Veamos otro ejemplo con un operador de comparación diferente:Queremos saber si ALGUN precio de los libros de "Borges" es mayor a ALGUN precio de los librosde "Richard Bach":select titulo,precio from libros where autor=Borges and precio > any (select precio from libros where autor=Bach);El precio de cada libro de "Borges" es comparado con cada valor de la lista de valores retornadapor la subconsulta; si ALGUNO cumple la condición, es decir, es mayor a ALGUN precio de"Richard Bach", se lista.Veamos la diferencia si empleamos "all" en lugar de "any":select titulo,precio from libros where autor=borges and precio > all (select precio from libros where autor=bach);El precio de cada libro de "Borges" es comparado con cada valor de la lista de valores retornadapor la subconsulta; si cumple la condición, es decir, si es mayor a TODOS los precios de "RichardBach" (o al mayor), se lista.Emplear "= any" es lo mismo que emplear "in".Emplear "<> all" es lo mismo que emplear "not in".
    • Recuerde que solamente las subconsultas luego de un operador de comparación al cual esseguido por "any" o "all") pueden incluir cláusulas "group by".95 - Subconsultas correlacionadasDETALLE DE CONCEPTOUn almacén almacena la información de sus ventas en una tabla llamada "facturas" en la cualguarda el número de factura, la fecha y el nombre del cliente y una tabla denominada "detalles" enla cual se almacenan los distintos items correspondientes a cada factura: el nombre del artículo, elprecio (unitario) y la cantidad.Se necesita una lista de todas las facturas que incluya el número, la fecha, el cliente, la cantidadde artículos comprados y el total:select f.*, (select count(d.numeroitem) from Detalles as d where f.numero=d.numerofactura) as cantidad, (select sum(d.preciounitario*cantidad) from Detalles as d where f.numero=d.numerofactura) as totalfrom facturas as f;El segundo "select" retorna una lista de valores de una sola columna con la cantidad de items porfactura (el número de factura lo toma del "select" exterior); el tercer "select" retorna una lista devalores de una sola columna con el total por factura (el número de factura lo toma del "select"exterior); el primer "select" (externo) devuelve todos los datos de cada factura.A este tipo de subconsulta se la denomina consulta correlacionada. La consulta interna se evalúatantas veces como registros tiene la consulta externa, se realiza la subconsulta para cada registrode la consulta externa. El campo de la tabla dentro de la subconsulta (f.numero) se compara con elcampo de la tabla externa.En este caso, específicamente, la consulta externa pasa un valor de "numero" a la consulta interna.La consulta interna toma ese valor y determina si existe en "detalles", si existe, la consulta internadevuelve la suma. El proceso se repite para el registro de la consulta externa, la consulta externapasa otro "numero" a la consulta interna y SQL Server repite la evaluación.96 - Exists y No ExistsDETALLE DE CONCEPTOLos operadores "exists" y "not exists" se emplean para determinar si hay o no datos en una lista devalores.Estos operadores pueden emplearse con subconsultas correlacionadas para restringir el resultadode una consulta exterior a los registros que cumplen la subconsulta (consulta interior). Estos
    • operadores retornan "true" (si las subconsultas retornan registros) o "false" (si las subconsultas noretornan registros).Cuando se coloca en una subconsulta el operador "exists", SQL Server analiza si hay datos quecoinciden con la subconsulta, no se devuelve ningún registro, es como un test de existencia; SQLServer termina la recuperación de registros cuando por lo menos un registro cumple la condición"where" de la subconsulta.La sintaxis básica es la siguiente:... where exists (SUBCONSULTA);En este ejemplo se usa una subconsulta correlacionada con un operador "exists" en la cláusula"where" para devolver una lista de clientes que compraron el artículo "lapiz":select cliente,numero from facturas as f where exists (select *from Detalles as d where f.numero=d.numerofactura and d.articulo=lapiz);Puede obtener el mismo resultado empleando una combinación.Podemos buscar los clientes que no han adquirido el artículo "lapiz" empleando "if not exists":select cliente,numero from facturas as f where not exists (select *from Detalles as d where f.numero=d.numerofactura and d.articulo=lapiz);98 - Subconsulta en lugar de una tablaDETALLE DE CONCEPTOSe pueden emplear subconsultas que retornen un conjunto de registros de varios campos en lugarde una tabla.Se la denomina tabla derivada y se coloca en la cláusula "from" para que la use un "select"externo.La tabla derivada debe ir entre paréntesis y tener un alias para poder referenciarla. La sintaxisbásica es la siguiente:select ALIASdeTABLADERIVADA.CAMPOfrom (TABLADERIVADA) as ALIAS;
    • La tabla derivada es una subsonsulta.Podemos probar la consulta que retorna la tabla derivada y luego agregar el "select" externo:select f.*, (select sum(d.precio*cantidad) from Detalles as d where f.numero=d.numerofactura) as total from facturas as f;La consulta anterior contiene una subconsulta correlacionada; retorna todos los datos de "facturas"y el monto total por factura de "detalles". Esta consulta retorna varios registros y varios campos yserá la tabla derivada que emplearemos en la siguiente consulta:select td.numero,c.nombre,td.total from clientes as c join (select f.*, (select sum(d.precio*cantidad) from Detalles as d where f.numero=d.numerofactura) as total from facturas as f) as td on td.codigocliente=c.codigo;La consulta anterior retorna, de la tabla derivada (referenciada con "td") el número de factura y elmonto total, y de la tabla "clientes", el nombre del cliente. Note que este "join" no emplea 2 tablas,sino una tabla propiamente dicha y una tabla derivada, que es en realidad una subconsulta.99 - Subconsulta (update - delete)DETALLE DE CONCEPTODijimos que podemos emplear subconsultas en sentencias "insert", "update", "delete", además de"select".La sintaxis básica para realizar actualizaciones con subconsulta es la siguiente:update TABLA set CAMPO=NUEVOVALORwhere CAMPO= (SUBCONSULTA);Actualizamos el precio de todos los libros de editorial "Emece":update libros set precio=precio+(precio*0.1)where codigoeditorial= (select codigo from editoriales where nombre=Emece);
    • La subconsulta retorna un único valor. También podemos hacerlo con un join.La sintaxis básica para realizar eliminaciones con subconsulta es la siguiente:delete from TABLAwhere CAMPO in (SUBCONSULTA);Eliminamos todos los libros de las editoriales que tiene publicados libros de "Juan Perez":delete from libroswhere codigoeditorial in (select e.codigo from editoriales as e join libros on codigoeditorial=e.codigo where autor=Juan Perez);La subconsulta es una combinación que retorna una lista de valores que la consulta externaemplea al seleccionar los registros para la eliminación.100 - Subconsulta (insert)DETALLE DE CONCEPTOAprendimos que una subconsulta puede estar dentro de un "select", "update" y "delete"; tambiénpuede estar dentro de un "insert".Podemos ingresar registros en una tabla empleando un "select".La sintaxis básica es la siguiente:insert into TABLAENQUESEINGRESA (CAMPOSTABLA1) select (CAMPOSTABLACONSULTADA) from TABLACONSULTADA;Un profesor almacena las notas de sus alumnos en una tabla llamada "alumnos". Tiene otra tablallamada "aprobados", con algunos campos iguales a la tabla "alumnos" pero en ella solamentealmacenará los alumnos que han aprobado el ciclo.Ingresamos registros en la tabla "aprobados" seleccionando registros de la tabla "alumnos":insert into aprobados (documento,nota) select (documento,nota) from alumnos;Entonces, se puede insertar registros en una tabla con la salida devuelta por una consulta a otratabla; para ello escribimos la consulta y le anteponemos "insert into" junto al nombre de la tabla enla cual ingresaremos los registros y los campos que se cargarán (si se ingresan todos los camposno es necesario listarlos).
    • La cantidad de columnas devueltas en la consulta debe ser la misma que la cantidad de campos acargar en el "insert".Se pueden insertar valores en una tabla con el resultado de una consulta que incluya cualquier tipode "join".101 - Crear tabla a partir de otra (select - into)DETALLE DE CONCEPTOPodemos crear una tabla e insertar datos en ella en una sola sentencia consultando otra tabla (ovarias) con esta sintaxis:select CAMPOSNUEVATABLA into NUEVATABLA from TABLA where CONDICION;Es decir, se crea una nueva tabla y se inserta en ella el resultado de una consulta a otra tabla.Tenemos la tabla "libros" de una librería y queremos crear una tabla llamada "editoriales" quecontenga los nombres de las editoriales.La tabla "editoriales", que no existe, contendrá solamente un campo llamado "nombre". La tablalibros contiene varios registros.Podemos crear la tabla "editoriales" con el campo "nombre" consultando la tabla "libros" y en elmismo momento insertar la información:select distinct editorial as nombre into editoriales from libros;La tabla "editoriales" se ha creado con el campo "nombre" seleccionado del campo "editorial" de"libros".Los campos de la nueva tabla tienen el mismo nombre, tipo de dato y valores almacenados que loscampos listados de la tabla consultada; si se quiere dar otro nombre a los campos de la nuevatabla se deben especificar alias.Entonces, luego de la lista de selección de campos de la tabla a consultar, se coloca "into" seguidodel nombre de la nueva tabla y se sigue con la consulta.Podemos emplear "group by", funciones de agrupamiento y "order by" en las consultas. Tambiénpodemos emplear "select... into" con combinaciones, para crear una tabla que contenga datos de 2o más tablas.
    • 102 - goDETALLE DE CONCEPTOEsto solo se aplica cuando instale el SQL Server en su máquina."go" es un signo de finalización de un lote de sentencias. No es una sentencia, es un comando. Ellote de sentencias está compuesto por todas las sentencias antes de "go" o todas las sentenciasentre dos "go".Las sentencias no deben ocupar la misma linea en la que está "go".Habrá notado que no se puede ejecutar un procedimiento almacenado luego de otras sentencias amenos que se incluya "execute" (o "exec").Por ejemplo, si tipeamos:select *from empleados;sp_helpconstraint empleados;muestra un mensaje de error porque no puede procesar ambas sentencias como un solo lote. Paraque no ocurra debemos tipear:select *from empleados;exec sp_helpconstraint empleados;o separar los lotes con "go":select *from empleados;gosp_helpconstraint empleados;Las siguientes sentencias no pueden ejecutarse en el mismo lote: create rule, create default,createview, create procedure, create trigger. Cada una de ellas necesita ejecutarse separándolas con"go". Por ejemplo:create table....gocreate rule...goRecuerde que si coloca "go" no debe incluir el "punto y coma" (;) al finalizar una instrucción.No está de más recordar que esto solo se aplica cuando instale el SQL Server en su máquina yejecute los comandos desde el Query Analyzer.103 - Vistas
    • DETALLE DE CONCEPTOUna vista es una alternativa para mostrar datos de varias tablas. Una vista es como una tablavirtual que almacena una consulta. Los datos accesibles a través de la vista no están almacenadosen la base de datos como un objeto.Entonces, una vista almacena una consulta como un objeto para utilizarse posteriormente. Lastablas consultadas en una vista se llaman tablas base. En general, se puede dar un nombre acualquier consulta y almacenarla como una vista.Una vista suele llamarse también tabla virtual porque los resultados que retorna y la manera dereferenciarlas es la misma que para una tabla.Las vistas permiten:- ocultar información: permitiendo el acceso a algunos datos y manteniendo oculto el resto de lainformación que no se incluye en la vista. El usuario opera con los datos de una vista como si setratara de una tabla, pudiendo modificar tales datos.- simplificar la administración de los permisos de usuario: se pueden dar al usuario permisos paraque solamente pueda acceder a los datos a través de vistas, en lugar de concederle permisos paraacceder a ciertos campos, así se protegen las tablas base de cambios en su estructura.- mejorar el rendimiento: se puede evitar tipear instrucciones repetidamente almacenando en unavista el resultado de una consulta compleja que incluya información de varias tablas.Podemos crear vistas con: un subconjunto de registros y campos de una tabla; una unión de variastablas; una combinación de varias tablas; un resumen estadístico de una tabla; un subconjunto deotra vista, combinación de vistas y tablas.Una vista se define usando un "select".La sintaxis básica parcial para crear una vista es la siguiente:create view NOMBREVISTA as SENTENCIASSELECT from TABLA;El contenido de una vista se muestra con un "select":select *from NOMBREVISTA;En el siguiente ejemplo creamos la vista "vista_empleados", que es resultado de una combinaciónen la cual se muestran 4 campos:create view vista_empleados as select (apellido+ +e.nombre) as nombre,sexo, s.nombre as seccion, cantidadhijos from empleados as e
    • join secciones as s on codigo=seccionPara ver la información contenida en la vista creada anteriormente tipeamos:select *from vista_empleados;Podemos realizar consultas a una vista como si se tratara de una tabla:select seccion,count(*) as cantidad from vista_empleados;Los nombres para vistas deben seguir las mismas reglas que cualquier identificador. Para distinguiruna tabla de una vista podemos fijar una convención para darle nombres, por ejemplo, colocar elsufijo “vista” y luego el nombre de las tablas consultadas en ellas.Los campos y expresiones de la consulta que define una vista DEBEN tener un nombre. Se debecolocar nombre de campo cuando es un campo calculado o si hay 2 campos con el mismo nombre.Note que en el ejemplo, al concatenar los campos "apellido" y "nombre" colocamos un alias; si nolo hubiésemos hecho aparecería un mensaje de error porque dicha expresión DEBE tener unencabezado, SQL Server no lo coloca por defecto.Los nombres de los campos y expresiones de la consulta que define una vista DEBEN ser únicos(no puede haber dos campos o encabezados con igual nombre). Note que en la vista definida en elejemplo, al campo "s.nombre" le colocamos un alias porque ya había un encabezado (el alias de laconcatenación) llamado "nombre" y no pueden repetirse, si sucediera, aparecería un mensaje deerror.Otra sintaxis es la siguiente:create view NOMBREVISTA (NOMBRESDEENCABEZADOS) as SENTENCIASSELECT from TABLA;Creamos otra vista de "empleados" denominada "vista_empleados_ingreso" que almacena lacantidad de empleados por año:create view vista_empleados_ingreso (fecha,cantidad) as select datepart(year,fechaingreso),count(*) from empleados group by datepart(year,fechaingreso)La diferencia es que se colocan entre paréntesis los encabezados de las columnas que apareceránen la vista. Si no los colocamos y empleamos la sintaxis vista anteriormente, se emplean losnombres de los campos o alias (que en este caso habría que agregar) colocados en el "select" quedefine la vista. Los nombres que se colocan entre paréntesis deben ser tantos como los campos oexpresiones que se definen en la vista.
    • Las vistas se crean en la base de datos activa.Al crear una vista, SQL Server verifica que existan las tablas a las que se hacen referencia en ella.Se aconseja probar la sentencia "select" con la cual definiremos la vista antes de crearla paraasegurarnos que el resultado que retorna es el imaginado.Existen algunas restricciones para el uso de "create view", a saber:- no puede incluir las cláusulas "compute" ni "compute by" ni la palabra clave "into";- no se pueden crear vistas temporales ni crear vistas sobre tablas temporales.- no se pueden asociar reglas ni valores por defecto a las vistas.- no puede combinarse con otras instrucciones en un mismo lote.Se pueden construir vistas sobre otras vistas.104 - Vistas (información)DETALLE DE CONCEPTOLas vistas son objetos, así que para obtener información de ellos pueden usarse los siguientesprocedimientos almacenados del sistema:"sp_help" sin parámetros nos muestra todos los objetos de la base de datos seleccionada,incluidas las vistas. En la columna "Object_type" aparece "view" si es una vista. Si le enviamoscomo argumento el nombre de una vista, obtenemos la fecha de creación, propietario, los camposy demás información."sp_helptext" seguido del nombre de una vista nos muestra el texto que la define, excepto si hasido encriptado.Ejecutando "sp_depends" seguido del nombre de un objeto, obtenemos 2 resultados:- nombre, tipo, campos, etc. de los objetos de los cuales depende el objeto nombrado y- nombre y tipo de los objetos que dependen del objeto nombrado.Si ejecutamos el procedimiento "sp_depends" seguido del nombre de una vista:sp_depends vista_empleados;
    • aparecen las tablas (y demás objetos) de las cuales depende la vista, es decir, las tablasreferenciadas en la misma.Si ejecutamos el procedimiento seguido del nombre de una tabla:sp_depends empleados;aparecen los objetos que dependen de la tabla, vistas, restricciones, etc.También se puede consultar la tabla del sistema "sysobjects":select *from sysobjects;Nos muestra nombre y varios datos de todos los objetos de la base de datos actual. La columna"xtype" indica el tipo de objeto, si es una vista, aparece V.Si queremos ver todas las vistas creadas por nosotros, podemos tipear:select *from sysobjects where xtype=V and-- tipo vista name like vista%;--búsqueda con comodínPROBLEMA RESUELTOProblema:Una empresa almacena la información de sus empleados en dos tablas llamadas "empleados" y"secciones".Eliminamos las tablas, si existen:if object_id(empleados) is not null drop table empleados;if object_id(secciones) is not null drop table secciones;Creamos las tablas:create table secciones( codigo tinyint identity, nombre varchar(20), sueldo decimal(5,2) constraint CK_secciones_sueldo check (sueldo>=0), constraint PK_secciones primary key (codigo)); create table empleados( legajo int identity, documento char(8) constraint CK_empleados_documento check (documento like [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]), sexo char(1)
    • constraint CK_empleados_sexo check (sexo in (f,m)), apellido varchar(20), nombre varchar(20), domicilio varchar(30), seccion tinyint not null, cantidadhijos tinyint constraint CK_empleados_hijos check (cantidadhijos>=0), estadocivil char(10) constraint CK_empleados_estadocivil check (estadocivil in (casado,divorciado,soltero,viudo)), fechaingreso datetime, constraint PK_empleados primary key (legajo), constraint FK_empleados_seccion foreign key (seccion) references secciones(codigo) on update cascade, constraint UQ_empleados_documento unique(documento));Ingresamos algunos registros:insert into secciones values(Administracion,300);insert into secciones values(Contaduría,400);insert into secciones values(Sistemas,500); insert into empleados values(22222222,f,Lopez,Ana,Colon 123,1,2,casado,1990-10-10); insert into empleados values(23333333,m,Lopez,Luis,Sucre 235,1,0,soltero,1990-02-10); insert into empleados values(24444444,m,Garcia,Marcos,Sarmiento1234,2,3,divorciado,1998-07-12); insert into empleados values(25555555,m,Gomez,Pablo,Bulnes 321,3,2,casado,1998-10-09); insert into empleados values(26666666,f,Perez,Laura,Peru 1254,3,3,casado,2000-05-09);Eliminamos la vista "vista_empleados" si existe:if object_id(vista_empleados) is not null drop view vista_empleados;Creamos la vista "vista_empleados", que es resultado de una combinación en la cual se muestran5 campos:create view vista_empleados as select (apellido+ +e.nombre) as nombre,sexo, s.nombre as seccion, cantidadhijos from empleados as e join secciones as s on codigo=seccion;Vemos la información de la vista:
    • select *from vista_empleados;Ejecutamos "sp_help" enviándole como argumento el nombre de la vista:sp_help vista_empleados;Vemos el texto que define la vista:sp_helptext vista_empleados;Ejecutamos el procedimiento almacenado del sistema "sp_depends" seguido del nombre de lavista:sp_depends vista_empleados;aparecen las tablas y campos de las cuales depende la vista, es decir, las tablas referenciadas enla misma.Ejecutamos el procedimiento "sp_depends" seguido del nombre de la tabla "empleados":sp_depends empleados;aparece la vista "vista_empleados" y las restricciones que dependen de ella.Consultamos la tabla del sistema "sysobjects":select *from sysobjects;Si queremos ver todas las vistas creadas por nosotros, podemos tipear:select *from sysobjects where xtype=V and-- tipo vista name like vista%;--búsqueda con comodín105 - vistas (encriptar)DETALLE DE CONCEPTOPodemos ver el texto que define una vista ejecutando el procedimiento almacenado del sistema"sp_helptext" seguido del nombre de la vista:sp_helptext NOMBREVISTA;Podemos ocultar el texto que define una vista empleando la siguiente sintaxis al crearla:create view NOMBREVISTA with encryption
    • as SENTENCIASSELECT from TABLA;"with encryption" indica a SQL Server que codifique las sentencias que definen la vista.Creamos una vista con su definición oculta:create view vista_empleados with encryptionas select (apellido+ +e.nombre) as nombre,sexo, s.nombre as seccion, cantidadhijos from empleados as e join secciones as s on codigo=seccionSi ejecutamos el procedimiento almacenado del sistema "sp_helptext" seguido del nombre de unavista encriptada, aparece un mensaje indicando tal situación y el texto no se muestra.PROBLEMA RESUELTOProblema:Una empresa almacena la información de sus empleados en dos tablas llamadas "empleados" y"secciones".Eliminamos las tablas, si existen:if object_id(empleados) is not null drop table empleados;if object_id(secciones) is not null drop table secciones;Creamos las tablas:create table secciones( codigo tinyint identity, nombre varchar(20), sueldo decimal(5,2) constraint CK_secciones_sueldo check (sueldo>=0), constraint PK_secciones primary key (codigo)); create table empleados( legajo int identity, documento char(8) constraint CK_empleados_documento check (documento like [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]),
    • sexo char(1) constraint CK_empleados_sexo check (sexo in (f,m)), apellido varchar(20), nombre varchar(20), domicilio varchar(30), seccion tinyint not null, cantidadhijos tinyint constraint CK_empleados_hijos check (cantidadhijos>=0), estadocivil char(10) constraint CK_empleados_estadocivil check (estadocivil in (casado,divorciado,soltero,viudo)), fechaingreso datetime, constraint PK_empleados primary key (legajo), constraint FK_empleados_seccion foreign key (seccion) references secciones(codigo) on update cascade, constraint UQ_empleados_documento unique(documento));Eliminamos la vista "vista_empleados" si existe:if object_id(vista_empleados) is not null drop view vista_empleados;Creamos una vista con su definición oculta:create view vista_empleados with encryptionas select (apellido+ +e.nombre) as nombre,sexo, s.nombre as seccion, cantidadhijos from empleados as e join secciones as s on codigo=seccion;Ejecutamos el procedimiento almacenado del sistema "sp_helptext" seguido del nombre de unavista encriptada:sp_helptext vista_empleados;No se muestra.106 - Vistas (eliminar)DETALLE DE CONCEPTOPara quitar una vista se emplea "drop view":
    • drop view NOMBREVISTA;Si se elimina una tabla a la que hace referencia una vista, la vista no se elimina, hay que eliminarlaexplícitamente.Solo el propietario puede eliminar una vista.Antes de eliminar un objeto, se recomienda ejecutar el procedimiento almacenado de sistema"sp_depends" para averiguar si hay objetos que hagan referencia a él.Eliminamos la vista denominada "vista_empleados":drop view vista_empleados;107 - Vistas (with check option)DETALLE DE CONCEPTOEs posible obligar a todas las instrucciones de modificación de datos que se ejecutan en una vistaa cumplir ciertos criterios.Por ejemplo, creamos la siguiente vista:create view vista_empleadosas select apellido, e.nombre, sexo, s.nombre as seccion from empleados as e join secciones as s on seccion=codigo where s.nombre=Administracion with check option;La vista definida anteriormente muestra solamente algunos de los datos de los empleados de lasección "Administracion". Además, solamente se permiten modificaciones a los empleados de esasección.Podemos actualizar el nombre, apellido y sexo a través de la vista, pero no el campo "seccion"porque está restringuido.108 - Vistas (modificar datos de una tabla a través de vistas)DETALLE DE CONCEPTOSi se modifican los datos de una vista, se modifica la tabla base.Se puede insertar, actualizar o eliminar datos de una tabla a través de una vista, teniendo encuenta lo siguiente, las modificaciones que se realizan a las vistas:
    • - no pueden afectar a más de una tabla consultada. Pueden modificarse datos de una vista quecombina varias tablas pero la modificación solamente debe afectar a una sola tabla.- no se pueden cambiar los campos resultado de un cálculo.- pueden generar errores si afectan a campos a las que la vista no hace referencia. Por ejemplo, sise ingresa un registro en una vista que consulta una tabla que tiene campos not null que no estánincluidos en la vista.- la opción "with check option" obliga a todas las instrucciones de modificación que se ejecutan enla vista a cumplir ciertos criterios que se especifican al definir la vista.- para eliminar datos de una vista solamente UNA tabla puede ser listada en el "from" de ladefinicion de la misma.PROBLEMA RESUELTOProblema:Una empresa almacena la información de sus empleados en dos tablas llamadas "empleados" y"secciones".Eliminamos las tablas, si existen:if object_id(empleados) is not null drop table empleados;if object_id(secciones) is not null drop table secciones;Creamos las tablas:create table secciones( codigo tinyint identity, nombre varchar(20), sueldo decimal(5,2) constraint CK_secciones_sueldo check (sueldo>=0), constraint PK_secciones primary key (codigo)); create table empleados( legajo int identity, documento char(8) constraint CK_empleados_documento check (documento like [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]), sexo char(1) constraint CK_empleados_sexo check (sexo in (f,m)), apellido varchar(20), nombre varchar(20), domicilio varchar(30), seccion tinyint not null,
    • cantidadhijos tinyint constraint CK_empleados_hijos check (cantidadhijos>=0), estadocivil char(10) constraint CK_empleados_estadocivil check (estadocivil in (casado,divorciado,soltero,viudo)), fechaingreso datetime, constraint PK_empleados primary key (legajo), sueldo decimal(6,2), constraint FK_empleados_seccion foreign key (seccion) references secciones(codigo) on update cascade, constraint UQ_empleados_documento unique(documento));Ingresamos algunos registros:insert into secciones values(Administracion,300);insert into secciones values(Contaduría,400);insert into secciones values(Sistemas,500); insert into empleados values(22222222,f,Lopez,Ana,Colon 123,1,2,casado,1990-10-10,600); insert into empleados values(23333333,m,Lopez,Luis,Sucre 235,1,0,soltero,1990-02-10,650); insert into empleados values(24444444, m, Garcia, Marcos, Sarmiento 1234, 2, 3, divorciado,1998-07-12,800); insert into empleados values(25555555,m,Gomez,Pablo,Bulnes 321,3,2,casado,1998-10-09,900); insert into empleados values(26666666,f,Perez,Laura,Peru 1254,3,3,casado,2000-05-09,700);Eliminamos la vista "vista_empleados" si existe:if object_id(vista_empleados) is not null drop view vista_empleados;Creamos la vista "vista_empleados", que es resultado de una combinación en la cual se muestran5 campos:create view vista_empleados as select (apellido+ +e.nombre) as nombre,sexo, s.nombre as seccion, cantidadhijos from empleados as e join secciones as s on codigo=seccion;Vemos la información contenida en la vista:select *from vista_empleados;
    • Eliminamos la vista "vista_empleados2" si existe:if object_id(vista_empleados2) is not null drop view vista_empleados2;Creamos otra vista de "empleados" denominada "vista_empleados2" que consulta solamente latabla "empleados" con "with check option":create view vista_empleados2 as select nombre, apellido,fechaingreso,seccion,estadocivil,sueldo from empleados where sueldo>=600 with check option;Consultamos la vista:select *from vista_empleados2;Ingresamos un registro en la vista "vista_empleados2":insert into vista_empleados2 values(Pedro,Perez,2000-10-10,1,casado,800);No es posible insertar un registro en la vista "vista_empleados" porque el campo de la vista"nombre" es un campo calculado.Actualizamos la sección de un registro de la vista "vista_empleados":update vista_empleados set seccion=Sistemas where nombre=Lopez Ana;Si intentamos actualizar el nombre de un empleado no lo permite porque es una columnacalculada.Actualizamos el nombre de un registro de la vista "vista_empleados2":update vista_empleados2 set nombre=Beatriz where nombre=Ana;Verifique que se actualizó la tabla:select *from empleados;Eliminamos un registro de la vista "vista_empleados2":delete from vista_empleados2 where apellido=Lopez;Si podemos eliminar registros de la vista "vista_empleados2" dicha vista solamente consulta unatabla. No podemos eliminar registros de la vista "vista_empleados" porque hay varias tablas en sudefinición.
    • 109 - Vistas modificar (alter view)DETALLE DE CONCEPTOPara modificar una vista puede eliminarla y volver a crearla o emplear "alter view".Con "alter view" se modifica la definición de una vista sin afectar los procedimientos almacenados ylos permisos. Si elimina una vista y vuelve a crearla, debe reasignar los permisos asociados a ella.Sintaxis básica para alterar una vista:alter view NOMBREVISTAwith encryption--opcionalas SELECTEn el ejemplo siguiente se altera vista_empleados para agregar el campo "domicilio":alter view vista_empleadoswith encryptionasselect (apellido+ +e.nombre) as nombre,sexo, s.nombre as seccion, cantidadhijos,domicilio from empleados as e join secciones as s on codigo=seccionSi creó la vista con "with encryption" y quiere modificarla manteniendo la encriptación, debecolocarla nuevamente, en caso de no hacerlo, desaparece.Si crea una vista con "select *" y luego agrega campos a la estructura de las tablas involucradas,los nuevos campos no aparecerán en la vista; esto es porque los campos se seleccionan alejecutar "create view"; debe alterar la vista.110 - Lenguaje de control de flujo (case)DETALLE DE CONCEPTOLa función "case" compara 2 o más valores y devuelve un resultado.La sintaxis es la siguiente:case VALORACOMPARAR when VALOR1 then RESULTADO1 when VALOR2 then RESULTADO2 ... else RESULTADO3
    • endPor cada valor hay un "when" y un "then"; si encuentra un valor coincidente en algún "where"ejecuta el "then" correspondiente a ese "where", si no encuentra ninguna coincidencia, se ejecutael "else"; si no hay parte "else" retorna "null". Finalmente se coloca "end" para indicar que el "case"ha finalizado.Un profesor guarda las notas de sus alumnos de un curso en una tabla llamada "alumnos" queconsta de los siguientes campos:- nombre (30 caracteres),- nota (valor entero entre 0 y 10, puede ser nulo).Queremos mostrar los nombres, notas de los alumnos y en una columna extra llamada "resultado"empleamos un case que testee la nota y muestre un mensaje diferente si en dicho campo hay unvalor:- 0, 1, 2 ó 3: libre;- 4, 5 ó 6: regular;- 7, 8, 9 ó 10: promocionado;Esta es la sentencia: select nombre,nota, resultado= case nota when 0 then libre when 1 then libre when 2 then libre when 3 then libre when 4 then regular when 5 then regular when 6 then regular when 7 then promocionado when 8 then promocionado when 9 then promocionado when 10 then promocionado endfrom alumnos;Note que cada "where" compara un valor puntual, por ello los valores devueltos son iguales paraalgunos casos. Note que como omitimos la parte "else", en caso que el valor no encuentrecoincidencia con ninguno valor "when", retorna "null".Podemos realizar comparaciones en cada "where". La sintaxis es la siguiente:case when VALORACOMPARAR OPERADOR VALOR1 then RESULTADO1 when VALORACOMPARAR OPERADOR VALOR2 then RESULTADO2 ...
    • else RESULTADO3endMostramos los nombres de los alumnos y en una columna extra llamada "resultado" empleamos uncase que teste si la nota es menor a 4, está entre 4 y 7 o supera el 7:select nombre, nota, condicion= case when nota<4 then libre when nota >=4 and nota<7 then regular when nota>=7 then promocionado else sin nota end from alumnos;Puede utilizar una expresión "case" en cualquier lugar en el que pueda utilizar una expresión.También se puede emplear con "group by" y funciones de agrupamiento.111 - Lenguaje de control de flujo (if)DETALLE DE CONCEPTOExisten palabras especiales que pertenecen al lenguaje de control de flujo que controlan laejecución de las sentencias, los bloques de sentencias y procedimientos almacenados.Tales palabras son: begin... end, goto, if... else, return, waitfor, while, break y continue.- "begin... end" encierran un bloque de sentencias para que sean tratados como unidad.- "if... else": testean una condición; se emplean cuando un bloque de sentencias debe serejecutado si una condición se cumple y si no se cumple, se debe ejecutar otro bloque desentencias diferente.- "while": ejecuta repetidamente una instrucción siempre que la condición sea verdadera.- "break" y "continue": controlan la operación de las instrucciones incluidas en el bucle "while".Veamos un ejemplo. Tenemos nuestra tabla "libros"; queremos mostrar todos los títulos de loscuales no hay libros disponibles (cantidad=0), si no hay, mostrar un mensaje indicando talsituación:if exists (select *from libros where cantidad=0) (select titulo from libros where cantidad=0)else select No hay libros sin stock;SQL Server ejecuta la sentencia (en este caso, una subconsulta) luego del "if" si la condición esverdadera; si es falsa, ejecuta la sentencia del "else" (si existe).
    • Podemos emplear "if...else" en actualizaciones. Por ejemplo, queremos hacer un descuento en elprecio, del 10% a todos los libros de una determinada editorial; si no hay, mostrar un mensaje:if exists (select *from libros where editorial=Emece)begin update libros set precio=precio-(precio*0.1) where editorial=Emece select libros actualizadosendelse select no hay registros actualizados;Note que si la condición es verdadera, se deben ejecutar 2 sentencias. Por lo tanto, se debenencerrar en un bloque "begin...end".En el siguiente ejemplo eliminamos los libros cuya cantidad es cero; si no hay, mostramos unmensaje:if exists (select *from libros where cantidad=0) delete from libros where cantidad=0else select No hay registros eliminados;112 - Variables de usuarioDETALLE DE CONCEPTOLas variables nos permiten almacenar un valor y recuperarlo más adelante para emplearlos enotras sentencias.Las variables de usuario son específicas de cada conexión y son liberadas automáticamente alabandonar la conexión.Las variables de usuario comienzan con "@" (arroba) seguido del nombre (sin espacios), dichonombre puede contener cualquier caracter.Una variable debe ser declarada antes de usarse. Una variable local se declara así: declare @NOMBREVARIABLE TIPOcolocando "declare" el nombre de la variable que comienza con el símbolo arroba (@) y el tipo dedato. Ejemplo: declare @nombre varchar(20)Puede declarar varias variables en una misma sentencia: declare @nombre varchar(20), @edad intNo existen variables globales en SQL Server.Una variable declarada existe dentro del entorno en que se declara; debemos declarar y emplear lavariable en el mismo lote de sentencias, porque si declaramos una variable y luego, en otro bloquede sentencias pretendemos emplearla, dicha variable ya no existe. Por ejemplo, si ejecutamosestas sentencias en diferentes lotes:declare @variable varchar(10); select @variable;aparece un mensaje indicando que la variable "@variable" debe ser declarada.Debemos tipear: declare @variable varchar(10)
    • select @variable;Disponemos punto y coma solo al final de la última instrucción del lote.Una variable a la cual no se le ha asignado un valor contiene "null".Se le asigna un valor inicial con "set": set @edad=45Para almacenar un valor en una variable se coloca el signo igual (=) entre la variable y el valor aasignar.Si le asignamos un valor resultado de una consulta, la sintaxis es: select @nombre = autor from libros where titulo=UnoPodemos ver el contenido de una variable con: select @nombre;Una variable puede tener comodines: declare @patron varchar(30) set @patron=B% select autor from libros where autor like @patron;La utilidad de las variables consiste en que almacenan valores para utilizarlos en otras consultas.Por ejemplo, queremos saber todos los datos del libro con mayor precio de la tabla "libros" de unalibrería. Para ello podemos emplear una variable para almacenar el precio más alto: declare @mayorprecio select @mayorprecio:=max(precio) from librosy luego mostrar todos los datos de dicho libro empleando la variable anterior: select *from libros where precio=@mayorprecio;Es decir, declaramos la variable y guardamos en ella el precio más alto y luego, en otra sentencia,mostramos los datos de todos los libros cuyo precio es igual al valor de la variable.Una variable puede ser definida con cualquier tipo de dato, excepto text, ntext e image; incluso deun tipo de dato definido por el usuario.113 - Tipos de datos text, ntext y imageDETALLE DE CONCEPTOLos tipos de datos "ntext", "text" e "image" representan tipos de datos de longitud fija y variable enlos que se pueden guardar gran cantidad de información, caracteres unicode y no unicode y datosbinarios."ntext" almacena datos unicode de longitud variable y el máximo es de aproximadamente1000000000 caracteres, en bytes, el tamaño es el doble de los caracteres ingresados (2 GB)."text" almacena datos binarios no unicode de longitud variable, el máximo es de 2000000000caracteres aprox. (2 GB). No puede emplearse en parámetros de procedimientos almacenados."image" es un tipo de dato de longitud variable que puede contener de 0 a 2000000000 bytes (2GB) aprox. de datos binarios. Se emplea para almacenar gran cantidad de información o gráficos.Se emplean estos tipos de datos para almacenar valores superiores a 8000 caracteres.
    • Ninguno de estos tipos de datos admiten argumento para especificar su longitud, como en el casode los tipos "char", o "varchar".Como estos tipos de datos tiene gran tamaño, SQL Server los almacena fuera de los registros, ensu lugar guarda un puntero (de 16 bytes) que apunta a otro sitio que contiene los datos.Para declarar un campo de alguno de estos tipos de datos, colocamos el nombre del camposeguido del tipo de dato:...NOMBRECAMPO text....Otras consideraciones importantes:- No pueden definirse variables de estos tipos de datos.- Los campos de estos tipos de datos no pueden emplearse para índices.- La única restricción que puede aplicar a estos tipos de datos es "default".- Se pueden asociar valores predeterminados pero no reglas a campos de estos tipos de datos.- No pueden alterarse campos de estos tipos con "alter table".115 - Tipo de dato text - ntext e image (leer)DETALLE DE CONCEPTOLa función "readtext" lee valores de un campo text, ntext o image, comenzando desde una posicióny leyendo un específico número de bytes. Sintaxis:readtext TABLA.CAMPO PUNTEROATEXTO DESPLAZAMIENTO CANTIDAD;Analicemos la sintaxis:- PUNTEROATEXTO: puntero a texto válido, binary(16).- DESPLAZAMIENTO: número de bytes (para text o image) o caracteres (ntext) que se mueve elpuntero antes de comenzar a leer.- CANTIDAD: número de bytes o caracteres a leer desde la posición indicada porDESPLAZAMIENTO. Si es 0, se leen 4KB bytes o hasta el final.Leemos la información almacenada en el campo "sinopsis" de "libros" del registro con código 2,desde la posición 9, 50 caracteres:declare @puntero varbinary(16)
    • select @puntero=textptr(sinopsis) from libros where codigo=2readtext libros.sinopsis @puntero 9 50;Si al insertar registros se ingresa un valor "null" en un campo "text", "ntext" o "image" o no seingresan datos, no se crea un puntero válido y al intentar leer dicho campo ocurre un error, porquela función "readtext" requiere un puntero válido. Para evitarlo podemos chequear el puntero antesde pasárselo a la función de lectura:declare @puntero varbinary(16)select @puntero=textptr(sinopsis) from libros where codigo=1if (textvalid(libros.sinopsis, @puntero)=1) readtext libros.sinopsis @puntero 9 50else select puntero invalido;PROBLEMA RESUELTOProblema:Una librería almacena los datos de sus libros en una tabla llamada "libros".Eliminamos la tabla, si existe:if object_id(libros) is not null drop table libros;Creamos la tabla con la siguiente estructura:create table libros( codigo int identity, titulo varchar(40), autor varchar(30), editorial varchar(20), sinopsis text);Ingresamos algunos registros:insert into libros values (Ilusiones,Richard Bach,Planeta,null);insert into libros values (Aprenda PHP,Mario Molina,Nuevo Siglo, Contiene todos los temas necesarios para el aprendizaje de PHP);insert into libros (titulo,autor,editorial) values (Uno,Richard Bach,Planeta);insert into libros values (El Aleph,Borges,Emece, Uno de los libros más célebres de este autor.);Leemos la información almacenada en el campo "sinopsis" de "libros" del registro con código 2,desde la posición 9, 50 caracteres:
    • declare @puntero varbinary(16)select @puntero=textptr(sinopsis) from libros where codigo=2readtext libros.sinopsis @puntero 9 50;Leemos la información almacenada en el campo "sinopsis" de "libros" del registro con código 3, talregistro no tiene inicializado el campo "sinopsis", para que no ocurra un error, vamos a controlar elpuntero antes de leer el campo:declare @puntero varbinary(16)select @puntero=textptr(sinopsis) from libros where codigo=3if (textvalid(libros.sinopsis, @puntero)=1) readtext libros.sinopsis @puntero 0 0else select puntero invalido;Recuperamos la sinopsis del libro con código 4 (desde el comienzo al final), controlando que elpuntero sea válido:declare @puntero varbinary(16)select @puntero=textptr(sinopsis) from libros where codigo=4if (textvalid(libros.sinopsis, @puntero)=1) readtext libros.sinopsis @puntero 0 0117 - Tipo de dato text - ntext e image (actualizar)DETALLE DEL CONCEPTOAprendimos que la función "writetext" sobreescribe, reemplaza el contenido completo de un campode tipo "text", "ntext" o "image".Para actualizar campos de estos tipos también empleamos "updatetext", que permite cambiar unaporción del campo (o todo el campo). La sintaxis básica es la siguiente:updatetext TABLA.CAMPO PUNTEROATEXTODESPLAZAMIENTODELPUNTEROLONGITUDDEBORRADODATOAINSERTAR;Analizamos la sintaxis:- TABLA.CAMPO: campo y tabla que se va a actualizar.- PUNTEROATEXTO: valor del puntero, retornado por la función "textptr", que apunta al dato text,ntext o image que se quiere actualizar.- DESPLAZAMIENTODELPUNTERO: indica la posición en que inserta el nuevo dato. Especifica lacantidad de bytes (para campos text e image) o caracteres (para campos ntext) que debe moverseel puntero para insertar el dato. Los valores pueden ser: 0 (el nuevo dato se inserta al comienzo),
    • "null" (coloca el puntero al final), un valor mayor a cero y menor o igual a la longitud total del texto(inserta el nuevo dato en la posición indicada) y un valor mayor a la longitud total del campo(genera un mensaje de error).Es importante recordar que cada caracter ntext ocupa 2 bytes.- LONGITUDDEBORRADO: indica la cantidad de bytes (para text e image) o caracteres (parantext) a borrar comenzando de la posición indicada por el parámetroDESPLAZAMIENTODELPUNTERO. Si colocamos el valor 0 (no se borra ningún dato), "null" (borratodos los datos desde la posición indicada por el parámetro DESPLAZAMIENTODELPUNTEROhasta el final), un valor mayor que cero y menor o igual a la longitud del texto (borra tal cantidad) yun valor inválido, es decir, mayor a la longitud del texto (genera un mensaje de error).Es importante recordar que cada caracter "ntext" ocupa 2 bytes.- DATOAINSERTAR: el dato que va a ser insertado en el campo. Puede ser char, nchar, varchar,nvarchar, binary, varbinary, text, ntext, image, un literal o una variable. Si el dato es un campo text,ntext o image de otra tabla, se debe indicar el nombre de la tabla junto con el campo y el valor delpuntero que apunta al tipo de dato text, ntext o image (retornado por la función "textptr"), de estaforma:TABLA.CAMPO PUNTERO;Tenemos la tabla libros, con un campo de tipo text llamado "sinopsis"; hay un registro cargado conel siguiente texto: "Para aprender PHP a paso." Necesitamos agregar antes de "a paso" el texto"paso " para que el texto completo sea "Para aprender PHP paso a paso", tipeamos:declare @puntero binary(16)select @puntero = textptr(sinopsis) from libros where titulo=Aprenda PHPupdatetext libros.sinopsis @puntero 18 0 paso ;Entonces, declaramos una variable llamada "@puntero"; guardamos en la variable el valor delpuntero, obtenido con la función "textptr(sinopsis)", tal puntero apunta al campo "sinopsis" del libro"Aprenda PHP". Luego actualizamos el campo, colocando el puntero en la posición 18, noborramos ningún byte y colocamos el texto a agregar; el campo ahora contendrá "Para aprencerPHP paso a paso".Es posible guardar en un campo "text" de una tabla el contenido del campo "text" de otra tabla;para ello debemos utilizar 2 punteros, uno para obtener la dirección del campo que queremosactualizar y otro para obtener la dirección del campo del cual extraemos la información.En el siguiente ejemplo guardamos en una variable el valor del puntero a texto al campo "sinopsis"del libro "Aprenda PHP" de la tabla "libros"; en otra variable guardamos el valor del puntero a textoal campo "sinopsis" del libro con código 1 de la tabla "ofertas"; finalmente actualizamos el registrode "ofertas" con el texto de "libros".declare @puntero1 binary(16)
    • select @puntero1 = textptr(sinopsis) from libros where titulo=Aprenda PHPdeclare @puntero2 binary(16)select @puntero2 = textptr(sinopsis) from ofertas where titulo=Aprenda PHP updatetext ofertas.sinopsis @puntero2 0 null libros.sinopsis @puntero1;Entonces, se emplea "updatetext" para modificar datos de campos de tipo text, ntext e image,pudiendo cambiar una porción del texto.118 - Tipo de dato text - ntext e image (funciones)DETALLE DEL CONCEPTOLas siguientes son otras funciones que pueden emplearse con estos tipos de datos:- datalenght(CAMPO): devuelve el número de bytes de un determinado campo. Retorna "null" si elcampo es nulo. Ejemplo:select titulo, datalength(sinopsis) as longitud from libros order by titulo;- patindex (PATRON,CAMPO): retorna el comienzo de la primera ocurrencia de un patrón de laexpresión especificada, si el patrón no se encuentra, retorna cero. El patrón es una cadena quepuede incluir comodines.Ejemplo:select patindex(%PHP%, sinopsis) from libros;Con este tipo de datos también puede utilizarse "like", pero "like" solamente puede incluirse en lacláusula "where".- substring (TEXTO,INICIO,LONGITUD): devuelve una parte del texto especificado como primerargumento, empezando desde la posición especificada por el segundo argumento y de tantoscaracteres de longitud como indica el tercer argumento.Ejemplo:select titulo,substring(sinopsis,1,20) from libros;
    • PROBLEMA RESUELTOProblema:Una librería almacena los datos de sus libros en una tabla llamada "libros".Eliminamos la tabla si existe:if object_id(libros) is not null drop table libros;Creamos la tabla:create table libros( codigo int identity, titulo varchar(40), autor varchar(30), editorial varchar(20), sinopsis text);Ingresamos algunos registros:insert into libros values (Ilusiones,Richard Bach,Planeta,null);insert into libros values (Aprenda PHP,Mario Molina,Nuevo Siglo, Para aprender PHP paso a paso);insert into libros values (Programación elemental en PHP,Mario Molina,Planeta, Contiene conceptos básicos de PHP);Veamos la longitud del campo "sinopsis" de todos los libros:select titulo, datalength(sinopsis) as longitud from libros order by titulo;Buscamos todos los libros en los cuales en su sinopsis se encuentre el texto "PHP":select titulo from libros where patindex(%PHP%, sinopsis)>0;Empleamos la función "patindex" para mostrar la posición en que se encuentra la cadena "PHP" enla sinopsis de todos los libros:select titulo, patindex(%PHP%, sinopsis) as posicion from libros;Note que en el libro en el cual no se encuentra, retorna "0".Seleccionamos los títulos y los primeros 10 caracteres de la sinopsis de cada uno de ellos:
    • select titulo,substring(sinopsis,1,10) as sinopsis from libros;119 - Procedimientos almacenadosDETALLE DEL CONCEPTOVimos que SQL Server ofrece dos alternativas para asegurar la integridad de datos, la integridad:1) DECLARATIVA, mediante el uso de restricciones (constraints), valores predeterminados(defaults) y reglas (rules) y2) PROCEDIMENTAL, mediante la implementación de procedimientos almacenados ydesencadenadores (triggers).Nos detendremos ahora en procedimientos almacenados.Un procedimiento almacenado es un conjunto de instrucciones a las que se les da un nombre, quese almacena en el servidor. Permiten encapsular tareas repetitivas.SQL Server permite los siguientes tipos de procedimientos almacenados:1) del sistema: están almacenados en la base de datos "master" y llevan el prefijo "sp_"; permitenrecuperar información de las tablas del sistema y pueden ejecutarse en cualquier base de datos.2) locales: los crea el usuario (próximo tema).3) temporales: pueden ser locales, cuyos nombres comienzan con un signo numeral (#), oglobales, cuyos nombres comienzan con 2 signos numeral (##). Los procedimientos almacenadostemporales locales están disponibles en la sesión de un solo usuario y se eliminanautomáticamente al finalizar la sesión; los globales están disponibles en las sesiones de todos losusuarios.4) extendidos: se implementan como bibliotecas de vínculos dinámicos (DLL, Dynamic-LinkLibraries), se ejecutan fuera del entorno de SQL Server. Generalmente llevan el prefijo "xp_". Nolos estudiaremos.Al crear un procedimiento almacenado, las instrucciones que contiene se analizan para verificar sison correctas sintácticamente. Si no se detectan errores, SQL Server guarda el nombre delprocedimiento almacenado en la tabla del sistema "sysobjects" y su contenido en la tabla delsistema "syscomments" en la base de datos activa. Si se encuentra algún error, no se crea.Un procedimiento almacenados puede hacer referencia a objetos que no existen al momento decrearlo. Los objetos deben existir cuando se ejecute el procedimiento almacenado.Ventajas:- comparten la lógica de la aplicación con las otras aplicaciones, con lo cual el acceso y lasmodificaciones de los datos se hacen en un solo sitio.
    • - permiten realizar todas las operaciones que los usuarios necesitan evitando que tengan accesodirecto a las tablas.- reducen el tráfico de red; en vez de enviar muchas instrucciones, los usuarios realizanoperaciones enviando una única instrucción, lo cual disminuye el número de solicitudes entre elcliente y el servidor.120 - Procedimientos almacenados (crear - ejecutar)DETALLE DEL CONCEPTOLos procedimientos almacenados se crean en la base de datos seleccionada, excepto losprocedimientos almacenados temporales, que se crean en la base de datos "tempdb".En primer lugar se deben tipear y probar las instrucciones que se incluyen en el procedimientoalmacenado, luego, si se obtiene el resultado esperado, se crea el procedimiento.Los procedimientos almacenados pueden hacer referencia a tablas, vistas, a funciones definidaspor el usuario, a otros procedimientos almacenados y a tablas temporales.Un procedimiento almacenado pueden incluir cualquier cantidad y tipo de instrucciones, excepto:create default, create procedure, create rule, create trigger y create view.Se pueden crear otros objetos (por ejemplo índices, tablas), en tal caso deben especificar elnombre del propietario; se pueden realizar inserciones, actualizaciones, eliminaciones, etc.Si un procedimiento almacenado crea una tabla temporal, dicha tabla sólo existe dentro delprocedimiento y desaparece al finalizar el mismo. Lo mismo sucede con las variables.Hemos empleado varias veces procedimientos almacenados del sistema ("sp_help","sp_helpconstraint", etc.), ahora aprenderemos a crear nuestros propios procedimientosalmacenados.Para crear un procedimiento almacenado empleamos la instrucción "create procedure".La sintaxis básica parcial es:create procedure NOMBREPROCEDIMIENTO as INSTRUCCIONES;Para diferenciar los procedimientos almacenados del sistema de los procedimientos almacenadoslocales use un prefijo diferente a "sp_" cuando les de el nombre.Con las siguientes instrucciones creamos un procedimiento almacenado llamado"pa_libros_limite_stock" que muestra todos los libros de los cuales hay menos de 10 disponibles:create proc pa_libros_limite_stock as select *from libros
    • where cantidad <=10;Entonces, creamos un procedimiento almacenado colocando "create procedure" (o "create proc",que es la forma abreviada), luego el nombre del procedimiento y seguido de "as" las sentenciasque definen el procedimiento."create procedure" debe ser la primera sentencia de un lote.Para ejecutar el procedimiento almacenado creado anteriormente tipeamos:exec pa_libros_limite_stock;Entonces, para ejecutar un procedimiento almacenado colocamos "execute" (o "exec") seguido delnombre del procedimiento.Cuando realizamos un ejercicio nuevo, siempre realizamos las mismas tareas: eliminamos la tablasi existe, la creamos y luego ingresamos algunos registros. Podemos crear un procedimientoalmacenado que contenga todas estas instrucciones:create procedure pa_crear_libros as if object_id(libros)is not null drop table libros; create table libros( codigo int identity, titulo varchar(40), autor varchar(30), editorial varchar(20), precio decimal(5,2), primary key(codigo) ); insert into libros values(Uno,Richard Bach,Planeta,15); insert into libros values(Ilusiones,Richard Bach,Planeta,18); insert into libros values(El aleph,Borges,Emece,25); insert into libros values(Aprenda PHP,Mario Molina,Nuevo siglo,45); insert into libros values(Matematica estas ahi,Paenza,Nuevo siglo,12); insert into libros values(Java en 10 minutos,Mario Molina,Paidos,35);Y luego lo ejecutamos cada vez que comenzamos un nuevo ejercicio y así evitamos tipear tantassentencias:exec pa_crear_libros;PROBLEMA RESUELTOProblema:Vamos a crear un procedimiento almacenado que contenga las siguientes instrucciones:
    • - eliminación de la tabla "libros" si existe;- creación de la tabla "libros" con: codigo, titulo, autor, editorial, precio, cantidad;- ingresode algunos registros.En primer lugar, debemos eliminarlo, si existe (no hemos aprendido aún a eliminar procedimientosalmacenados, en próximos capítulos lo veremos):if object_id(pa_crear_libros) is not null drop procedure pa_crear_libros;Creamos el procedimiento:create procedure pa_crear_librosas if object_id(libros)is not null drop table libros create table libros( codigo int identity, titulo varchar(40), autor varchar(30), editorial varchar(20), precio decimal(5,2), cantidad smallint, primary key(codigo) ) insert into libros values(Uno,Richard Bach,Planeta,15,5) insert into libros values(Ilusiones,Richard Bach,Planeta,18,50) insert into libros values(El aleph,Borges,Emece,25,9) insert into libros values(Aprenda PHP,Mario Molina,Nuevo siglo,45,100) insert into libros values(Matematica estas ahi,Paenza,Nuevo siglo,12,50) insert into libros values(Java en 10 minutos,Mario Molina,Paidos,35,300);Disponemos un punto y coma (;) en la última instrucción del procedimiento almacenado.Ejecutamos el procedimiento:exec pa_crear_libros;Veamos si ha creado la tabla:select *from libros;Ejecutamos el procedimiento almacenado del sistema "sp_help" y el nombre del procedimientoalmacenado para verificar que existe el procedimiento creado recientemente:sp_help pa_crear_libros;Aparece el nombre, propietario, tipo y fecha de creación.
    • Necesitamos un procedimiento almacenado que muestre los libros de los cuales hay menos de 10.En primer lugar, lo eliminamos si existe:if object_id(pa_libros_limite_stock) is not null drop procedure pa_libros_limite_stock;Creamos el procedimiento:create proc pa_libros_limite_stock as select *from libros where cantidad <=10;Ejecutamos el procedimiento almacenado del sistema "sp_help" junto al nombre del procedimientocreado recientemente para verificar que existe:sp_help pa_libros_limite_stock;Aparece el nombre, propietario, tipo y fecha de creación.Lo ejecutamos:exec pa_libros_limite_stock;Modificamos algún registro y volvemos a ejecutar el procedimiento:update libros set cantidad=2 where codigo=4;exec pa_libros_limite_stock;Note que el resultado del procedimiento ha cambiado porque los datos han cambiado.121 - Procedimientos almacenados (eliminar)DETALLE DEL CONCEPTOLos procedimientos almacenados se eliminan con "drop procedure". Sintaxis:drop procedure NOMBREPROCEDIMIENTO;Eliminamos el procedimiento almacenado llamado "pa_libros_autor":drop procedure pa_libros_autor;Si el procedimiento que queremos eliminar no existe, aparece un mensaje de error, para evitarlo,podemos emplear esta sintaxis:if object_id(NOMBREPROCEDIMIENTO) is not null drop procedure NOMBREPROCEDIMIENTO;
    • Eliminamos, si existe, el procedimiento "pa_libros_autor", si no existe, mostramos un mensaje:if object_id(pa_libros_autor) is not null drop procedure pa_libros_autorelse select No existe el procedimiento "pa_libros_autor";"drop procedure" puede abreviarse con "drop proc".Se recomienda ejecutar el procedimiento almacenado del sistema "sp_depends" para ver si algúnobjeto depende del procedimiento que deseamos eliminar.Podemos eliminar una tabla de la cual dependa un procedimiento, SQL Server lo permite, peroluego, al ejecutar el procedimiento, aparecerá un mensaje de error porque la tabla referenciada noexiste.PROBLEMA RESUELTOProblema:Eliminamos, si existe, el procedimiento almacenado "pa_crear_libros":if object_id(pa_crear_libros) is not null drop procedure pa_crear_libros;Verificamos que no existe ejecutando "sp_help":sp_help pa_crear_libros;Aparece un mensaje de error indicando que no existe.Creamos el procedimiento:create procedure pa_crear_librosas if object_id(libros)is not null drop table libros create table libros( codigo int identity, titulo varchar(40), autor varchar(30), editorial varchar(20), precio decimal(5,2), cantidad smallint, primary key(codigo) ) insert into libros values(Uno,Richard Bach,Planeta,15,5) insert into libros values(Ilusiones,Richard Bach,Planeta,18,50) insert into libros values(El aleph,Borges,Emece,25,9)
    • insert into libros values(Aprenda PHP,Mario Molina,Nuevo siglo,45,100) insert into libros values(Matematica estas ahi,Paenza,Nuevo siglo,12,50) insert into libros values(Java en 10 minutos,Mario Molina,Paidos,35,300);Verificamos que existe:sp_help pa_crear_libros;Aparece.Lo eliminamos sin corroborar su existencia:drop proc pa_crear_libros;Vemos si aparece en la lista de objetos que muestra "sp_help":sp_help pa_crear_libros;Aparece un mensaje de error indicando que no existe.Solicitamos su eliminación nuevamente:drop proc pa_crear_libros;No existe, aparece un mensaje de error.Solicitamos su eliminación verificando si existe, si no existe, mostramos un mensaje:if object_id(pa_crear_libros) is not null drop proc pa_crear_libroselse select No existe el procedimiento "pa_crear_libros";122 - Procedimientos almacenados (parámetros de entrada)DETALLE DEL CONCEPTOLos procedimientos almacenados pueden recibir y devolver información; para ello se empleanparámetros, de entrada y salida, respectivamente.Veamos los primeros. Los parámetros de entrada posibilitan pasar información a un procedimiento.Para que un procedimiento almacenado admita parámetros de entrada se deben declarar variablescomo parámetros al crearlo. La sintaxis es:create proc NOMBREPROCEDIMIENTO @NOMBREPARAMETRO TIPO =VALORPORDEFECTO as SENTENCIAS;
    • Los parámetros se definen luego del nombre del procedimiento, comenzando el nombre con unsigno arroba (@). Los parámetros son locales al procedimiento, es decir, existen solamente dentrodel mismo. Pueden declararse varios parámetros por procedimiento, se separan por comas.Cuando el procedimiento es ejecutado, deben explicitarse valores para cada uno de los parámetros(en el orden que fueron definidos), a menos que se haya definido un valor por defecto, en tal caso,pueden omitirse. Pueden ser de cualquier tipo de dato (excepto cursor).Luego de definir un parámetro y su tipo, opcionalmente, se puede especificar un valor por defecto;tal valor es el que asume el procedimiento al ser ejecutado si no recibe parámetros. Si no se colocavalor por defecto, un procedimiento definido con parámetros no puede ejecutarse sin valores paraellos. El valor por defecto puede ser "null" o una constante, también puede incluir comodines si elprocedimiento emplea "like".Creamos un procedimiento que recibe el nombre de un autor como parámetro para mostrar todoslos libros del autor solicitado:create procedure pa_libros_autor @autor varchar(30)as select titulo, editorial,precio from libros where autor= @autor;El procedimiento se ejecuta colocando "execute" (o "exec") seguido del nombre del procedimientoy un valor para el parámetro:exec pa_libros_autor Borges;Creamos un procedimiento que recibe 2 parámetros, el nombre de un autor y el de una editorial:create procedure pa_libros_autor_editorial @autor varchar(30), @editorial varchar(20)as select titulo, precio from libros where autor= @autor and editorial=@editorial;El procedimiento se ejecuta colocando "execute" (o "exec") seguido del nombre del procedimientoy los valores para los parámetros separados por comas:exec pa_libros_autor_editorial Richard Bach,Planeta;Los valores de un parámetro pueden pasarse al procedimiento mediante el nombre del parámetroo por su posición. La sintaxis anterior ejecuta el procedimiento pasando valores a los parámetrospor posición. También podemos emplear la otra sintaxis en la cual pasamos valores a losparámetros por su nombre:
    • exec pa_libros_autor_editorial @editorial=Planeta, @autor=Richard Bach;Cuando pasamos valores con el nombre del parámetro, el orden en que se colocan puedealterarse.No podríamos ejecutar el procedimiento anterior sin valores para los parámetros. Si queremosejecutar un procedimiento que permita omitir los valores para los parámetros debemos, al crear elprocedimiento, definir valores por defecto para cada parámetro:create procedure pa_libros_autor_editorial2 @autor varchar(30)=Richard Bach, @editorial varchar(20)=Planetaas select titulo, autor,editorial,precio from libros where autor= @autor and editorial=@editorial;Podemos ejecutar el procedimiento anterior sin enviarle valores, usará los predeterminados.Si enviamos un solo parámetro a un procedimiento que tiene definido más de un parámetro sinespecificar a qué parámetro corresponde (valor por posición), asume que es el primero. Es decir,SQL Server asume que los valores se dan en el orden que fueron definidos, no se puedeinterrumpir la secuencia.Si queremos especificar solamente el segundo parámetro, debemos emplear la sintaxis de paso devalores a parámetros por nombre:exec pa_libros_autor_editorial2 @editorial=Paidos;Podemos emplear patrones de búsqueda en la consulta que define el procedimiento almacenado yutilizar comodines como valores por defecto:create proc pa_libros_autor_editorial3 @autor varchar(30) = %, @editorial varchar(30) = %as select titulo,autor,editorial,precio from libros where autor like @autor and editorial like @editorial;La sentencia siguiente ejecuta el procedimiento almacenado "pa_libros_autor_editorial3" enviandoun valor por posición, se asume que es el primero.exec pa_libros_autor_editorial3 P%;
    • La sentencia siguiente ejecuta el procedimiento almacenado "pa_libros_autor_editorial3" enviandoun valor para el segundo parámetro, para el primer parámetro toma el valor por defecto:exec pa_libros_autor_editorial3 @editorial=P%;También podríamos haber tipeado:exec pa_libros_autor_editorial3 default, P%;123 - Procedimientos almacenados (parámetros de salida)DETALLE DEL CONCEPTODijimos que los procedimientos almacenados pueden devolver información; para ello se empleanparámetros de salida. El valor se retorna a quien realizó la llamada con parámetros de salida. Paraque un procedimiento almacenado devuelva un valor se debe declarar una variable con la palabraclave "output" al crear el procedimiento:create procedure NOMBREPROCEDIMIENTO @PARAMETROENTRADA TIPO =VALORPORDEFECTO, @PARAMETROSALIDA TIPO=VALORPORDEFECTO output as SENTENCIAS select @PARAMETROSALIDA=SENTENCIAS;Los parámetros de salida pueden ser de cualquier tipo de datos, excepto text, ntext e image.Creamos un procedimiento almacenado al cual le enviamos 2 números y retorna el promedio:create procedure pa_promedio @n1 decimal(4,2), @n2 decimal(4,2), @resultado decimal(4,2) output as select @resultado=(@n1+@n2)/2;Al ejecutarlo también debe emplearse "output": declare @variable decimal(4,2) execute pa_promedio 5,6, @variable output select @variable;Declaramos una variable para guardar el valor devuelto por el procedimiento; ejecutamos elprocedimiento enviándole 2 valores y mostramos el resultado.La instrucción que realiza la llamada al procedimiento debe contener un nombre de variable paraalmacenar el valor retornado.
    • Creamos un procedimiento almacenado que muestre los títulos, editorial y precio de los libros deun determinado autor (enviado como parámetro de entrada) y nos retorne la suma y el promedio delos precios de todos los libros del autor enviado:create procedure pa_autor_sumaypromedio @autor varchar(30)=%, @suma decimal(6,2) output, @promedio decimal(6,2) output as select titulo,editorial,precio from libros where autor like @autor select @suma=sum(precio) from libros where autor like @autor select @promedio=avg(precio) from libros where autor like @autor;Ejecutamos el procedimiento y vemos el contenido de las variables en las que almacenamos losparámetros de salida del procedimiento:declare @s decimal(6,2), @p decimal(6,2)execute pa_autor_sumaypromedio Richard Bach, @s output, @p outputselect @s as total, @p as promedio;PROBLEMA RESUELTOProblema:Eliminamos el procedimiento almacenado "pa_promedio", si existe:if object_id(pa_promedio) is not null drop proc pa_promedio;Creamos un procedimiento almacenado al cual le enviamos 2 números decimales y retorna elpromedio:create procedure pa_promedio @n1 decimal(4,2), @n2 decimal(4,2), @resultado decimal(4,2) output as select @resultado=(@n1+@n2)/2;Lo ejecutamos enviando diferentes valores: declare @variable decimal(4,2) execute pa_promedio 5,6, @variable output select @variable
    • execute pa_promedio 5.3,4.7, @variable output select @variable execute pa_promedio 9,10, @variable output select @variable;Trabajamos con la tabla "libros" de una librería.Eliminamos la tabla si existe y la creamos nuevamente:if object_id(libros) is not null drop table libros;create table libros( codigo int identity, titulo varchar(40), autor varchar(30), editorial varchar(20), precio decimal(5,2), primary key(codigo));Ingresamos algunos registros:insert into libros values (Uno,Richard Bach,Planeta,15);insert into libros values (Ilusiones,Richard Bach,Planeta,12);insert into libros values (El aleph,Borges,Emece,25);insert into libros values (Aprenda PHP,Mario Molina,Nuevo siglo,50);insert into libros values (Matematica estas ahi,Paenza,Nuevo siglo,18);insert into libros values (Puente al infinito,Richard Bach,Sudamericana,14);insert into libros values (Antología,J. L. Borges,Paidos,24);insert into libros values (Java en 10 minutos,Mario Molina,Siglo XXI,45);insert into libros values (Antología,Borges,Planeta,34);Eliminamos el procedimiento almacenado "pa_autor_sumaypromedio", si existe:if object_id(pa_autor_sumaypromedio) is not null drop proc pa_autor_sumaypromedio;Creamos un procedimiento almacenado que muestre los títulos, editorial y precio de los libros deun determinado autor (enviado como parámetro de entrada) y nos retorne la suma y el promedio delos precios de todos los libros del autor enviado:create procedure pa_autor_sumaypromedio @autor varchar(30)=%, @suma decimal(6,2) output, @promedio decimal(6,2) output as select titulo,editorial,precio
    • from libros where autor like @autor select @suma=sum(precio) from libros where autor like @autor select @promedio=avg(precio) from libros where autor like @autor;Ejecutamos el procedimiento enviando distintos valores:declare @s decimal(6,2), @p decimal(6,2)execute pa_autor_sumaypromedio Richard Bach, @s output, @p outputselect @s as total, @p as promedioexecute pa_autor_sumaypromedio Borges, @s output, @p outputselect @s as total, @p as promedioexecute pa_autor_sumaypromedio Mario Molina, @s output, @p outputselect @s as total, @p as promedioEjecutamos el procedimiento sin pasar el parámetro para autor. Recuerde que en estos casosdebemos colocar los nombres de las variables.declare @s decimal(6,2), @p decimal(6,2)execute pa_autor_sumaypromedio @suma=@s output,@promedio= @p outputselect @s as total, @p as promedio;124 - Procedimientos almacenados (return)DETALLE DEL CONCEPTOLa instrucción "return" sale de una consulta o procedimiento y todas las instrucciones posterioresno son ejecutadas.Creamos un procedimiento que muestre todos los libros de un autor determinado que se ingresacomo parámetro. Si no se ingresa un valor, o se ingresa "null", se muestra un mensaje y se saledel procedimiento:create procedure pa_libros_autor @autor varchar(30)=nullasif @autor is nullbegin select Debe indicar un autor returnend;select titulo from libros where autor = @autor;
    • Si al ejecutar el procedimiento enviamos el valor "null" o no pasamos valor, con lo cual toma elvalor por defecto "null", se muestra un mensaje y se sale; en caso contrario, ejecuta la consultaluego del "else"."return" puede retornar un valor entero.Un procedimiento puede retornar un valor de estado para indicar si se ha ejecutado correctamenteo no.Creamos un procedimiento almacenado que ingresa registros en la tabla "libros". Los parámetroscorrespondientes al título y autor DEBEN ingresarse con un valor distinto de "null", los demás sonopcionales. El procedimiento retorna "1" si la inserción se realiza, es decir, si se ingresan valorespara título y autor y "0", en caso que título o autor sean nulos:create procedure pa_libros_ingreso @titulo varchar(40)=null, @autor varchar(30)=null, @editorial varchar(20)=null, @precio decimal(5,2)=nullasif (@titulo is null) or (@autor is null) return 0elsebegin insert into libros values (@titulo,@autor,@editorial,@precio) return 1end;Para ver el resultado, debemos declarar una variable en la cual se almacene el valor devuelto porel procedimiento; luego, ejecutar el procedimiento asignándole el valor devuelto a la variable,finalmente mostramos el contenido de la variable:declare @retorno intexec @retorno=pa_libros_ingreso Alicia en el pais...,Lewis Carrollselect Ingreso realizado=1 = @retornoexec @retorno=pa_libros_ingresoselect Ingreso realizado=1 = @retorno;También podríamos emplear un "if" para controlar el valor de la variable de retorno:declare @retorno int;exec @retorno=pa_libros_ingreso El gato con botas,Anónimoif @retorno=1 print Registro ingresadoelse select Registro no ingresado porque faltan datos;
    • 125 - Procedimientos almacenados (información)DETALLE DE CONCEPTOLos procedimientos almacenados son objetos, así que para obtener información de ellos puedenusarse los siguientes procedimientos almacenados del sistema y las siguientes tablas:- "sp_help": sin parámetros nos muestra todos los objetos de la base de datos seleccionada,incluidos los procedimientos. En la columna "Object_type" aparece "stored procedure" si es unprocedimiento almacenado. Si le enviamos como argumento el nombre de un procedimiento,obtenemos la fecha de creación e información sobre sus parámetros.- "sp_helptext": seguido del nombre de un procedimiento almacenado nos muestra el texto quedefine el procedimiento, excepto si ha sido encriptado.- "sp_stored_procedures": muestra todos los procedimientos almacenados, los propietarios, etc.Este procedimiento almacenado puede recibir 3 parámetros: @sp_name (nombre, nvarchar,admite comodines para búsqueda de patrones), @sp_owner (propietario, nvarchar, admitecomodines) y @qualifier (nombre de la base de datos). Por ejemplo, podemos ver todos losprocedimientos almacenados creados por nosotros con esta sentencia:sp_stored_procedures @sp_name=pa_%;- "sp_depends": seguido del nombre de un objeto, nos devuelve 2 resultados: 1) nombre, tipo,campos, etc. de los objetos de los cuales depende el objeto enviado y 2) nombre y tipo de losobjetos que dependen del objeto nombrado. Por ejemplo, ejecutamos "sp_depends" seguido delnombre de un procedimiento:sp_depends pa_autor_promedio;aparecen las tablas (y demás objetos) de las cuales depende el procedimiento, es decir, las tablasreferenciadas en el mismo. Podemos ejecutar el procedimiento seguido del nombre de una tabla:sp_depends libros;aparecen los procedimientos (y demás objetos) que dependen de ella.- La tabla del sistema "sysobjects": muestra nombre y varios datos de todos los objetos de la basede datos actual. La columna "xtype" indica el tipo de objeto. Si es un procedimiento almacenado,muestra "P". Ejemplo:select *from sysobjects;Si queremos ver todos los procedimientos almacenados creados por nosotros, podemos tipear:select *from sysobjects where xtype=P and-- tipo procedimiento name like pa%;--búsqueda con comodín
    • 126 - Procedimientos almacenados (encriptado)DETALLE DE CONCEPTODijimos que SQL Server guarda el nombre del procedimiento almacenado en la tabla del sistema"sysobjects" y su contenido en la tabla "syscomments".Si no quiere que los usuarios puedan leer el contenido del procedimiento podemos indicarle a SQLServer que codifique la entrada a la tabla "syscomments" que contiene el texto. Para ello, debemoscolocar la opción "with encryption" al crear el procedimiento:create procedure NOMBREPROCEDIMIENTO PARAMETROS with encryption as INSTRUCCIONES;Esta opción es opcional.Creamos el procedimiento almacenado "pa_libros_autor" con la opción de encriptado:create procedure pa_libros_autor @autor varchar(30)=null with encryption as select *from libros where autor=@autor;Si ejecutamos el procedimiento almacenado del sistema "sp_helptext" para ver su contenido, noaparece.127 - Procedimientos almacenados (modificar)DETALLE DE CONCEPTOLos procedimientos almacenados pueden modificarse, por necesidad de los usuarios o porcambios en la estructura de las tablas que referencia.Un procedimiento almacenado existente puede modificarse con "alter procedure". Sintaxis:alter procedure NOMBREPROCEDIMIENTO@PARAMETRO TIPO = VALORPREDETERMINADOas SENTENCIAS;Modificamos el procedimiento almacenado "pa_libros_autor" para que muestre, además del título,la editorial y precio:alter procedure pa_libros_autor@autor varchar(30)=nullas
    • if @autor is nullbegin select Debe indicar un autor returnendelse select titulo,editorial,precio from libros where autor = @autor;Si quiere modificar un procedimiento que se creó con la opción "with encryption" y quiereconservarla, debe incluirla al alterarlo.128 - Procedimientos almacenados (insertar)DETALLE DE CONCEPTOPodemos ingresar datos en una tabla con el resultado devuelto por un procedimiento almacenado.La instrucción siguiente crea el procedimiento "pa_ofertas", que ingresa libros en la tabla "ofertas":create proc pa_ofertasas select titulo,autor,editorial,precio from libros where precio<50;La siguiente instrucción ingresa en la tabla "ofertas" el resultado del procedimiento "pa_ofertas":insert into ofertas exec pa_ofertas;Las tablas deben existir y los tipos de datos deben coincidir.129 - Procedimientos almacenados (anidados)DETALLE DE CONCEPTOUn procedimiento almacenado puede llamar a otro procedimiento almacenado. El procedimientoque es invocado por otro debe existir cuando creamos el procedimiento que lo llama. Es decir, siun procedimiento A llama a otro procedimiento B, B debe existir al crear A.Los procedimientos almacenados pueden anidarse hasta 32 niveles.Creamos un procedimiento almacenado que reciba 2 números enteros y nos retorne el producto delos mismos:
    • create procedure pa_multiplicar @numero1 int, @numero2 int, @producto int output as select @producto=@numero1*@numero2;Creamos otro procedimiento que nos retorne el factorial de un número, tal procedimiento llamará alprocedimiento "pa_multiplicar": create procedure pa_factorial @numero int as declare @resultado int declare @num int set @resultado=1 set @num=@numero while (@num>1) begin exec pa_multiplicar @resultado,@num, @resultado output set @num=@num-1 end select rtrim(convert(char,@numero))+!=+convert(char,@resultado); Cuando un procedimiento (A) llama a otro (B), el segundo (B) tiene acceso a todos los objetos quecree el primero (A).130 - Procedimientos Almacenados (recompilar)DETALLE DE CONCEPTOLa compilación es un proceso que consiste en analizar el procedimiento almacenado y crear unplan de ejecución. Se realiza la primera vez que se ejecuta un procedimiento almacenado o si elprocedimiento almacenado se debe volver a compilar (recompilación).SQL Server recompila automáticamente un procedimiento almacenado si se realiza algún cambioen la estructura de una tabla (o vista) referenciada en el procedimiento (alter table y alter view) ycuando se modifican las claves (insert o delete) de una tabla referenciada.Un procedimiento almacenado puede recompilarse explícitamente. En general se recomienda nohacerlo excepto si se agrega un índice a una tabla referenciada por el procedimiento o si los datoshan variado mucho desde la última compilación.SQL Server ofrece tres métodos para recompilar explícitamente un procedimiento almacenado:1) Se puede indicar, al crear el procedimiento, que SQL Server no guarde en la caché un plan deejecución para el procedimiento sino que lo compile cada vez que se ejecute.En este caso la sintaxis es la siguiente:create procedure NOMBREPROCEDIMIENTO PARAMETROS
    • with recompile as SENTENCIAS;2) Podemos especificar "with recompile" al momento de ejecutarlo:exec NOMBREPROCEDIMIENTO with recompile;3) Podemos ejecutar el procedimiento almacenado del sistema "sp_recompile". Este procedimientovuelve a compilar el procedimiento almacenado (o desencadenador) que se especifica. La sintaxises:exec sp_recompile NOMBREOBJETO;El parámetro enviado debe ser el nombre de un procedimiento, de un desencadenador, de unatabla o de una vista. Si es el nombre de una tabla o vista, todos los procedimientos almacenadosque usan tal tabla (o vista) se vuelven a compilar.131 - Procedimientos Almacenados (con join)DETALLE DE CONCEPTOHasta ahora, hemos creado procedimientos que incluyen una sola tabla o pocas instrucciones paraaprender la sintaxis, pero la funcionalidad de un procedimiento consiste básicamente en quecontengan muchas instrucciones o instrucciones complejas y así evitar tipear repetidamente dichasinstrucciones; además si no queremos que el usuario conozca la estructura de las tablasinvolucradas, los procedimientos permiten el acceso a ellas.Podemos crear procedimientos que incluyan combinaciones (join), subconsultas, variasinstrucciones y llamadas a otros procedimientos.Podemos crear todos los procedimientos que necesitemos para que realicen todas las operacionesy consultas.PROBLEMA RESUELTOProblema:Vamos a crear procedimientos que incluyan combinaciones (join), subconsultas, variasinstrucciones y llamadas a otros procedimientos.Un club dicta clases de distintos deportes. Almacena la información en varias tablas:- deportes: codigo y nombre,- cursos: numero de curso, codigo de deporte, documento del profesor que lo dicta y dia de la semana,- profesores: documento, nombre y domicilio,- socios: documento, nombre y domicilio,- inscriptos: documento del socio, número del curso y si la matricula está paga o no.Una vez por semana se dicta cada curso.
    • Puede haber varios cursos de un mismo deporte que se dicten distintos días y/o por distintosprofesores. Por ejemplo: curso 1 de natación los lunes por Carlos Caseres, curso 2 de natación losmartes por Carlos Caseres y curso 3 de natación los miércoles por Ana Acosta.Un profesor puede estar a cargo de distintos cursos, incluso de distintos deportes. Por ejemplo:curso 1 de natación los lunes por Carlos Caseres y curso 4 de tenis los miércoles por CarlosCaseres.Quien se inscriba debe ser socio, es decir, debe estar en la tabla "socios".Un socio no puede inscribirse en un mismo curso.Eliminamos las tablas si existen y las creamos:if (object_id(inscriptos)) is not null drop table inscriptos;if (object_id(deportes)) is not null drop table deportes;if (object_id(cursos)) is not null drop table cursos;if (object_id(profesores)) is not null drop table profesores;if (object_id(socios)) is not null drop table socios;create table deportes( codigo tinyint identity, nombre varchar(30), primary key (codigo));create table profesores( documento char(8), nombre varchar(30), domicilio varchar(30), primary key (documento));create table socios( documento char(8), nombre varchar(30), domicilio varchar(30), primary key (documento));create table cursos( numero tinyint identity, codigodeporte tinyint not null,
    • documentoprofesor char(8) not null, dia varchar(15), constraint PK_cursos_numero primary key clustered (numero), constraint FK_cursos_documentoprofesor foreign key (documentoprofesor) references profesores(documento) on update cascade, constraint FK_cursos_codigodeporte foreign key (codigodeporte) references deportes(codigo));create table inscriptos( documentosocio char(8) not null, numero tinyint not null, matricula char(1) --s=paga; n=impaga, constraint PK_inscriptos_documentosocio_numero primary key(documentosocio,numero), constraint FK_inscriptos_documentosocio foreign key (documentosocio) references socios(documento), constraint FK_inscriptos_numero foreign key (numero) references cursos(numero));Ingresamos algunos registros para todas las tablas:insert into deportes values(tenis);insert into deportes values(natacion);insert into deportes values(basquet);insert into deportes values(futbol);insert into profesores values(22222222,Ana Acosta,Colon 123);insert into profesores values(23333333,Carlos Caseres,Sarmiento 847);insert into profesores values(24444444,Daniel Duarte,Avellaneda 284);insert into profesores values(25555555,Fabiola Fuentes,Caseros 456);insert into profesores values(26666666,Gaston Garcia,Bulnes 345);insert into cursos values(1,22222222,jueves);insert into cursos values(1,22222222,viernes);insert into cursos values(1,23333333,miercoles);insert into cursos values(2,22222222,miercoles);insert into cursos values(2,23333333,lunes);insert into cursos values(2,23333333,martes);insert into cursos values(3,24444444,lunes);insert into cursos values(3,24444444,jueves);insert into cursos values(3,25555555,martes);
    • insert into cursos values(3,25555555,viernes);insert into cursos values(4,24444444,martes);insert into cursos values(4,24444444,miercoles);insert into cursos values(4,24444444,viernes);insert into socios values(31111111,Luis Lopez,Colon 464);insert into socios values(30000000,Nora Nores,Bulnes 234);insert into socios values(33333333,Mariano Morales,Sucre 464);insert into socios values(32222222,Patricia Perez,Peru 1234);insert into socios values(34444444,Susana Suarez,Salta 765);insert into inscriptos values(30000000,1,s);insert into inscriptos values(30000000,4,n);insert into inscriptos values(31111111,1,s);insert into inscriptos values(31111111,4,s);insert into inscriptos values(31111111,7,s);insert into inscriptos values(31111111,13,s);insert into inscriptos values(32222222,1,s);insert into inscriptos values(32222222,4,s);Eliminamos el procedimiento "pa_inscriptos", si existe:if (object_id(pa_inscriptos)) is not null drop proc pa_inscriptos;Creamos un procedimiento que muestre el nombre del socio, el nombre del deporte, el día, elprofesor y la matrícula: create procedure pa_inscriptos as select s.nombre, d.nombre, dia, p.nombre, matricula from socios as s join inscriptos as i on s.documento=i.documentosocio join cursos as c on c.numero=i.numero join deportes as d on c.codigodeporte=d.codigo join profesores as p on c.documentoprofesor=p.documento;Si necesitamos esta información frecuentemente, este procedimiento nos evita tipear este joinrepetidamente; además si no queremos que el usuario conozca la estructura de las tablasinvolucradas, éste y otros procedimientos permiten el acceso a ellas.Ejecutamos el procedimiento:exec pa_inscriptos;Eliminamos el procedimiento "pa_documentovalido", si existe:
    • if (object_id(pa_documentovalido)) is not null drop proc pa_documentovalido;Creamos un procedimiento que reciba un documento y nos retorne distintos valores según: seanulo (1), no sea válido (2), no esté en la tabla "socios" (3), sea un socio deudor (4) o sea un sociosin deuda (0):create procedure pa_documentovalido @documento char(8)=null as if @documento is null return 1 else if len(@documento)<8 return 2 else if not exists (select *from socios where documento=@documento) return 3 else begin if exists (select *from inscriptos where documentosocio=@documento and matricula=n) return 4 else return 0 end;Este procedimiento recibe parámetro, emplea "return" e incluye subconsultas.Eliminamos el procedimiento "pa_deportediavalido", si existe:if (object_id(pa_deportediavalido)) is not null drop proc pa_deportediavalido;Creamos un procedimiento al cual le enviamos el nombre de un deporte y el día y nos retorna unvalor diferente según: el nombre del deporte o día sean nulos (1), el día sea inválido (2), deporte nose dicte (3), el deporte se dicte pero no el día ingresado (4) o el deporte se dicte el día ingresado(0):create procedure pa_deportediavalido @deporte varchar(30)=null, @dia varchar (15)=null as if @deporte is null or @dia is null return 1 else if @dia not in (lunes,martes,miercoles,jueves,viernes,sabado) return 2 else begin declare @coddep tinyint select @coddep= codigo from deportes where nombre=@deporte if @coddep is null return 3 else
    • if not exists(select *from cursos where codigodeporte=@coddep and dia=@dia) return 4 else return 0 end;Eliminamos el procedimiento "pa_ingreso", si existe:if (object_id(pa_ingreso)) is not null drop proc pa_ingreso;Creamos un procedimiento que nos permita ingresar una inscripción con los siguientes datos:documento del socio, nombre del deporte, dia y matrícula. El procedimiento llamará a losprocedimientos "pa_documentovalido" y "pa_deportediavalido" y mostrará diferentes mensajes. Unsocio que deba alguna matrícula NO debe poder inscribirse en ningún curso:create procedure pa_ingreso @documento char(8)=null, @deporte varchar(20)=null, @dia varchar(20)=null, @matricula char(1)=null as --verificamos el documento declare @doc int exec @doc=pa_documentovalido @documento if @doc=1 select Ingrese un documento else if @doc=2 select Documento debe tener 8 digitos else if @doc=3 select @documento+ no es socio else if @doc=4 select Socio + @documento+ debe matriculas --verificamos el deporte y el dia declare @depdia int exec @depdia=pa_deportediavalido @deporte, @dia if @depdia=1 select Ingrese deporte y dia else if @depdia=2 select Ingrese día válido else if @depdia=3 select @deporte+ no se dicta else if @depdia=4 select @deporte+ no se dicta el + @dia; --verificamos que el socio no esté inscripto ya en el deporte el día solicitado if @doc=0 and @depdia=0 begin declare @codcurs int select @codcurs=c.numero from cursos as c join deportes as d on c.codigodeporte=d.codigo where @deporte=d.nombre and
    • @dia=c.dia if exists (select *from inscriptos as i join cursos as c on i.numero=c.numero where @codcurs=i.numero and i.documentosocio=@documento) select Ya está inscripto en +@deporte+ el + @dia else if @matricula is null or @matricula=s or @matricula=n begin insert into inscriptos values(@documento,@codcurs,@matricula) print Inscripción del socio +@documento+ para +@deporte+ el +@dia+ realizada end else select Matricula debe ser s, n o null end;Este procedimiento recibe parámetros, declara variables locales, llama a otros procedimientos yevalua los resultados devueltos con "if" y emplea join.Podemos ejecutar el procedimiento "pa_ingreso" con distintos valores para ver el resultado.Enviamos un documento que no está en "socios":exec pa_ingreso 22222222;Enviamos un documento de un socio que tiene deudas:exec pa_ingreso 30000000;Enviamos un documento de un socio que no tiene deudas, pero falta el deporte y el día:exec pa_ingreso 31111111;Enviamos valor de día inválido:exec pa_ingreso 31111111,tenis,sabado;Enviamos datos que ya están en la tabla "inscriptos":exec pa_ingreso 31111111,tenis,jueves;Enviamos el documento de un socio y un deporte y día en el cual no está inscripto:exec pa_ingreso 33333333,tenis,jueves;Podemos verificar este ingreso consultando "pa_inscriptos":exec pa_inscriptos;Aparece la nueva inscripción con valor nulo en matrícula, porque no enviamos ese dato.
    • Eliminamos el procedimiento "pa_profesor", si existe:if (object_id(pa_profesor)) is not null drop proc pa_profesor;Creamos un procedimiento que recibe el documento de un profesor y nos muestra los distintosdeportes de los cuales está a cargo y los días en que se dictan:create proc pa_profesor @documento char(8)=nullas if @documento is null or len(@documento)<8 select Ingrese un documento válido else begin declare @nombre varchar(30) select @nombre=nombre from profesores where documento=@documento if @nombre is null select No es profesor else if not exists(select *from cursos where documentoprofesor=@documento) select El profesor +@nombre+ no tiene cursos asignados else select d.nombre,c.dia from cursos as c join deportes as d on c.codigodeporte=d.codigo where c.documentoprofesor=@documento end;Ejecutamos el procedimiento creado anteriormente enviando un documento que no está en la tabla"profesores":exec pa_profesor 34343434;Nuevamente ejecutamos el procedimiento creado anteriormente, esta vez con un documentoexistente en "profesores":exec pa_profesor 22222222;Eliminamos el procedimiento "pa_inscriptos_por_curso", si existe:if (object_id(pa_inscriptos_por_curso)) is not null drop proc pa_inscriptos_por_curso;Creamos un procedimiento que recibe un parámetro correspondiente al nombre de un deporte ymuestra los distintos cursos (número, día y profesor) y la cantidad de inscriptos; en caso que elparámetro sea "null", muestra la información de todos los cursos:
    • create procedure pa_inscriptos_por_curso @deporte varchar(20)=nullas if @deporte is null select c.numero,d.nombre,dia,p.nombre, (select count(*) from inscriptos as i where i.numero=c.numero) as cantidad from cursos as c join deportes as d on c.codigodeporte=d.codigo join profesores as p on p.documento=c.documentoprofesor else select c.numero,dia,p.nombre, (select count(*) from inscriptos as i where i.numero=c.numero) as cantidad from cursos as c join deportes as d on c.codigodeporte=d.codigo join profesores as p on p.documento=c.documentoprofesor where d.nombre=@deporte;Este procedimiento recibe un parámetro, emplea subconsulta y join, no retorna valores.Ejecutamos el procedimiento sin enviar valor para el parámetro:exec pa_inscriptos_por_curso;Ejecutamos el procedimiento enviando un valor:exec pa_inscriptos_por_curso tenis;Ejecutamos el procedimiento enviando otro valor:pa_inscriptos_por_curso voley;Veamos las dependencias. Ejecutamos "sp_depends" con distintos objetos:exec sp_depends socios;Muestra que los procedimientos "pa_documentovalido" y "pa_inscriptos" dependen de ella.Ejecutamos "sp_depends" enviándole el nombre de otra tabla:exec sp_depends profesores;
    • Muestra que los procedimientos "pa_inscriptos_por_curso", "pa_profesor" y "pa_inscriptos"dependen de ella.Ejecutamos "sp_depends" enviándole el nombre de otra tabla:exec sp_depends cursos;Muestra que los procedimientos "pa_deportevalido", "pa_ingreso", inscriptos_por_curso","pa_profesor" y "pa_inscriptos" dependen de ella.Ejecutamos "sp_depends" enviándole el nombre de otra tabla:exec sp_depends deportes;Muestra que los procedimientos "pa_deportevalido", "pa_ingreso", inscriptos_por_curso","pa_profesor" y "pa_inscriptos" dependen de ella.Vemos las dependencias de "inscriptos":exec sp_depends inscriptos;Muestra que los procedimientos "pa_deportevalido", "pa_ingreso", inscriptos_por_curso" y"pa_inscriptos" dependen de ella.Vemos las dependencias de los distintos procedimientos:exec sp_depends pa_documentovalido;Muestra que el procedimiento "pa_ingreso" dependen de él y que él depende de las tablas "socios"e "inscriptos" (de esta tabla referencia 2 campos).Ejecutamos el mismo procedimiento enviando el nombre de otro procedimiento:exec sp_depends pa_inscriptos;Muestra que no hay objetos que dependen de él y que él depende de las tablas "inscriptos" (3campos), "cursos" (4 campos), "profesores" (2 campos), socios" (2 campos) y "deportes" (2campos).Ejecutamos otra vez "sp_depends" enviando el nombre de otro procedimiento:exec sp_depends pa_deportediavalido;Aparecen las 2 tablas y los campos a los cuales referencia, es decir, de las cuales depende y elnombre del procedimiento "pa_ingreso" que lo referencia a él, es decir, que depende de él.Vemos las dependencias del procedimiento almacenado "pa_ingreso":exec sp_depends pa_ingreso;
    • No tiene objetos dependientes de él pero si depende de varios, de 2 procedimientos y 4 tablas.Vemos las dependencias del procedimiento almacenado "pa_profesor":exec sp_depends pa_profesor;No tiene objetos dependientes de él pero si depende de varios, de 3 tablas.Finalmente vemos las dependencias del procedimiento "pa_inscritos_por_curso":exec sp_depends pa_inscriptos_por_curso;No tiene objetos dependientes de él pero si depende de varios a los cuales hace referencia (4tablas).132 - Tablas temporalesDETALLE DE CONCEPTOLas tablas temporales son visibles solamente en la sesión actual.Las tablas temporales se eliminan automáticamente al acabar la sesión o la función oprocedimiento almacenado en el cual fueron definidas. Se pueden eliminar con "drop table".Pueden ser locales (son visibles sólo en la sesión actual) o globales (visibles por todas lassesiones).Para crear tablas temporales locales se emplea la misma sintaxis que para crear cualquier tabla,excepto que se coloca un signo numeral (#) precediendo el nombre.create table #NOMBRE( CAMPO DEFINICION, ...);Para referenciarla en otras consultas, se debe incluir el numeral(#), que es parte del nombre. Porejemplo:insert into #libros default values;select *from #libros;Una tabla temporal no puede tener una restricción "foreign key" ni ser indexada, tampoco puedeser referenciada por una vista.Para crear tablas temporales globales se emplea la misma sintaxis que para crear cualquier tabla,excepto que se coloca un signo numeral doble (##) precediendo el nombre.create table ##NOMBRE(
    • CAMPO DEFINICION, ...);El (o los) numerales son parte del nombre. Así que puede crearse una tabla permanente llamada"libros", otra tabla temporal local llamada "#libros" y una tercera tabla temporal global denominada"##libros".No podemos consultar la tabla "sysobjects" para ver las tablas temporales, debemos tipear:select *from tempdb..sysobjects;133 - FuncionesDETALLE DE CONCEPTOSQL Server ofrece varios tipos de funciones para realizar distintas operaciones. Hemos visto yempleado varias de ellas.Se pueden emplear las funciones del sistema en cualquier lugar en el que se permita unaexpresión en una sentencia "select".Las funciones pueden clasificarse en:- deterministicas: siempre retornan el mismo resultado si se las invoca enviando el mismo valor deentrada. Todas las funciones de agregado y string son deterministicas, excepto "charindex" y"patindex".- no deterministicas: pueden retornar distintos resultados cada vez que se invocan con el mismovalor de entrada. Las siguientes son algunas de las funciones no deterministicas: getdate,datename, textptr, textvalid, rand. Todas las funciones de configuración, cursor, meta data,seguridad y estadísticas del sistema son no deterministicas.SQL Server provee muchas funciones y además permite que el usuario pueda definir sus propiasfunciones.Sabemos que una función es un conjunto de sentencias que operan como una unidad lógica, unarutina que retorna un valor. Una función tiene un nombre, acepta parámetros de entrada y retornaun valor escalar o una tabla.Los parámetros de entrada pueden ser de cualquier tipo, excepto timestamp, cursor y table.Las funciones definidas por el usuario no permiten parámetros de salida.No todas las sentencias SQL son válidas dentro de una función. NO es posible emplear en ellasfunciones no determinadas (como getdate()) ni sentencias de modificación o actualización detablas o vistas. Si podemos emplear sentencias de asignación, de control de flujo (if), demodificación y eliminación de variables locales.
    • SQL Server admite 3 tipos de funciones definidas por el usuario clasificadas según el valorretornado:1) escalares: retornan un valor escalar;2) de tabla de varias instrucciones (retornan una tabla) y3) de tabla en línea (retornan una tabla).Las funciones definidas por el usuario se crean con la instrucción "create function" y se eliminancon "drop function".134 - Funciones (drop)DETALLE DE CONCEPTOLas funciones definidas por el usuario se eliminan con la instrucción "drop function":Sintaxis:drop function NOMBREPPROPIETARIO.NOMBREFUNCION;Se coloca el nombre del propietario seguido del nombre de la función.Si la función que se intenta eliminar no existe, aparece un mensaje indicándolo, para evitarlo,podemos verificar su existencia antes de solicitar su eliminación (como con cualquier otro objeto):if object_id(NOMBREPROPIETARIO.NOMBREFUNCION) is not null drop function NOMBREPROPIETARIO.NOMBREFUNCION;Eliminamos, si existe, la función denominada "f_fechacadena":if object_id(dbo.f_fechacadena) is not null drop function dbo.f_fechacadena;135 - Funciones escalares (crear y llamar)DETALLE DE CONCEPTOUna función escalar retorna un único valor. Como todas las funciones, se crean con la instrucción"create function". La sintaxis básica es:create function NOMBRE(@PARAMETRO TIPO=VALORPORDEFECTO) returns TIPO begin INSTRUCCIONES return VALOR
    • end;Luego del nombre se colocan (opcionalmente) los parámetros de entrada con su tipo.La cláusula "returns" indica el tipo de dato retornado.El cuerpo de la función, se define en un bloque "begin...end" que contiene las instrucciones queretornan el valor. El tipo del valor retornado puede ser de cualquier tipo, excepto text, ntext, image,cursor o timestamp.Creamos una simple función denominada "f_promedio" que recibe 2 valores y retorna el promedio:create function f_promedio(@valor1 decimal(4,2), @valor2 decimal(4,2))returns decimal (6,2)asbegin declare @resultado decimal(6,2) set @resultado=(@valor1+@valor2)/2 return @resultadoend;Entonces, luego de "create function" y el nombre de la función, se deben especificar losparámetros de entrada con sus tipos de datos (entre paréntesis), el tipo de dato que retorna luegode "returns", luego de "as" comienza el bloque "begin...end" dentro del cual se encuentran lasinstrucciones de procesamiento y el valor retornado luego de "return".En el ejemplo anterior se declara una variable local a la función (desaparece al salir de la función)que calcula el resultado que se retornará.Al hacer referencia a una función escalar, se debe especificar el propietario y el nombre de lafunción:select dbo.f_promedio(5.5,8.5);Cuando llamamos a funciones que tienen definidos parámetros de entrada DEBEMOS suministrarSIEMPRE un valor para él.Si llamamos a la función anterior sin enviarle los valores para los parámetros:select dbo.f_promedio();SQL Server muestra un mensaje de error indicando que necesita argumentos.Creamos una función a la cual le enviamos una fecha y nos retorna el nombre del mes en español:create function f_nombreMes
    • (@fecha datetime=2007/01/01) returns varchar(10) as begin declare @nombre varchar(10) set @nombre= case datename(month,@fecha) when January then Enero when February then Febrero when March then Marzo when April then Abril when May then Mayo when June then Junio when July then Julio when August then Agosto when September then Setiembre when October then Octubre when November then Noviembre when December then Diciembre end--case return @nombreend;Analicemos: luego de "create function" y el nombre de la función, especificamos los parámetros deentrada con sus tipos de datos (entre paréntesis). El parámetro de entrada tiene definido un valorpor defecto.Luego de los parámetros de entrada se indica el tipo de dato que retorna luego de "returns"; luegode "as" comienza el bloque "begin...end" dentro del cual se encuentran las instrucciones deprocesamiento y el valor retornado luego de "return".Las funciones que retornan un valor escalar pueden emplearse en cualquier consulta donde secoloca un campo.Recuerde que al invocar una función escalar, se debe especificar el propietario y el nombre de lafunción:select nombre, dbo.f_nombreMes(fechaingreso) as mes de ingresofrom empleados;No olvide que cuando invocamos funciones que tienen definidos parámetros de entradaDEBEMOS suministrar SIEMPRE un valor para él.Podemos colocar un valor por defecto al parámetro, pero al invocar la función, para que tome elvalor por defecto DEBEMOS especificar "default". Por ejemplo, si llamamos a la función anterior sinenviarle un valor:select dbo.f_nombreMes();
    • SQL Server muestra un mensaje de error indicando que necesita argumento.Para que tome el valor por defecto debemos enviar "default" como argumento:select dbo.f_nombreMes(default);La instrucción "create function" debe ser la primera sentencia de un lote.136 - Funciones de tabla de varias instruccionesDETALLE DE CONCEPTOHemos visto el primer tipo de funciones definidas por el usuario, que retornan un valor escalar.Ahora veremos las funciones con varias instrucciones que retornan una tabla.Las funciones que retornan una tabla pueden emplearse en lugar de un "from" de una consulta.Este tipo de función es similar a un procedimiento almacenado; la diferencia es que la tablaretornada por la función puede ser referenciada en el "from" de una consulta, pero el resultado deun procedimiento almacenado no.También es similar a una vista; pero en las vistas solamente podemos emplear "select", mientrasque en funciones definidas por el usuario podemos incluir sentencias como "if", llamadas afunciones, procedimientos, etc.Sintaxis:create function NOMBREFUNCION(@PARAMETRO TIPO)returns @NOMBRETABLARETORNO table-- nombre de la tabla--formato de la tabla(CAMPO1 TIPO, CAMPO2 TIPO, CAMPO3 TIPO)asbegin insert @NOMBRETABLARETORNO select CAMPOS from TABLA where campo OPERADOR @PARAMETRO RETURNendComo cualquier otra función, se crea con "create function" seguida del nombre de la función; luego(opcionalmente) los parámetros de entrada con su tipo de dato.
    • La cláusula "returns" define un nombre de variable local para la tabla que retornará, el tipo de datosa retornar (que es "table") y el formato de la misma (campos y tipos).El cuerpo de la función se define también en un bloque "begin... end", el cual contiene lasinstrucciones que insertan filas en la variable (tabla que será retornada) definida en "returns"."return" indica que las filas insertadas en la variable son retornadas; no puede ser un argumento.El siguiente ejemplo crea una función denominada "f_ofertas" que recibe un parámetro. La funciónretorna una tabla con el codigo, título, autor y precio de todos los libros cuyo precio sea inferior alparámetro:create function f_ofertas(@minimo decimal(6,2))returns @ofertas table-- nombre de la tabla--formato de la tabla(codigo int, titulo varchar(40), autor varchar(30), precio decimal(6,2))asbegin insert @ofertas select codigo,titulo,autor,precio from libros where precio < @minimo returnend;Las funciones que retornan una tabla pueden llamarse sin especificar propietario:select *from f_ofertas(30);select *from dbo.f_ofertas(30);Dijimos que este tipo de función puede ser referenciada en el "from" de una consulta; la siguienteconsulta realiza un join entre la tabla "libros" y la tabla retornada por la función "f_ofertas":select *from libros as l join dbo.f_ofertas(25) as o on l.codigo=o.codigo;Se puede llamar a la función como si fuese una tabla o vista listando algunos campos:select titulo,precio from dbo.f_ofertas(40);
    • 137 - Funciones con valores de tabla en líneaDETALLE DE CONCEPTOUna función con valores de tabla en línea retorna una tabla que es el resultado de una únicainstrucción "select".Es similar a una vista, pero más flexible en el empleo de parámetros. En una vista no se puedeincluir un parámetro, lo que hacemos es agregar una cláusula "where" al ejecutar la vista. Lasfunciones con valores de tabla en línea funcionan como una vista con parámetros.Sintaxis:create function NOMBREFUNCION(@PARAMETRO TIPO=VALORPORDEFECTO)returns tableasreturn ( select CAMPOS from TABLA where CONDICION);Como todas las funciones definidas por el usuario, se crea con "create function" seguido delnombre que le damos a la función; luego declaramos los parámetros de entrada con su tipo dedato entre paréntesis. El valor por defecto es opcional."returns" especifica "table" como el tipo de datos a retornar. No se define el formato de la tabla aretornar porque queda establecido en el "select".El cuerpo de la función no contiene un bloque "begin...end" como las otras funciones.La cláusula "return" contiene una sola instrucción "select" entre paréntesis. El resultado del "select"es la tabla que se retorna. El "select" está sujeto a las mismas reglas que los "select" de las vistas.Creamos una función con valores de tabla en línea que recibe un valor de autor como parámetro:create function f_libros(@autor varchar(30)=Borges)returns tableasreturn ( select titulo,editorial from libros where autor like %+@autor+%);Estas funciones retornan una tabla y se hace referencia a ellas en la cláusula "from", como unavista:
    • select *from f_libros(Bach);Recuerde a que todas las funciones que tienen definidos parámetros se les DEBE suministrarvalores para ellos al invocarse.Recuerde que para que el parámetro tome el valor por defecto (si lo tiene) DEBE enviarse "default"al llamar a la función; si no le enviamos parámetros, SQL Server muestra un mensaje de error.--incorrecto: select *from f_libros(); select *from f_libros(default);--correcto138 - Funciones (modificar)DETALLE DE CONCEPTOLas funciones de SQL Server no pueden ser modificadas, las funciones definidas por el usuario si.Las funciones definidas por el usuario pueden modificarse con la instrucción "alter function".Sintaxis general:alter function PROPIETARIO.NOMBREFUNCIONNUEVADEFINICION;Sintaxis para modificar funciones escalares:alter funtion PROPIETARIO.NOMBREFUNCION(@PARAMETRO TIPO=VALORPORDEFECTO) returns TIPO as begin CUERPO return EXPRESIONESCALAR endSintaxis para modificar una función de varias instrucciones que retorna una tabla:alter function NOMBREFUNCION(@PARAMETRO TIPO=VALORPORDEFECTO)returns @VARIABLE table(DEFINICION DE LA TABLA A RETORNAR)asbegin CUERPO DE LA FUNCION returnendSintaxis para modificar una función con valores de tabla en línea
    • alter function NOMBREFUNCION(@PARAMETRO TIPO)returns TABLEas return (SENTENCIAS SELECT)Veamos un ejemplo. Creamos una función que retorna una tabla en línea:create function f_libros(@autor varchar(30)=Borges)returns tableasreturn ( select titulo,editorial from libros where autor like %+@autor+%);La modificamos agregando otro campo en el "select":alter table f_libros(@autor varchar(30)=Borges)returns tableasreturn ( select codigo,titulo,editorial from libros where autor like %+@autor+%);139 - Funciones (encriptado)DETALLE DE CONCEPTOLas funciones definidas por el usuario pueden encriptarse, para evitar que sean leídas con"sp_helptext".Para ello debemos agregar al crearlas la opción "with encryption" antes de "as".En funciones escalares:create function NOMBREFUNCION(@PARAMETRO TIPO) returns TIPO with encryption as begin CUERPO
    • return EXPRESION endEn funciones de tabla de varias sentencias se coloca luego del formato de la tabla a retornar:create function NOMBREFUNCION(@PARAMETRO TIPO)returns @NOMBRETABLARETORNO table-- nombre de la tabla--formato de la tabla(CAMPO1 TIPO, CAMPO2 TIPO, CAMPO3 TIPO)with encryptionasbegin insert @NOMBRETABLARETORNO select CAMPOS from TABLA where campo OPERADOR @PARAMETRO RETURNendEn funciones con valores de tabla en línea:create function NOMBREFUNCION(@PARAMETRO TIPO=VALORPORDEFECTO)returns tablewith encryptionasreturn (SELECT);Veamos un ejemplo:create function f_libros(@autor varchar(30)=Borges)returns tablewith encryptionasreturn ( select titulo,editorial from libros where autor like %+@autor+%);Si ejecutamos el procedimiento almacenado del sistema "sp_helptext" seguido del nombre de lafunción creada anteriormente, SQL Server mostrará un mensaje indicando que tal función estáencriptada.
    • 140 - Funciones (información)DETALLE DE CONCEPTOLas funciones son objetos, así que para obtener información de ellos pueden usarse los siguientesprocedimientos almacenados del sistema y las siguientes tablas:- "sp_help": sin parámetros nos muestra todos los objetos de la base de datos seleccionada,incluidas las funciones definidas por el usuario. En la columna "Object_type" aparece "scalarfunction" si es una función escalar, "table function" si es una función de tabla de varias sentencias y"inline function" si es una función de tabla en línea.Si le enviamos como argumento el nombre de una función definida por el usuario, obtenemos elpropietario, el tipo de función y la fecha de creación; si es una función de tabla, los campos de latabla retornada.- "sp_helptext": seguido del nombre de una función definida por el usuario nos muestra el texto quedefine la función, excepto si ha sido encriptado.- "sp_stored_procedures": muestra todos los procedimientos almacenados y funciones definidaspor el usuario.- "sp_depends": seguido del nombre de un objeto, nos devuelve 2 resultados: 1) nombre, tipo,campos, etc. de los objetos de los cuales depende el objeto enviado (referenciados por el objeto) y2) nombre y tipo de los objetos que dependen del objeto nombrado (que lo referencian). Porejemplo, ejecutamos "sp_depends" seguido del nombre de una función definida por el usuario:sp_depends pa_libroslistado;aparecen las tablas (y demás objetos) de las cuales depende el procedimiento, es decir, las tablas(y campos) referenciadas en la misma. No aparecen objetos que dependan de la función porque noexiste ningún objeto que la referencie.Podemos ejecutar el procedimiento seguido del nombre de una tabla:sp_depends libros;aparecen las funciones (y demás objetos) que dependen de ella (que la referencian). No aparecenobjetos de los cuales depende porque la tabla no los tiene.- La tabla del sistema "sysobjects": muestra nombre y varios datos de todos los objetos de la basede datos actual. La columna "xtype" indica el tipo de objeto. Si es una función definida por elusuario escalar, muestra "FN", si es una función de tabla de varias sentencias, muestra "TF" y si esuna función de tabla en linea muestra "IF".Si queremos ver el nombre, tipo y fecha de creación de todas las funciones definidas por elusuario, podemos tipear:
    • select name,xtype as tipo,crdate as fecha from sysobjects where xtype in (FN,TF,IF);141 - Disparadores (triggers)DETALLE DE CONCEPTOUn "trigger" (disparador o desencadenador) es un tipo de procedimiento almacenado que seejecuta cuando se intenta modificar los datos de una tabla (o vista).Se definen para una tabla (o vista) específica.Se crean para conservar la integridad referencial y la coherencia entre los datos entre distintastablas.Si se intenta modificar (agregar, actualizar o eliminar) datos de una tabla en la que se definió undisparador para alguna de estas acciones (inserción, actualización y eliminación), el disparador seejecuta (se dispara) en forma automática.Un trigger se asocia a un evento (inserción, actualización o borrado) sobre una tabla.La diferencia con los procedimientos almacenados del sistema es que los triggers:- no pueden ser invocados directamente; al intentar modificar los datos de una tabla para la que seha definido un disparador, el disparador se ejecuta automáticamente.- no reciben y retornan parámetros.- son apropiados para mantener la integridad de los datos, no para obtener resultados deconsultas.Los disparadores, a diferencia de las restricciones "check", pueden hacer referencia a campos deotras tablas. Por ejemplo, puede crearse un trigger de inserción en la tabla "ventas" quecompruebe el campo "stock" de un artículo en la tabla "articulos"; el disparador controlaría que,cuando el valor de "stock" sea menor a la cantidad que se intenta vender, la inserción del nuevoregistro en "ventas" no se realice.Los disparadores se ejecutan DESPUES de la ejecución de una instrucción "insert", "update" o"delete" en la tabla en la que fueron definidos. Las restricciones se comprueban ANTES de laejecución de una instrucción "insert", "update" o "delete". Por lo tanto, las restricciones secomprueban primero, si se infringe alguna restricción, el desencadenador no llega a ejecutarse.Los triggers se crean con la instrucción "create trigger". Esta instrucción especifica la tabla en laque se define el disparador, los eventos para los que se ejecuta y las instrucciones que contiene.Sintaxis básica:
    • create triggre NOMBREDISPARADOR on NOMBRETABLA for EVENTO- insert, update o deleteas SENTENCIASAnalizamos la sintaxis:- "create trigger" junto al nombre del disparador.- "on" seguido del nombre de la tabla o vista para la cual se establece el trigger.- luego de "for", se indica la acción (evento, el tipo de modificación) sobre la tabla o vista queactivará el trigger. Puede ser "insert", "update" o "delete". Debe colocarse al menos UNA acción, sise coloca más de una, deben separarse con comas.- luego de "as" viene el cuerpo del trigger, se especifican las condiciones y acciones deldisparador; es decir, las condiciones que determinan cuando un intento de inserción, actualizacióno borrado provoca las acciones que el trigger realizará.Consideraciones generales:- "create trigger" debe ser la primera sentencia de un bloque y sólo se puede aplicar a una tabla.- un disparador se crea solamente en la base de datos actual pero puede hacer referencia aobjetos de otra base de datos.- Las siguientes instrucciones no están permitidas en un desencadenador: create database, alterdatabase, drop database, load database, restore database, load log, reconfigure, restore log, diskinit, disk resize.- Se pueden crear varios triggers para cada evento, es decir, para cada tipo de modificación(inserción, actualización o borrado) para una misma tabla. Por ejemplo, se puede crear un "inserttrigger" para una tabla que ya tiene otro "insert trigger".A continuación veremos la creación de un disparador para el suceso de inserción: "insert triger".142 - Disparador de inserción (insert trigger)DETALLE DE CONCEPTOPodemos crear un disparador para que se ejecute siempre que una instrucción "insert" ingresedatos en una tabla.Sintaxis básica:create triggre NOMBREDISPARADOR on NOMBRETABLA for insert
    • as SENTENCIASAnalizamos la sintaxis:"create trigger" junto al nombre del disparador; "on" seguido del nombre de la tabla para la cual seestablece el trigger.Luego de "for" se coloca el evento (en este caso "insert"), lo que indica que las inserciones sobre latabla activarán el trigger.Luego de "as" se especifican las condiciones y acciones, es decir, las condiciones que determinancuando un intento de inserción provoca las acciones que el trigger realizará.Creamos un trigger sobre la tabla "ventas" para el evento se inserción. Cada vez que se realiza un"insert" sobre "ventas", el disparador se ejecuta. El disparador controla que la cantidad que seintenta vender sea menor o igual al stock del libro y actualiza el campo "stock" de "libros", restandoal valor anterior la cantidad vendida:create trigger DIS_ventas_insertar on ventas for insert as declare @stock int select @stock= stock from libros join inserted on inserted.codigolibro=libros.codigo where libros.codigo=inserted.codigolibro if (@stock>=(select cantidad from inserted)) update libros set stock=stock-inserted.cantidad from libros join inserted on inserted.codigolibro=libros.codigo where codigo=inserted.codigolibro else begin raiserror (Hay menos libros en stock de los solicitados para la venta, 16, 1) rollback transaction endEntonces, creamos el disparador ("create trigger") dándole un nombre ("DI_ventas_insertar") sobre("on") una tabla específica ("ventas") para ("for") el suceso de inserción ("insert"). Luego se "as"colocamos las sentencias, las acciones que el trigger realizará cuando se ingrese un registro en"ventas" (en este caso, controlar que haya stock y disminuir el stock de "libros").Cuando se activa un disparador "insert", los registros se agregan a la tabla del disparador y a unatabla denominada "inserted". La tabla "inserted" es una tabla virtual que contiene una copia de losregistros insertados; tiene una estructura similar a la tabla en que se define el disparador, es decir,la tabla en que se intenta la acción. La tabla "inserted" guarda los valores nuevos de los registros.
    • Dentro del trigger se puede acceder a esta tabla virtual "inserted" que contiene todos los registrosinsertados, es lo que hicimos en el disparador creado anteriormente, lo que solicitamos es que sele reste al "stock" de "libros", la cantidad ingresada en el nuevo registro de "ventas", valor querecuperamos de la tabla "inserted"."rollback transaction" es la sentencia que deshace la transacción, es decir, borra todas lasmodificaciones que se produjeron en la última transacción restableciendo todo al estado anterior."raiserror" muestra un mensaje de error personalizado.Para identificar fácilmente los disparadores de otros objetos se recomienda usar un prefijo y darlesel nombre de la tabla para la cual se crean junto al tipo de acción.La instrucción "writetext" no activa un disparador.143 - Disparador de borrado (delete trigger)DETALLE DE CONCEPTOPodemos crear un disparador para que se ejecute siempre que una instrucción "delete" eliminedatos en una tabla.Sintaxis básica:create triggre NOMBREDISPARADOR on NOMBRETABLA for deleteas SENTENCIASAnalizamos la sintaxis:"create trigger" junto al nombre del disparador; "on" seguido del nombre de la tabla para la cual seestablece el trigger.Luego de "for" se coloca el evento (en este caso "delete"), lo que indica que las eliminacionessobre la tabla activarán el trigger.Luego de "as" se especifican las condiciones que determinan cuando un intento de eliminacióncausa las acciones que el trigger realizará.El disparador del siguiente ejemplo se crea para la tabla "ventas", para que cada vez que seelimine un registro de "ventas", se actualice el campo "stock" de la tabla "libros" (por ejemplo, si elcomprador devuelve los libros comprados):create trigger DIS_ventas_borrar on ventas for delete
    • as update libros set stock= libros.stock+deleted.cantidad from libros join deleted on deleted.codigolibro=libros.codigo;Entonces, creamos el disparador ("create trigger") dándole un nombre ("DI_ventas_borrar") sobre("on") una tabla específica ("ventas") para ("for") el evento de borrado ("delete"). Luego de "as"colocamos las sentencias, las acciones que el trigger realizará cuando se elimine un registro en"ventas" (en este caso, aumentar el stock de "libros").Cuando se activa un disparador "delete", los registros eliminados en la tabla del disparador seagregan a una tabla llamada "deleted". La tabla "deleted" es una tabla virtual que conserva unacopia de los registros eliminados; tiene una estructura similar a la tabla en que se define eldisparador, es decir, la tabla en que se intenta la acción.Dentro del trigger se puede acceder a esta tabla virtual "deleted".El siguiente disparador se crea para controlar que no se elimine más de un registro de la tabla"libros". El disparador se activa cada vez que se elimina un registro o varios, controlando lacantidad de registros que se están eliminando; si se está eliminando más de un registro, eldisparador retorna un mensaje de error y deshace la transacción:create trigger DIS_libros_borrar on libros for delete as if (select count(*) from deleted) > 1 begin raiserror(No puede borrar más de un libro,16,1) rollback transaction end;Si se ejecuta un "delete" sobre "libros" que afecte a varios registros, se activa el disparador y evitala transacción.Si se ejecuta el siguiente "delete", que afecta a un solo registro, se activa el disparador y permite latransacción:delete from libros where codigo=5;La sentencia "truncate table" no puede incluirse en un disparador de borrado (delete trigger).144 - Disparador de actualización (update trigger)DETALLE DE CONCEPTOPodemos crear un disparador para que se ejecute siempre que una instrucción "update" actualicelos datos de una tabla.
    • Sintaxis básica:create triggre NOMBREDISPARADOR on NOMBRETABLA for updateas SENTENCIASAnalizamos la sintaxis:"create trigger" junto al nombre del disparador; "on" seguido del nombre de la tabla para la cual seestablece el trigger.Luego de "for" se coloca el evento (en este caso "update"), lo que indica que las actualizacionessobre la tabla activarán el trigger.Luego de "as" se especifican las condiciones y acciones, es decir, las condiciones que determinancuando un intento de modificación provoca las acciones que el trigger realizará.El siguiente disparador de actualización se crea para evitar que se modifiquen los datos de la tabla"libros":create trigger DIS_libros_actualizar on libros for update as raiserror(Los datos de la tabla "libros" no pueden modificarse, 10, 1) rollback transactionEntonces, creamos el disparador ("create trigger") dándole un nombre ("DI_libros_actualizar")sobre una tabla específica ("libros") para ("for") el suceso de actualización ("update"). Luego de"as" colocamos las sentencias, las acciones que el trigger realizará cuando se intente actualizaruno o varios registros en "libros" (en este caso, impedir las modificaciones).Cuando se ejecuta una instrucción "update" en una tabla que tiene definido un disparador, losregistros originales (antes de ser actualizados) se mueven a la tabla virtual "deleted" y los registrosactualizados (con los nuevos valores) se copian a la tabla virtual "inserted". Dentro del trigger sepuede acceder a estas tablas.En el cuerpo de un trigger se puede emplear la función "update(campo)" que recibe un campo yretorna verdadero si el evento involucra actualizaciones (o inserciones) en ese campo; en casocontrario retorna "false".Creamos un disparador que evite que se actualice el campo "precio" de la tabla "libros":create trigger DIS_libros_actualizar_precio on libros for update
    • as if update(precio) begin raiserror(El precio de un libro no puede modificarse., 10, 1) rollback transaction end;Empleamos "if update()" para que el trigger controle la actualización del campo "precio"; así,cuando el disparador detecte una actualización en tal campo, realizará las acciones apropiadas(mostrar un mensaje y deshacer la actualización); en caso que se actualice otro campo, eldisparador se activa, pero permite la transacción.Creamos un disparador de actualización que muestra el valor anterior y nuevo valor de losregistros actualizados:create trigger DIS_libros_actualizar2 on libros for update as if (update(titulo) or update(autor) or update(editorial)) and not (update(precio) or update(stock)) begin select d.codigo, (d.titulo+-+ d.autor+-+d.editorial) as registro anterior, (i.titulo+-+ i.autor+-+i.editorial) as registro actualizado from deleted as d join inserted as i on d.codigo=i.codigo end else begin raiserror(El precio y stock no pueden modificarse. La actualización no se realizó., 10, 1) rollback transaction end;Empleamos "if update" para que el trigger controle si la actualización se realiza en ciertos campospermitidos (titulo, autor y editorial) y no en los campos prohibidos (precio y stock)); si se modificanlos campos permitidos y ninguno de los no permitidos, mostrará los antiguos y nuevos valoresconsultando las tablas "deleted" e "inserted", en caso que se actualice un campo no permitido, eldisparador muestra un mensaje y deshace la transacción.Note que el disparador no controla los intentos de actualización sobre el campo "codigo", esto esporque tal campo, no puede modificarse porque está definido "identity", si intentamos modificarlo,SQL Server muestra un mensaje de error y el trigger no llega a dispararse.145 - Disparadores (varios eventos)DETALLE DE CONCEPTO
    • Hemos aprendido a crear disparadores para diferentes eventos (insert, update y delete).Dijimos que un disparador puede definirse para más de una acción; en tal caso, deben separarsecon comas.Creamos un trigger para evitar que se inscriban socios que deben matrículas y no permitir que seeliminen las inscripciones de socios deudores. El trigger se define para ambos eventos en lamisma sentencia de creación.create trigger dis_inscriptos_insert_delete on inscriptos for insert,delete as if exists (select *from inserted join morosos on morosos.documento=inserted.documento) begin raiserror(El socio es moroso, no puede inscribirse en otro curso, 16, 1) rollback transaction end else if exists (select *from deleted join morosos on morosos.documento=deleted.documento) begin raiserror(El socio debe matriculas, no puede borrarse su inscripcion, 16, 1) rollback transaction end else if (select matricula from inserted)=n insert into morosos select documento from inserted;El trigger controla:- si se intenta ingresar una inscripción de un socio moroso, se deshace la transacción;- si se intenta eliminar una inscripción de un socio que está en "morosos", se deshace latransacción;- si se ingresa una nueva inscripción y no se paga la matrícula, dicho socio se ingresa a la tabla"morosos".PROBLEMA RESUELTOProblema:Un club almacena los datos de sus socios en una tabla denominada "socios", las inscripciones en"inscriptos" y en otra tabla "morosos" guarda los documentos de los socios que deben matrículas.Eliminamos las tablas si existen:if object_id(inscriptos) is not null drop table inscriptos;if object_id(socios) is not null
    • drop table socios;if object_id(morosos) is not null drop table morosos;Creamos las tablas, con las siguientes estructuras:create table socios( documento char(8) not null, nombre varchar(30), domicilio varchar(30), constraint PK_socios primary key(documento));create table inscriptos( numero int identity, documento char(8) not null, deporte varchar(20), matricula char(1), constraint FK_inscriptos_documento foreign key (documento) references socios(documento), constraint CK_inscriptos_matricula check (matricula in (s,n)), constraint PK_inscriptos primary key(documento,deporte));create table morosos( documento char(8) not null);Ingresamos algunos registros en las 3 tablas:insert into socios values(22222222,Ana Acosta,Avellaneda 800);insert into socios values(23333333,Bernardo Bustos,Bulnes 345);insert into socios values(24444444,Carlos Caseros,Colon 382);insert into socios values(25555555,Mariana Morales,Maipu 234);insert into inscriptos values(22222222,tenis,s);insert into inscriptos values(22222222,natacion,n);insert into inscriptos values(23333333,tenis,n);insert into inscriptos values(24444444,futbol,s);insert into inscriptos values(24444444,natacion,s);insert into morosos values(22222222);insert into morosos values(23333333);Creamos un trigger para evitar que se inscriban socios que deben matrículas y no permitir que seeliminen las inscripciones de socios deudores. El trigger se define para ambos eventos en lamisma sentencia de creación.
    • create trigger dis_inscriptos_insert_delete on inscriptos for insert,delete as if exists (select *from inserted join morosos on morosos.documento=inserted.documento) begin raiserror(El socio es moroso, no puede inscribirse en otro curso, 16, 1) rollback transaction end else if exists (select *from deleted join morosos on morosos.documento=deleted.documento) begin raiserror(El socio debe matriculas, no puede borrarse su inscripcion, 16, 1) rollback transaction end else if (select matricula from inserted)=n insert into morosos select documento from inserted;El trigger controla:- si se intenta ingresar una inscripción de un socio moroso, se deshace la transacción;- si se intenta eliminar una inscripción de un socio que está en "morosos", se deshace latransacción;- si se ingresa una nueva inscripción y no se paga la matrícula, dicho socio se ingresa a la tabla"morosos".Ingresamos una inscripción de un socio no deudor con matrícula paga:insert into inscriptos values(25555555,tenis,s);El disparador se activa ante el "insert" y permite la transacción.Ingresamos una inscripción de un socio no deudor con matrícula n:insert into inscriptos values(25555555,natacion,n);El disparador se activa ante el "insert", permite la transacción y agrega al socio en la tabla"morosos". Verifiquémoslo consultando las tablas correspondientes:select *from inscriptos;select *from morosos;Ingresamos una inscripción de un socio deudor:
    • insert into inscriptos values(25555555,basquet,s);El disparador se activa ante el "insert" y deshace la transacción porque encuentra su documentoen la tabla "morosos".Eliminamos una inscripción de un socio no deudor:delete inscriptos where numero=4;El disparador se activa ante la sentencia "delete" y permite la transacción. Verificamos que lainscripción nº 4 fue eliminada de "inscriptos":select *from inscriptos;Intentamos eliminar una inscripción de un socio deudor:delete inscriptos where numero=6;El disparador se activa ante el "delete" y deshace la transacción porque encuentra su documentoen "morosos".146 - Disparador (Instead Off y after)DETALLE DE CONCEPTOHasta el momento hemos aprendido que un trigger se crea sobre una tabla específica para unevento (inserción, eliminación o actualización).También podemos especificar el momento de disparo del trigger. El momento de disparo indicaque las acciones (sentencias) del trigger se ejecuten luego de la acción (insert, delete o update)que dispara el trigger o en lugar de la acción.La sintaxis para ello es:create triggre NOMBREDISPARADOR on NOMBRETABLA o VISTA MOMENTODEDISPARO-- after o instead of ACCION-- insert, update o deleteas SENTENCIASEntonces, el momento de disparo especifica cuando deben ejecutarse las acciones (sentencias)que realiza el trigger. Puede ser "después" (after) o "en lugar" (instead of) del evento que lodispara.Si no especificamos el momento de disparo en la creación del trigger, por defecto se establececomo "after", es decir, las acciones que el disparador realiza se ejecutan luego del sucesodisparador. Hasta el momento, todos los disparadores que creamos han sido "after".
    • Los disparadores "instead of" se ejecutan en lugar de la acción desencadenante, es decir,cancelan la acción desencadenante (suceso que disparó el trigger) reemplazándola por otrasacciones.Veamos un ejemplo. Una empresa almacena los datos de sus empleados en una tabla"empleados" y en otra tabla "clientes" los datos de sus clientes. Se crea una vista que muestra losdatos de ambas tablas:create view vista_empleados_clientesas select documento,nombre, domicilio, empleado as condicion from empleados union select documento,nombre, domicilio,cliente from clientes;Creamos un disparador sobre la vista "vista_empleados_clientes" para inserción, que redirija lasinserciones a la tabla correspondiente:create trigger DIS_empleadosclientes_insertar on vista_empleados_clientes instead of insert as insert into empleados select documento,nombre,domicilio from inserted where condicion=empleado insert into clientes select documento,nombre,domicilio from inserted where condicion=cliente;El disparador anterior especifica que cada vez que se ingresen registros en la vista"vista_empleados_clientes", en vez de (instead of) realizar la acción (insertar en la vista), seejecuten las sentencias del trigger, es decir, se ingresen los registros en las tablascorrespondientes.Entonces, las opciones de disparo pueden ser:a) "after": el trigger se dispara cuando las acciones especificadas (insert, delete y/o update) sonejecutadas; todas las acciones en cascada de una restricción "foreign key" y las comprobacionesde restricciones "check" deben realizarse con éxito antes de ejecutarse el trigger. Es la opción pordefecto si solamente colocamos "for" (equivalente a "after").La sintaxis es:create triggre NOMBREDISPARADOR on NOMBRETABLA after | for-- son equivalentes ACCION-- insert, update o deleteas SENTENCIAS
    • b) "instead of": sobreescribe la acción desencadenadora del trigger. Se puede definir solamente undisparador de este tipo para cada acción (insert, delete o update) sobre una tabla o vista.Sintaxis:create triggre NOMBREDISPARADOR on NOMBRETABLA o VISTA instead of ACCION-- insert, update o deleteas SENTENCIASConsideraciones:- Se pueden crear disparadores "instead of" en vistas y tablas.- No se puede crear un disparador "instead of" en vistas definidas "with check option".- No se puede crear un disparador "instead of delete" y "instead of update" sobre tablas que tenganuna "foreign key" que especifique una acción "on delete cascade" y "on update cascade"respectivamente.- Los disparadores "after" no pueden definirse sobre vistas.- No pueden crearse disparadores "after" en vistas ni en tablas temporales; pero puedenreferenciar vistas y tablas temporales.- Si existen restricciones en la tabla del disparador, se comprueban DESPUES de la ejecución deldisparador "instead of" y ANTES del disparador "after". Si se infringen las restricciones, serevierten las acciones del disparador "instead of"; en el caso del disparador "after", no se ejecuta.147 - Disparador (eliminar)DETALLE DE CONCEPTOLos triggers se eliminan con la instrucción "drop trigger":drop trigger NOMBREDISPARADOR;Si el disparador que se intenta eliminar no existe, aparece un mensaje indicándolo, para evitarlo,podemos verificar su existencia antes de solicitar su eliminación (como con cualquier otro objeto):if object_id(NOMBREDISPARADOR) is not null drop trigger NOMBREDISPARADOR;Eliminamos, si existe, el trigger "dis_libros_insertar":if object_id(dis_libros_insertar) is not null
    • drop trigger dis_libros_insertar;Cuando se elimina una tabla o vista que tiene asociados triggers, todos los triggers asociados seeliminan automáticamente.148 - Disparador (información)DETALLE DE CONCEPTOLos triggers (disparadores) son objetos, así que para obtener información de ellos pueden usarselos siguientes procedimientos almacenados del sistema y las siguientes tablas:- "sp_help": sin parámetros nos muestra todos los objetos de la base de datos seleccionada,incluidos los triggers. En la columna "Object_type" aparece "trigger" si es un disparador.Si le enviamos como argumento el nombre de un disparador, obtenemos el propietario, el tipo deobjeto y la fecha de creación.- "sp_helptext": seguido del nombre de un disparador nos muestra el texto que define el trigger,excepto si ha sido encriptado.- "sp_depends": retorna 2 resultados:1) el nombre, tipo, campos, etc. de los objetos de los cuales depende el objeto enviado(referenciados por el objeto) y2) nombre y tipo de los objetos que dependen del objeto nombrado (que lo referencian).Por ejemplo, ejecutamos "sp_depends" seguido del nombre de un disparador:sp_depends dis_inscriptos_insertar;Aparece una tabla similar a la siguiente:name type updated column-----------------------------------------------------------------dbo.condicionales user table yes codigocursodbo.condicionales user table yes fechadbo.inscriptos user table yes numerocursodbo.inscriptos user table yes fechadbo.condicionales user table yes documentodbo.cursos user table no numerodbo.cursos user table no cantidadmaximadbo.inscriptos user table yes documentoEn la columna "name" nos muestra las tablas (y demás objetos si hubiese) de las cuales dependeel trigger, es decir, las tablas referenciadas en el mismo; el tipo de objeto en la columna "type" (eneste caso, todas tablas); la columna "update" indica si el objeto es actualizado o no (note que la
    • tabla "cursos" no se actualiza, solamente se consulta); la columna "column" muestra el nombre delcampo que se referencia.No aparecen objetos que dependen del trigger porque no existe ningún objeto que lo referencie.También podemos ejecutar el mismo procedimiento seguido del nombre de una tabla:sp_depends inscriptos;aparecen los objetos que dependen de ella (que la referencian). En este ejemplo: 1 solo objeto, sunombre y tipo (trigger). No aparecen objetos de los cuales depende porque la tabla no los tiene.- Para conocer los disparadores que hay en una tabla específica y sus acciones respectivas,podemos ejecutar el procedimiento del sistema "sp_helptrigger" seguido del nombre de la tabla ovista. Por ejemplo:sp_helptrigger inscriptos;Nos muestra la siguiente información:trigger_name trigger_owner isupdate isdelete isinsert isafter isinsteadof------------------------------------------------------------------------------------------------------------dis_inscriptos_insertar dbo 0 0 1 0 1El nombre del trigger, su propietario; en las 3 columnas siguientes indica para qué evento se hadefinido (un valor 1 indica que está definido para tal evento); las 2 últimas columnas indican elmomento de disparo (un valor 1 se interpreta como verdadero y un 0 como falso). En el ejemplo, eldisparador "dis_inscriptos_insertar" está definido para el evento de inserción (valor 1 en "isinsert") yes "instead of" (valor 1 en "isinsteadof").- La tabla del sistema "sysobjects": muestra nombre y varios datos de todos los objetos de la basede datos actual. La columna "xtype" indica el tipo de objeto. Si es un trigger muestra "TR".Si queremos ver el nombre, tipo y fecha de creación de todos los disparadores, podemos tipear:select name,xtype as tipo,crdate as fecha from sysobjects where xtype = TR;149 - Disparador (modificar)DETALLE DE CONCEPTOLos triggers pueden modificarse y eliminarse.Al modificar la definición de un disparador se reemplaza la definición existente del disparador por lanueva definición.La sintaxis general es la siguiente:
    • alter trigger NOMBREDISPARADORNUEVADEFINICION;Asumiendo que hemos creado un disparador llamado "dis_empleados_borrar" que no permitíaeliminar más de 1 registro de la tabla empleados; alteramos el disparador, para que cambia lacantidad de eliminaciones permitidas de 1 a 3:alter trigger dis_empleados_borraron empleadosfor deleteas if (select count(*) from deleted)>3--antes era 1 begin raiserror(No puede borrar mas de 3 empleados,16, 1) rollback transaction end;Se puede cambiar el evento del disparador. Por ejemplo, si creó un disparador para "insert" y luegose modifica el evento por "update", el disparador se ejecutará cada vez que se actualice la tabla.PROBLEMA RESUELTOProblema:Una empresa almacena los datos de sus empleados en una tabla denominada "empleados".Eliminamos la tabla si existe:if object_id(empleados) is not null drop table empleados;Creamos la tabla, con la siguiente estructura:create table empleados( documento char(8) not null, nombre varchar(30) not null, domicilio varchar(30), constraint PK_empleados primary key(documento),);Ingresamos algunos registros:insert into empleados values(22000000,Ana Acosta,Avellaneda 56);insert into empleados values(23000000,Bernardo Bustos,Bulnes 188);insert into empleados values(24000000,Carlos Caseres,Caseros 364);insert into empleados values(25555555,Diana Duarte,Colon 1234);insert into empleados values(26666666,Diana Duarte,Colon 897);insert into empleados values(27777777,Matilda Morales,Colon 542);Creamos un disparador para que no permita eliminar más de un registro a la vez de la tablaempleados:
    • create trigger dis_empleados_borrar on empleados for deleteas if (select count(*) from deleted)>1 begin raiserror(No puede eliminar más de un 1 empleado, 16, 1) rollback transaction end;Eliminamos 1 empleado:delete from empleados where documento =22000000;El trigger se dispara y realiza la eliminación. Podemos verificarlo consultando "empleados".Intentamos eliminar varios empleados:delete from empleados where documento like 2%;El trigger se dispara, muestra un mensaje y deshace la transacción.Alteramos el disparador, para que cambia la cantidad de eliminaciones permitidas de 1 a 3:alter trigger dis_empleados_borraron empleadosfor deleteas if (select count(*) from deleted)>3--antes era 1 begin raiserror(No puede borrar más de 3 empleados,16, 1) rollback transaction end;Intentamos eliminar 5 empleados:delete from empleados where documento like 2%;El trigger se dispara, muestra el nuevo mensaje y deshace la transacción.Eliminamos 3 empleados:delete from empleados where domicilio like Colon%;El trigger se dispara y realiza las eliminaciones solicitadas. Puede verificarse consultando la tabla"empleados".
    • 150 - disparador (deshabilitar y habilitar)DETALLE DE CONCEPTOSe puede deshabilitar o habilitar un disparador específico de una tabla o vista, o todos losdisparadores que tenga definidos.Si se deshabilita un disparador, éste sigue existiendo, pero al ejecutar una instrucción "insert","update" o "delete" en la tabla, no se activa.Sintaxis para deshabilitar o habilitar un disparador:alter table NOMBRETABLA ENABLE | DISABLE trigger NOMBREDISPARADOR;El siguiente ejemplo deshabilita un trigger:alter table empleadosdisable trigger dis_empleados_borrar;Se pueden deshabilitar (o habilitar) varios disparadores en una sola sentencia, separando susnombres con comas. El siguiente ejemplo deshabilitamos dos triggers definidos sobre la tablaempleados:alter table empleadosdisable trigger dis_empleados_actualizar, dis_empleados_insertar;Sintaxis para habilitar (o deshabilitar) todos los disparadores de una tabla específica:alter table NOMBRETABLAENABLE | DISABLE TRIGGER all;La siguiente sentencia habilita todos los triggers de la tabla "empleados":alter table empleadosenable trigger all;PROBLEMA RESUELTOProblema:Una empresa almacena los datos de sus empleados en una tabla denominada "empleados".Eliminamos la tabla si existe:if object_id(empleados) is not null drop table empleados;Creamos la tabla, con la siguiente estructura:create table empleados( documento char(8) not null, nombre varchar(30) not null, domicilio varchar(30),
    • seccion varchar(20), constraint PK_empleados primary key(documento),);Ingresamos algunos registros:insert into empleados values(22222222,Ana Acosta,Bulnes 56,Secretaria);insert into empleados values(23333333,Bernardo Bustos,Bulnes 188,Contaduria);insert into empleados values(24444444,Carlos Caseres,Caseros 364,Sistemas);insert into empleados values(25555555,Diana Duarte,Colon 1234,Sistemas);insert into empleados values(26666666,Diana Duarte,Colon 897,Sistemas);insert into empleados values(27777777,Matilda Morales,Colon 542,Gerencia);Creamos un disparador para que no permita eliminar más de un registro a la vez de la tablaempleados:create trigger dis_empleados_borrar on empleados for deleteas if (select count(*) from deleted)>1 begin raiserror(No puede eliminar más de un 1 empleado, 16, 1) rollback transaction end;Creamos un disparador para que no permita actualizar el campo "documento" de la tabla"empleados":create trigger dis_empleados_actualizar on empleados for updateas if update(documento) begin raiserror(No puede modificar el documento de los empleados, 16, 1) rollback transaction end;Creamos un disparador para que no permita ingresar empleados en la sección "Gerencia":create trigger dis_empleados_insertar on empleados for insertas if (select seccion from inserted)=Gerencia begin raiserror(No puede ingresar empleados en la sección "Gerencia"., 16, 1) rollback transaction
    • end;Intentamos borrar varios empleados:delete from empleados where domicilio like Bulnes%;El trigger se dispara, muestra el mensaje y deshace la transacción.Deshabilitamos el trigger para el evento de eliminación: alter table empleados disable trigger dis_empleados_borrar;Borramos varios empleados:delete from empleados where domicilio like Bulnes%;El trigger no se disparó porque está deshabilitado. Podemos verificar que los registros deeliminaron recuperando los datos de la tabla:select *from empleados;Intentamos modificar un documento:update empleados set documento=23030303 where documento=23333333;El trigger se dispara, muestra el mensaje y deshace la transacción.Intentamos ingresar un nuevo empleado en "Gerencia":insert into empleados values(28888888,Juan Juarez,Jamaica 123,Gerencia);El trigger se dispara, muestra el mensaje y deshace la transacción.Deshabilitamos los disparadores de inserción y actualización definidos sobre "empleados":alter table empleadosdisable trigger dis_empleados_actualizar, dis_empleados_insertar;Ejecutamos la sentencia de actualización del documento:update empleados set documento=20000444 where documento=24444444;El trigger no se dispara porque está deshabilitado, el documento se actualizó. verifiquémoslo:select *from empleados;Ingresar un nuevo empleado en "Gerencia":
    • insert into empleados values(28888888,Juan Juarez,Jamaica 123,Gerencia);El trigger "dis_empleados_insertar" no se dispara porque está deshabilitado, el registro se agregó ala tabla. verifiquémoslo:select *from empleados;Habilitamos todos los triggers de la tabla "empleados":alter table empleadosenable trigger all;Ya no podemos eliminar más de un registro, actualizar un documento ni ingresar un empleado enla sección "Gerencia"; lo intentamos:update empleados set documento=30000000 where documento=28888888;El trigger se dispara (está habilitado), muestra el mensaje y deshace la transacción.151 - Disparador (with encryption)DETALLE DE CONCEPTOHasta el momento hemos aprendido que un trigger se crea sobre una tabla (o vista), especificandoel momento de ejecución (after o instead of), para un evento (inserción, eliminación oactualización).Podemos encriptar los triggers para evitar que sean leídos con "sp_helptext". Para ello debemosagregar al crearlos la opción "with encryption" luego del nombre de la tabla o vista:create triggre NOMBREDISPARADOR on NOMBRETABLAoVISTA with encryption MOMENTODEDISPARO--after o instead of ACCION-- insert, update, delete as SENTENCIASEl siguiente disparador se crea encriptado:create trigger DIS_empleados_insertar on empleados with encryption after insertas if (select seccion from inserted)=Gerencia begin
    • raiserror(No puede ingresar empleados en la sección "Gerencia"., 16, 1) rollback transaction end;Si ejecutamos el procedimiento almacenado del sistema "sp_helptext" seguido del nombre deltrigger creado anteriormente, SQL Server mostrará un mensaje indicando que tal disparador hasido encriptado.PROBLEMA RESUELTOProblema:Una empresa almacena los datos de sus empleados en una tabla denominada "empleados".Eliminamos la tabla si existe:if object_id(empleados) is not null drop table empleados;Creamos la tabla, con la siguiente estructura:create table empleados( documento char(8) not null, nombre varchar(30) not null, domicilio varchar(30), seccion varchar(20), constraint PK_empleados primary key(documento),);Creamos el siguiente disparador encriptado:create trigger DIS_empleados_insertar on empleados with encryption after insertas if (select seccion from inserted)=Gerencia begin raiserror(No puede ingresar empleados en la sección "Gerencia"., 16, 1) rollback transaction end;Ejecutamos el procedimiento almacenado del sistema "sp_helptext" seguido del nombre del triggercreado anteriormente:sp_helptext dis_empleados_insertar;SQL Server muestra un mensaje indicando que tal disparador ha sido encriptado.Modificamos el disparador para quitar la encriptación:alter trigger dis_empleados_insertar
    • on empleadosafter insertasif (select seccion from inserted)=Gerenciabegin raiserror(No puede ingresar empleados en la sección "Gerencia"., 16, 1) rollback transactionend;Ejecutamos el procedimiento almacenado del sistema "sp_helptext" seguido del nombre del trigger:sp_helptext dis_empleados_insertar;SQL Server nos permite ver la definición del trigger porque ya no está encriptado.152 - Disparador (condicionales)DETALLE DE CONCEPTOUna instrucción "insert", "update" o "delete" que invoque a un disparador puede afectar a variosregistros. En tales casos, un trigger rechaza o acepta cada transacción de modificación como unatotalidad. Podemos optar por:1) procesar todos los registros: todos los registros afectados deberán cumplir los criterios deldisparador para que se produzca la acción, o2) permitir acciones condicionales: puede definir un disparador que controle si cada registroafectado cumple con la condición; si algún registro no la cumple, la acción no se produce para talregistro pero si para los demás que si la cumplen.Veamos un ejemplo. Tenemos la tabla "libros". Creamos un disparador de actualización sobre latabla "libros". Se permite actualizar el stock de varios libros a la vez; pero ningún "stock" debe tenerun valor negativo. Entonces, si algún "stock" queda con un valor negativo, no debe cambiar, losdemás si:create trigger dis_libros_actualizaron librosafter updateas if exists (select *from inserted where stock<0) begin update libros set stock=deleted.stock from libros join deleted on deleted.codigo=libros.codigo join inserted on inserted.codigo=libros.codigo where inserted.stock<0;
    • end;No podemos revertir la transacción con "rollback transaction" porque en ese caso TODOS losregistros modificados volverían a los valores anteriores, y lo que necesitamos es que solamenteaquellos que quedaron con valor negativo vuelvan a su valor original.Tampoco podemos evitar que se actualicen todos los registros porque se actualizan antes que lasacciones del trigger se ejecuten.Lo que hacemos es, en el cuerpo del trigger, averiguar si alguno de los registros actualizados tienestock negativo; si es así, volvemos a actualizarlo al valor anterior a la transacción.