SQL Server
SQL Server
SQL Server
La única herramienta que necesitamos inicialmente es este sitio ya que podrá ejecutar todos los
problemas como son la creación de tablas, insert, delete, update, definición de índices y
restricciones, creación y ejecución de procedimientos almacenados, vistas, subconsultas,
creación de trigger etc.
La única restricción es que todos los visitantes de este sitio comparten la misma base de datos
llamada: wi520641_sqlserverya (este nombre un poco singular se debe a que las empresas de
hosting es la que lo define)
Una tabla es una estructura de datos que organiza los datos en columnas y filas; cada columna es
un campo (o atributo) y cada fila, un registro. La intersección de una columna con una fila,
contiene un dato específico, un solo valor.
Nosotros trabajaremos con la base de datos llamada wi520641_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 el
procedimiento 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
crea el SQL Server para administración interna.
Al crear una tabla debemos resolver qué campos (columnas) tendrá y que tipo de datos
almacenarán cada uno de ellos, es decir, su estructura.
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:
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 de
dato. 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 de 128 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 la
sentencia no se ejecutará. Esto es muy importante ya que cuando haga los ejercicios en este sitio
puede 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 al
nombre de la tabla:
sp_columns usuarios;
Para eliminar una tabla usamos "drop table" junto al nombre de la tabla a eliminar:
Si intentamos eliminar una tabla que no existe, aparece un mensaje de error indicando tal
situación y la sentencia no se ejecuta. Para evitar este mensaje podemos agregar a la instrucción
lo siguiente:
Necesita almacenar los datos de sus amigos en una tabla. Los datos que
guardará serán: apellido,
nombre, domicilio y teléfono.
1- Elimine la tabla "agenda" si existe:
if object_id('agenda') is not null
drop table agenda;
3- Cree una tabla llamada "agenda", debe tener los siguientes campos:
apellido, varchar(30); nombre,
varchar(20); domicilio, varchar (30) y telefono, varchar(11):
create table agenda(
apellido varchar(30),
nombre varchar(20),
domicilio varchar(30),
telefono varchar(11)
);
7- Elimine la tabla.
Segundo problema:
3- Cree una tabla llamada "libros". Debe definirse con los siguientes campos:
titulo, varchar(20);
autor, varchar(30) y editorial, varchar(15).
7- Elimine la tabla.
Ver solución
Al ingresar los datos de cada registro debe tenerse en cuenta la cantidad y el orden de los
campos.
Usamos "insert into", luego el nombre de la tabla, detallamos los nombres de los campos entre
paréntesis y separados por comas y luego de la cláusula "values" colocamos los valores para cada
campo, también entre paréntesis y separados por comas.
Es importante ingresar los valores en el mismo orden en que se nombran los campos:
En el ejemplo anterior se nombra primero el campo "clave" y luego el campo "nombre" por eso,
los valores también se colocan en ese orden.
Si ingresamos los datos en un orden distinto al orden en que se nombraron los campos, no
aparece 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,
el valor de la clave (la cadena "Boca") se guardará en el campo "nombre" y el valor del nombre
(la cadena "Luis") en el campo "clave":
2- Cree una tabla llamada "agenda". Debe tener los siguientes campos: apellido
(cadena de 30),
nombre (cadena de 20), domicilio (cadena de 30) y telefono (cadena de 11):
Segundo problema:
Trabaje con la tabla "libros" que almacena los datos de los libros de su
propia biblioteca.
1- Elimine la tabla "libros", si existe:
if object_id('libros') is not null
drop table libros;
2- Cree una tabla llamada "libros". Debe definirse con los siguientes campos:
titulo (cadena de 20),
autor (cadena de 30) y editorial (cadena de 15).
Ver solución
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 adecuado para
cada uno de ellos.
Por ejemplo, si en un campo almacenaremos números enteros, el tipo "float" sería una mala
elección; si vamos a guardar precios, el tipo "float" es más adecuado, no así "integer" que no
tiene decimales. Otro ejemplo, si en un campo vamos a guardar un número telefónico o un
número de documento, usamos "varchar", no "integer" porque si bien son dígitos, con ellos no
realizamos operaciones matemáticas.
4 - Tipos de datos básicos
Primer problema:
Segundo problema:
Una empresa almacena los datos de sus empleados en una tabla "empleados" que
guarda los siguientes
datos: nombre, documento, sexo, domicilio, sueldobasico.
Ver solución
5 - Recuperar algunos campos (select)
Hemos aprendido cómo ver todos los registros de una tabla, empleando la instrucción "select".
Podemos especificar el nombre de los campos que queremos ver separándolos por comas:
La lista de campos luego del "select" selecciona los datos correspondientes a los campos
nombrados. 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 dicha lista los nombres de los campos se separan con comas.
2- Cree la tabla:
create table peliculas(
titulo varchar(20),
actor varchar(20),
duracion integer,
cantidad integer
);
Segundo problema:
Una empresa almacena los datos de sus empleados en una tabla llamada
"empleados".
2- Cree la tabla:
create table empleados(
nombre varchar(20),
documento varchar(8),
sexo varchar(1),
domicilio varchar(30),
sueldobasico float
);
Ver solución
Existe una cláusula, "where" con la cual podemos especificar condiciones para una consulta
"select". Es decir, podemos recuperar algunos registros, sólo los que cumplan con ciertas
condiciones indicadas con la cláusula "where". Por ejemplo, queremos ver el usuario cuyo
nombre es "Marcelo", para ello utilizamos "where" y luego de ella, la condición:
Para las condiciones se utilizan operadores relacionales (tema que trataremos más adelante en
detalle). El signo igual(=) es un operador relacional.
Para la siguiente selección de registros especificamos una condición que solicita los usuarios
cuya clave es igual a "River":
select nombre,clave
from usuarios
where clave='River';
Si ningún registro cumple la condición establecida con el "where", no aparecerá ningún registro.
Entonces, con "where" establecemos condiciones para recuperar algunos registros.
select nombre
from usuarios
where clave='River';
En la consulta anterior solicitamos el nombre de todos los usuarios cuya clave sea igual a
"River".
Trabaje con la tabla "agenda" en la que registra los datos de sus amigos.
2- Cree la tabla, con los siguientes campos: apellido (cadena de 30), nombre
(cadena de 20),
domicilio (cadena de 30) y telefono (cadena de 11).
Segundo problema:
Trabaje con la tabla "libros" de una librería que guarda información referente
a sus libros
disponibles para la venta.
7- Seleccione los nombres de las editoriales de los libros cuyo titulo sea
"Martin Fierro" (2
registros)
Ver solución
7 - Operadores relacionales
Los operadores son símbolos que permiten realizar operaciones matemáticas, concatenar
cadenas, hacer comparaciones.
1. relacionales (o de comparación)
2. aritméticos
3. de concatenación
4. lógicos.
Los operadores relacionales (o de comparación) nos permiten comparar dos expresiones, que
pueden ser variables, valores de campos, etc.
Hemos aprendido a especificar condiciones de igualdad para seleccionar registros de una tabla;
por ejemplo:
Los operadores relacionales vinculan un campo con un valor para que SQL Server compare cada
registro (el campo especificado) con el valor dado.
= igual
<> distinto
> mayor
< menor
>= mayor o igual
<= menor o igual
Podemos seleccionar los registros cuyo autor sea diferente de "Borges", para ello usamos la
condición:
Podemos comparar valores numéricos. Por ejemplo, queremos mostrar los títulos y precios de los
libros 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:
Los operadores relacionales comparan valores del mismo tipo. Se emplean para comprobar si un
campo cumple con una condición.
7 - Operadores relacionales
Primer problema:
6- Seleccione los artículos cuyo precio sea mayor o igual a 400 (3 registros)
7- Seleccione el código y nombre de los artículos cuya cantidad sea menor a 30
(2 registros)
Segundo problema:
5- Seleccione el título de todas las películas en las que el actor NO sea "Tom
Cruise" (2
registros)
6- Muestre todos los campos, excepto "duracion", de todas las películas de las
que haya más de 2
copias (2 registros)
Ver solución
Si no queremos eliminar todos los registros, sino solamente algunos, debemos indicar cuál o
cuáles, para ello utilizamos el comando "delete" junto con la clausula "where" con la cual
establecemos la condición que deben cumplir los registros a borrar.
Por ejemplo, queremos eliminar aquel registro cuyo nombre de usuario es "Marcelo":
Si solicitamos el borrado de un registro que no existe, es decir, ningún registro cumple con la
condición especificada, ningún registro será eliminado.
Tenga en cuenta que si no colocamos una condición, se eliminan todos los registros de la tabla
nombrada.
2- Cree la tabla con los siguientes campos: apellido (cadena de 30), nombre
(cadena de 20),
domicilio (cadena de 30) y telefono (cadena de 11):
create table agenda(
apellido varchar(30),
nombre varchar(20),
domicilio varchar(30),
telefono varchar(11)
);
6- Muestre la tabla.
8- Muestre la tabla.
Ver solución
Segundo problema:
5- Elimine los artículos cuyo precio sea mayor o igual a 500 (2 registros)
delete from articulos
where precio>=500;
Ver solución
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":
Utilizamos "update" junto al nombre de la tabla y "set" junto con el campo a modificar y su
nuevo valor.
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" que
afecte solamente a este registro:
Si Microsoft SQL Server no encuentra registros que cumplan con la condición del "where", no se
modifica ninguno.
Para ello colocamos "update", el nombre de la tabla, "set" junto al nombre del campo y el nuevo
valor y separado por coma, el otro nombre del campo con su nuevo valor.
Trabaje con la tabla "agenda" que almacena los datos de sus amigos.
4- Modifique el registro cuyo nombre sea "Juan" por "Juan Jose" (1 registro
afectado)
5- Actualice los registros cuyo número telefónico sea igual a "4545454" por
"4445566"
(2 registros afectados)
6- Actualice los registros que tengan en el campo "nombre" el valor "Juan" por
"Juan Jose" (ningún
registro afectado porque ninguno cumple con la condición del "where")
Segundo problema:
5- Modifique los registros cuyo autor sea igual a "Paenza", por "Adrian
Paenza" (1 registro
afectado)
update libros set autor='Adrian Paenza'
where autor='Paenza';
6- Nuevamente, modifique los registros cuyo autor sea igual a "Paenza", por
"Adrian Paenza" (ningún
registro afectado porque ninguno cumple la condición)
update libros set autor='Adrian Paenza'
where autor='Paenza';
8- Actualice el valor del campo "editorial" por "Emece S.A.", para todos los
registros cuya
editorial sea igual a "Emece" (3 registros afectados):
update libros set editorial='Emece S.A.'
where editorial='Emece';
Ver solución
10 - Comentarios
Para 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:
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 (/*) al
comienzo del bloque de comentario y al finalizarlo, un asterisco seguido de una barra (*/).
Por ejemplo, en nuestra tabla de libros, podemos tener valores nulos en el campo "precio" porque
es posible que para algunos libros no le hayamos establecido el precio para la venta.
Veamos un ejemplo. Tenemos nuestra tabla "libros". El campo "titulo" no debería estar vacío
nunca, igualmente el campo "autor". Para ello, al crear la tabla, debemos especificar que dichos
campos 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 la
definició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:
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 el
valor.
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:
Para ver cuáles campos admiten valores nulos y cuáles no, podemos emplear el procedimiento
almacenado "sp_columns" junto al nombre de la tabla. Nos muestra mucha información, en la
columna "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
los operadores relacionales vistos anteriormente: = (igual) y <> (distinto); debemos utilizar los
operadores "is null" (es igual a null) y "is not null" (no es null):
Con la primera sentencia veremos los libros cuyo precio es igual a "null" (desconocido); con la
segunda, los libros cuyo precio es 0.
Igualmente para campos de tipo cadena, las siguientes sentencias "select" no retornan los mismos
registros:
Con la primera sentencia veremos los libros cuya editorial es igual a "null", con la segunda, los
libros cuya editorial guarda una cadena vacía.
Entonces, para que un campo no permita valores nulos debemos especificarlo luego de definir el
campo, agregando "not null". Por defecto, los campos permiten valores nulos, pero podemos
especificarlo igualmente agregando "null".
Primer problema:
4- Ingrese algunos registros con valores "null" para los campos que lo
admitan:
insert into medicamentos (codigo,nombre,laboratorio,precio,cantidad)
values(1,'Sertal gotas',null,null,100);
insert into medicamentos (codigo,nombre,laboratorio,precio,cantidad)
values(2,'Sertal compuesto',null,8.90,150);
insert into medicamentos (codigo,nombre,laboratorio,precio,cantidad)
values(3,'Buscapina','Roche',null,200);
6- Ingrese un registro con valor "0" para el precio y cadena vacía para el
laboratorio:
insert into medicamentos (codigo,nombre, laboratorio,precio,cantidad)
values(4,'Bayaspirina','',0,150);
7- Ingrese un registro con valor "0" para el código y cantidad y cadena vacía
para el nombre:
insert into medicamentos (codigo,nombre,laboratorio,precio,cantidad)
values(0,'','Bayer',15.60,0);
9- Intente ingresar un registro con valor nulo para un campo que no lo admite
(aparece un mensaje de
error):
insert into medicamentos (codigo,nombre,laboratorio,precio,cantidad)
values(null,'Amoxidal jarabe','Bayer',25,120);
11- Recupere los registros que contengan valor "null" en el campo "precio",
luego los que tengan el
valor 0 en el mismo campo. Note que el resultado es distinto.
12- Recupere los registros cuyo laboratorio no contenga una cadena vacía,
luego los que sean
distintos de "null".
Note que la salida de la primera sentencia no muestra los registros con
cadenas vacías y tampoco los
que tienen valor nulo; el resultado de la segunda sentencia muestra los
registros con valor para el
campo laboratorio (incluso cadena vacía).
13- Recupere los registros cuyo precio sea distinto de 0, luego los que sean
distintos de "null":
Note que la salida de la primera sentencia no muestra los registros con valor
0 y tampoco los que
tienen valor nulo; el resultado de la segunda sentencia muestra los registros
con valor para el
campo precio (incluso el valor 0).
Ver solución
Segundo problema:
Trabaje con la tabla que almacena los datos sobre películas, llamada
"peliculas".
1- Elimine la tabla si existe:
if object_id('peliculas') is not null
drop table peliculas;
5- Recupere todos los registros para ver cómo SQL Server los almacenó:
select *from peliculas;
6- Intente ingresar un registro con valor nulo para campos que no lo admiten
(aparece un mensaje de
error):
insert into peliculas (codigo,titulo,actor,duracion)
values(null,'Mujer bonita','R. Gere-J. Roberts',190);
7- Muestre los registros con valor nulo en el campo "actor" y luego los que
guardan una cadena vacía
(note que la salida es distinta) (1 registro)
8- Modifique los registros que tengan valor de duración desconocido (nulo) por
"120" (1 registro
actualizado)
10- Muestre todos los registros. Note que el cambio anterior no afectó a los
registros con valor
nulo en el campo "actor".
11- Elimine los registros cuyo título sea una cadena vacía (1 registro)
Ver solución
12 - Clave primaria
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 puede
establecerse como clave primaria, es un valor que no se repite; puede haber personas con igual
apellido 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 clave
primaria, es un valor que no se repite; puede haber usuarios con igual clave, pero su nombre de
usuario será siempre diferente.
Podemos establecer que un campo sea clave primaria al momento de crear la tabla o luego que
ha sido creada. Vamos a aprender a establecerla al crear la tabla. Hay 2 maneras de hacerlo, por
ahora 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:
En el siguiente ejemplo definimos una clave primaria, para nuestra tabla "usuarios" para
asegurarnos que cada usuario tendrá un nombre diferente y único:
Lo que hacemos agregar luego de la definición de cada campo, "primary key" y entre paréntesis,
el nombre del campo que será clave primaria.
Una tabla sólo puede tener una clave primaria. Cualquier campo (de cualquier tipo) puede ser
clave 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 Server
controla que los valores para el campo establecido como clave primaria no estén repetidos en la
tabla; si estuviesen repetidos, muestra un mensaje y la inserción no se realiza. Es decir, si en
nuestra tabla "usuarios" ya existe un usuario con nombre "juanperez" e intentamos ingresar un
nuevo 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 campo
establecido como clave primaria no estén repetidos en la tabla, si lo estuviese, aparece un
mensaje indicando que se viola la clave primaria y la actualización no se realiza.
12 - Clave primaria
Primer problema:
Segundo problema:
Ver solución
Para que un campo pueda establecerse como "identity", éste debe ser entero (también puede ser
de 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:
Cuando un campo tiene el atributo "identity" no se puede ingresar valor para él, porque se inserta
automáticamente tomando el último valor como referencia, o 1 si es el primero.
Para ingresar registros omitimos el campo definido como "identity", por ejemplo:
Los valores secuenciales de un campo "identity" se generan tomando como referencia el último
valor ingresado; si se elimina el último registro ingresado (por ejemplo 3) y luego se inserta otro
registro, SQL Server seguirá la secuencia, es decir, colocará el valor "4".
5- Verifique que SQL Server generó valores para el campo "código" de modo
automático:
select *from medicamentos;
10- Seleccione todos los registros para ver qué valor guardó SQL Server en el
campo código:
select *from medicamentos;
Ver solución
Segundo problema:
9- Visualice los registros para ver el valor almacenado en codigo (valor 7):
select *from peliculas;
Ver solución
La función "ident_seed()" retorna el valor de inicio del campo "identity" de la tabla que
nombramos:
select ident_seed('libros');
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":
Cuando "identity_insert" está en ON, las instrucciones "insert" deben explicitar un valor:
El atributo "identity" no implica unicidad, es decir, permite repetición de valores; por ello hay
que tener cuidado al explicitar un valor porque se puede ingresar un valor repetido.
7- Ingrese un nuevo registro sin valor para el campo "codigo" (no lo permite):
insert into medicamentos (nombre, laboratorio,precio,cantidad)
values('Amoxilina 500','Bayer',15.60,100);
Segundo problema:
12- Ingrese un nuevo registro y muestre todos los registros para ver cómo SQL
Server siguió la
secuencia tomando el último valor del campo como referencia.
Ver solución
15 - Truncate table
Aprendimos 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:
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 nota
cuando 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 los
registros 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 del campo de identidad vuelve a iniciarse en 1.
Por ejemplo, tenemos la tabla "libros" con el campo "codigo" definido "identity", y el valor más
alto de 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", al ingresar un nuevo registro el valor del código se iniciará en 1 nuevamente.
15 - Truncate table
Primer problema:
7- Ingrese los siguientes registros y muestre todos los registros para ver que
SQL Server reinició
la secuencia del campo "identity":
insert into alumnos (documento,nombre,domicilio)
values('22345345','Perez Mariana','Colon 234');
insert into alumnos (documento,nombre,domicilio)
values('23545345','Morales Marcos','Avellaneda 348');
insert into alumnos (documento,nombre,domicilio)
values('24356345','Gonzalez Analia','Caseros 444');
insert into alumnos (documento,nombre,domicilio)
values('25666777','Torres Ramiro','Dinamarca 209');
select *from alumnos;
Ver solución
Segundo problema:
Un comercio que vende artículos de computación registra los datos de sus
artículos en una tabla con
ese nombre.
1- Elimine "articulos", si existe:
if object_id('articulos') is not null
drop table articulos;
Ver solución
Hasta ahora hemos visto 3 tipos de datos: varchar, integer y float. Hay más tipos, incluso,
subtipos.
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.
Entonces, cuando creamos una tabla y definir sus campos debemos elegir el tipo de dato más
preciso. Por ejemplo, si necesitamos almacenar nombres usamos texto; si un campo numérico
almacenará 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".
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.
Por ejemplo, si en un campo definido como varchar(5) ingresamos el valor 12345, lo toma como
si hubiésemos tipeado '12345', igualmente, si ingresamos el valor 23.56, lo convierte a '23.56'. Si
el valor numérico, al ser convertido a cadena supera la longitud definida, aparece un mensaje de
error y la sentencia no se ejecuta.
Para almacenar cadenas que varían en su longitud, es decir, no todos los registros tendrán la
misma 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 apellidos
tienen la misma longitud.
Para almacenar cadenas que no varían en su longitud, es decir, todos los registros tendrán la
misma longitud en un campo determinado, se emplea "char".
Por ejemplo, definimos un campo "codigo" que constará de 5 caracteres, todos los registros
tendrán un código de 5 caracteres, ni más ni menos.
nvarchar(x) 0 a 8K
nchar(x) 0 a 8K
ntext 0 a 2GB
Una concesionaria de autos vende autos usados y almacena los datos de los
autos en una tabla llamada
"autos".
1- Elimine la tabla "autos" si existe:
if object_id('autos') is not null
drop table autos;
Segundo problema:
Una empresa almacena los datos de sus clientes en una tabla llamada
"clientes".
1- Elimine la tabla "clientes" si existe:
if object_id('clientes') is not null
drop table clientes;
Ver solución
Para almacenar valores ENTEROS, por ejemplo, en campos que hacen referencia a cantidades,
usamos:
Para almacenar valores numéricos EXACTOS con decimales, especificando la cantidad de cifras
a la izquierda y derecha del separador decimal, utilizamos:
2) decimal o numeric (t,d): Pueden tener hasta 38 digitos, guarda un valor exacto. El primer
argumento 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
como tipo "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.
Si ingresamos un valor con más decimales que los permitidos, redondea al más cercano; por
ejemplo, si definimos "decimal(4,2)" e ingresamos el valor "12.686", guardará "12.69",
redondeando hacia arriba; si ingresamos el valor "12.682", guardará "12.67", redondeando hacia
abajo.
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.
Es importante elegir el tipo de dato adecuado según el caso, el más preciso. Por ejemplo, si un
campo 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" en
lugar de "money".
decimal 2 a 17
float 4 u 8
real 4 u 8
money 8
smallmoney 4
18 - Tipo de dato (numérico)
Primer problema:
Un banco tiene registrados las cuentas corrientes de sus clientes en una tabla
llamada "cuentas".
La tabla contiene estos datos:
Número de Cuenta Documento Nombre Saldo
______________________________________________________________
1234 25666777 Pedro Perez 500000.60
2234 27888999 Juan Lopez -250000
3344 27888999 Juan Lopez 4000.50
3346 32111222 Susana Molina 1000
2- Cree la tabla eligiendo el tipo de dato adecuado para almacenar los datos
descriptos arriba:
4- Seleccione todos los registros cuyo saldo sea mayor a "4000" (2 registros)
Segundo problema:
Una empresa almacena los datos de sus empleados en una tabla "empleados" que
guarda los siguientes
datos: nombre, documento, sexo, domicilio, sueldobasico.
1- Elimine la tabla, si existe:
if object_id('empleados') is not null
drop table empleados;
6- Muestre todos los empleados cuyo sueldo no supere los 900 pesos (1
registro):
Ver solución
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.
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 orden
de las partes de una fecha (dia, mes y año) empleamos "set dateformat". Estos son los formatos:
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, si
ingresamos '10:15', mostrará '1900-01-01 10:15.000'.
Una facultad almacena los datos de sus alumnos en una tabla denominada
"alumnos".
1- Elimine la tabla, si existe:
if object_id('alumnos') is not null
drop table alumnos;
3- Setee el formato para entrada de datos de tipo fecha para que acepte
valores "día-mes-año":
set dateformat 'dmy';
5- Ingrese otro alumno empleando solamente un dígito para día y mes y 2 para
el año:
insert into alumnos values('Juarez','Bernardo','25555555','Sucre 456','03-03-
1991','15/02/1972');
11- Setee el formato de entrada de fechas para que acepte valores "mes-dia-
año".
20 - Ingresar algunos campos (insert into)
Hemos aprendido a ingresar registros listando todos los campos y colocando valores para todos y
cada 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:
También es posible ingresar valores para algunos campos. Ingresamos valores solamente para los
campos "titulo" y "autor":
SQL Server almacenará el valor "null" en el campo "editorial", para el cual no hemos explicitado
un valor.
- 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 de
error 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, que
permitan valores nulos (se guardará "null"); si omitimos el valor para un campo "not null", la
sentencia 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
valor por defecto con la cláusula "default" (tema que veremos a continuación).
2- Cree la tabla :
create table cuentas(
numero int identity,
documento char(8) not null,
nombre varchar(30),
saldo money
);
3- Ingrese un registro con valores para todos sus campos, inclusive el campo
identity, omitiendo la
lista de campos (error, no se debe ingresar para el campo identity):
insert into cuentas
values (1,'25666777','Juan Perez',2500.50);
4- Ingrese un registro con valores para todos sus campos omitiendo la lista de
campos (excepto el
campo "identity"):
insert into cuentas
values ('25666777','Juan Perez',2500.50);
Un valor por defecto se inserta cuando no está presente al ingresar un registro y en algunos casos
en que el dato ingresado es inválido.
Para campos de cualquier tipo no declarados "not null", es decir, que admiten valores nulos, el
valor por defecto es "null". Para campos declarados "not null", no existe valor por defecto, a
menos que se declare explícitamente con la cláusula "default".
Para todos los tipos, excepto los declarados "identity", se pueden explicitar valores por defecto
con la cláusula "default".
Podemos establecer valores por defecto para los campos cuando creamos la tabla. Para ello
utilizamos "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":
Si al ingresar un nuevo registro omitimos los valores para el campo "autor" y "cantidad", Sql
Server insertará 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á el
valor por defecto.
Ahora, al visualizar la estructura de la tabla con "sp_columns" podemos entender lo que informa
la columna "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:
Si todos los campos de una tabla tienen valores predeterminados (ya sea por ser "identity",
permitir valores nulos o tener un valor por defecto), se puede ingresar un registro de la siguiente
manera:
La sentencia anterior almacenará un registro con los valores predetermiandos para cada uno de
sus campos.
Los campos para los cuales no se ingresan valores en un "insert" tomarán los valores por defecto:
- 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 para
la 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 con
valores por defecto. Que un campo tenga valor por defecto no significa que no admita valores
nulos, puede o no admitirlos.
Un comercio que tiene un stand en una feria registra en una tabla llamada
"visitantes" algunos datos
de las personas que visitan o compran en su stand para luego enviarle
publicidad de sus productos.
1- Elimine la tabla "visitantes", si existe:
if object_id('visitantes') is not null
drop table visitantes;
5- Ingrese algunos registros sin especificar valores para algunos campos para
ver cómo opera la
cláusula "default":
insert into visitantes (nombre, domicilio, montocompra)
values ('Susana Molina','Colon 123',59.80);
insert into visitantes (nombre, edad, ciudad, mail)
values ('Marcos Torres',29,'Carlos Paz','[email protected]');
select *from visitantes;
Segundo problema:
Una pequeña biblioteca de barrio registra los préstamos de sus libros en una
tabla llamada
"prestamos". En ella almacena la siguiente información: título del libro,
documento de identidad del
socio a quien se le presta el libro, fecha de préstamo, fecha en que tiene que
devolver el libro y
si el libro ha sido o no devuelto.
1- Elimine la tabla "prestamos" si existe:
if object_id('prestamos') is not null
drop table prestamos;
2- Cree la tabla:
create table prestamos(
titulo varchar(40) not null,
documento char(8) not null,
fechaprestamo datetime not null,
fechadevolucion datetime,
devuelto char(1) default 'n'
);
Ver solución
Es posible obtener salidas en las cuales una columna sea el resultado de un cálculo y no un
campo de 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 la
cantidad por cada título, pero también podemos hacer que SQL Server realice el cálculo y lo
incluya en una columna extra en la salida:
Si queremos saber el precio de cada libro con un 10% de descuento podemos incluir en la
sentencia los siguientes cálculos:
select titulo,precio,
precio-(precio*0.1)
from libros;
También podemos actualizar los datos empleando operadores aritméticos:
select 5/0;
select titulo+'-'+autor+'-'+editorial
from libros;
Note que concatenamos además unos guiones para separar los campos.
2- Cree la tabla:
create table articulos(
codigo int identity,
nombre varchar(20),
descripcion varchar(30),
precio smallmoney,
cantidad tinyint default 0,
primary key (codigo)
);
5- Vea el resultado:
select *from articulos;
23 - Alias
Una manera de hacer más comprensible el resultado de una consulta consiste en cambiar los
encabezados de las columnas.
Por ejemplo, tenemos la tabla "agenda" con un campo "nombre" (entre otros) en el cual se
almacena el nombre y apellido de nuestros amigos; queremos que al mostrar la información de
dicha tabla aparezca como encabezado del campo "nombre" el texto "nombre y apellido", para
ello colocamos 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
texto del encabezado.
Si el alias consta de una sola cadena las comillas no son necesarias, pero si contiene más de una
palabra, es necesario colocarla entre comillas simples:
Entonces, un "alias" se usa como nombre de un campo o de una expresión. En estos casos, son
opcionales, sirven para hacer más comprensible el resultado; en otros casos, que veremos más
adelante, son obligatorios.
2- Cree la tabla:
create table articulos(
codigo int identity,
nombre varchar(20),
descripcion varchar(30),
precio smallmoney,
cantidad tinyint default 0,
primary key (codigo)
);
5- Vea el resultado:
select *from articulos;
23 - Alias
Una manera de hacer más comprensible el resultado de una consulta consiste en cambiar los
encabezados de las columnas.
Por ejemplo, tenemos la tabla "agenda" con un campo "nombre" (entre otros) en el cual se
almacena el nombre y apellido de nuestros amigos; queremos que al mostrar la información de
dicha tabla aparezca como encabezado del campo "nombre" el texto "nombre y apellido", para
ello colocamos un alias de la siguiente manera:
Para reemplazar el nombre de un campo por otro, se coloca la palabra clave "as" seguido del
texto del encabezado.
Si el alias consta de una sola cadena las comillas no son necesarias, pero si contiene más de una
palabra, es necesario colocarla entre comillas simples:
Entonces, un "alias" se usa como nombre de un campo o de una expresión. En estos casos, son
opcionales, sirven para hacer más comprensible el resultado; en otros casos, que veremos más
adelante, son obligatorios.
23 - Alias
Primer problema:
2- Cree la tabla:
create table libros(
codigo int identity,
titulo varchar(40) not null,
autor varchar(20) default 'Desconocido',
editorial varchar(20),
precio decimal(6,2),
cantidad tinyint default 0,
primary key (codigo)
);
4- Muestre todos los campos de los libros y un campo extra, con el encabezado
"monto total" en la
que calcule el monto total en dinero de cada libro (precio por cantidad)
24 - Funciones
Una 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ámetros
de entrada. Las funciones de SQL Server no pueden ser modificadas, las funciones definidas por
el usuario si.
SQL Server ofrece varios tipos de funciones para realizar distintas operaciones. Se pueden
clasificar 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 siguiente
manera:
select @@version;
- de cadena: operan con valores "char", "varchar", "nchar", "nvarchar", "binary" y "varbinary" y
devuelven un valor de cadena o numérico.
- del sistema: informan sobre opciones, objetos y configuraciones del sistema. Ejemplo:
select user_name();
- texto e imagen: realizan operaciones con valor de entrada de tipo text o image y retornan
información referente al mismo.
retorna "tardes".
select str(123.456,7,3);
select str(-123.456,7,3);
retorna '-123.46';
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 "**".
select stuff('abcde',3,2,'opqrs');
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,
que significa 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".
-ltrim(cadena): retorna la cadena con los espacios de la izquierda eliminados. Trim significa
recortar. Ejemplo:
select replace('xxx.sqlserverya.com','x','w');
retorna "www.sqlserverya.com'.
select reverse('Hola');
retorna "aloH".
retorna 7.
retorna 2.
select patindex('%ar%', 'Jorge Luis Borges');
retorna 0.
retorna 13.
retorna 2.
retorna 0.
retorna 0.
retorna "HolaHolaHola";
- space(cantidad): retorna una cadena de espacios de longitud indicada por "cantidad", que debe
ser un valor positivo. Ejemplo:
Se pueden emplear estas funciones enviando como argumento el nombre de un campo de tipo
caracter.
26 - Funciones matemáticas
Las funciones matemáticas realizan operaciones con expresiones numéricas y retornan un
resultado, operan con tipos de datos numéricos.
Microsoft SQL Server tiene algunas funciones para trabajar con números. Aquí presentamos
algunas.
select abs(-20);
retorna 20.
select ceiling(12.34);
retorna 13.
select floor(12.34);
retorna 12.
select 10%3;
retorna 1.
select 10%2;
retorna 0.
select power(2,3);
retorna 8.
select round(123.456,1);
retorna "123.400", es decir, redondea desde el primer decimal.
select round(123.456,2);
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).
Se pueden emplear estas funciones enviando como argumento el nombre de un campo de tipo
numérico.
select getdate();
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());
select datepart(day,getdate());
select datepart(hour,getdate());
select datename(month,getdate());
select datename(day,getdate());
select dateadd(day,3,'1980/11/02');
select dateadd(month,3,'1980/11/02');
select dateadd(hour,2,'1980/11/02');
select dateadd(minute,16,'1980/11/02');
select datediff(month,'2005/10/28','2006/11/29');
retorna 13 (meses).
select day(getdate());
select month(getdate());
select year(getdate());
Se pueden emplear estas funciones enviando como argumento el nombre de un campo de tipo
datetime o smalldatetime.
Una empresa almacena los datos de sus empleados en una tabla denominada
"empleados".
1- Elimine la tabla si existe:
if object_id ('empleados') is not null
drop table empleados;
2- Cree la tabla:
create table empleados(
nombre varchar(30) not null,
apellido varchar(20) not null,
documento char(8),
fechanacimiento datetime,
fechaingreso datetime,
sueldo decimal(6,2),
primary key(documento)
);
6- Muestre los nombres y apellidos de los empleados que cumplen años en el mes
"october" (3
registros)
Por ejemplo, recuperamos los registros de la tabla "libros" ordenados por el título:
También podemos colocar el número de orden del campo por el que queremos que se ordene en
lugar de su nombre, es decir, referenciar a los campos por su posición en la lista de selección.
Por ejemplo, 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 a
mayor).
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":
Incluso, podemos ordenar en distintos sentidos, por ejemplo, por "titulo" en sentido ascendente y
"editorial" en sentido descendente:
Debe aclararse al lado de cada campo, pues estas palabras claves afectan al campo
inmediatamente anterior.
La cláusula "order by" no puede emplearse para campos text, ntext e image.
28 - Ordenar registros (order by)
Primer problema:
En una página web se guardan los siguientes datos de las visitas: número de
visita, nombre, mail,
pais, fecha.
1- Elimine la tabla "visitas", si existe:
if object_id('visitas') is not null
drop table visitas;
5- Muestre el nombre del usuario, pais y el nombre del mes, ordenado por pais
(ascendente) y nombre
del mes (descendente)
6- Muestre el pais, el mes, el día y la hora y ordene las visitas por nombre
del mes, del día y la
hora.
7- Muestre los mail, país, ordenado por país, de todos los que visitaron la
página en octubre (4
registros)
Ver solución
Los registros recuperados en una sentencia que une 2 condiciones con el operador "and",
cumplen con las 2 condiciones.
Queremos ver los libros cuyo autor sea "Borges" y/o cuya editorial sea "Planeta":
En la sentencia anterior usamos el operador "or"; indicamos que recupere los libros en los cuales
el valor 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 con
ambas condiciones.
Los registros recuperados con una sentencia que une 2 condiciones con el operador "or",
cumplen 1 de las condiciones o ambas.
Queremos recuperar los libros que NO cumplan la condición dada, por ejemplo, aquellos cuya
editorial NO sea "Planeta":
Los registros recuperados en una sentencia en la cual aparece el operador "not", no cumplen con
la 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 las
expresiones más claramente.
select*from libros
where (autor='Borges') or
(editorial='Paidos' and precio<20);
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
ello se recomienda usar los paréntesis.
Entonces, para establecer más de una condición en un "where" es necesario emplear operadores
lógicos. "and" significa "y", indica que se cumplan ambas condiciones; "or" significa "y/o",
indica que se cumpla una u otra condición (o ambas); "not" significa "no", indica que no se
cumpla la condición especificada.
5- Recupere los medicamentos cuyo laboratorio sea 'Roche' o cuyo precio sea
menor a 5 (4 registros):
select * from medicamentos
where laboratorio='Roche' or
precio<5;
Note que el resultado es diferente al del punto 4, hemos cambiado el operador
de la sentencia
anterior.
7- Muestre todos los medicamentos cuyo laboratorio sea "Bayer" y cuya cantidad
NO sea=100 (2 registros):
select * from medicamentos
where laboratorio='Bayer' and
not cantidad=100;
Analice estas 2 últimas sentencias. El operador "not" afecta a la condición a
la cual antecede, no a
las siguientes. Los resultados de los puntos 6 y 7 son diferentes.
9- Cambie la cantidad por 200, a todos los medicamentos de "Roche" cuyo precio
sea mayor a 5 (1
registro afectado)
10- Borre los medicamentos cuyo laboratorio sea "Bayer" o cuyo precio sea
menor a 3 (3 registros
borrados)
Ver solución
Segundo problema:
4- Recupere los registros cuyo actor sea "Tom Cruise" or "Richard Gere" (3
registros)
5- Recupere los registros cuyo actor sea "Tom Cruise" y duración menor a 100
(ninguno cumple ambas
condiciones)
6- Cambie la duración a 200, de las películas cuyo actor sea "Daniel R." y
cuya duración sea 180 (1
registro afectado)
7- Borre todas las películas donde el actor NO sea "Tom Cruise" y cuya
duración sea mayor o igual a
100 (2 registros eliminados)
Ver solución
Se emplea el operador "is null" para recuperar los registros en los cuales esté almacenado el
valor "null" en un campo específico:
Para obtener los registros que no contiene "null", se puede emplear "is not null", esto mostrará
los registros 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ón de los datos.
6- Borre todas las películas donde el actor sea "null" y cuya duración sea 0
(1 registro)
Ver solución
Hasta ahora, para recuperar de la tabla "libros" los libros con precio mayor o igual a 20 y menor
o igual a 40, usamos 2 condiciones unidas por el operador lógico "and":
Averiguamos si el valor de un campo dado (precio) está entre los valores mínimo y máximo
especificados (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 incluyen
los valores mínimo y máximo) y tipos de datos fecha y hora (incluye sólo el valor mínimo).
Siempre que sea posible, emplee condiciones de búsqueda positivas ("between"), evite las
negativas ("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".
En una página web se guardan los siguientes datos de las visitas: número de
visita, nombre, mail,
pais, fechayhora de la visita.
1- Elimine la tabla "visitas", si existe:
if object_id('visitas') is not null
drop table visitas;
Segundo problema:
Una concesionaria de autos vende autos usados y almacena la información en una
tabla llamada
"autos".
1- Elimine la tabla "autos" si existe:
if object_id('autos') is not null
drop table autos;
4- Seleccione todos los autos cuyo modelo se encuentre entre '1970' y '1990'
usando el operador
"between" y ordénelos por dicho campo(4 registros)
5- Seleccione todos los autos cuyo precio esté entre 50000 y 100000.
Ver solución
En la siguiente sentencia usamos "in" para averiguar si el valor del campo autor está incluido en
la lista de valores especificada (en este caso, 2 cadenas).
Hasta ahora, para recuperar los libros cuyo autor sea 'Paenza' o 'Borges' usábamos 2 condiciones:
Para recuperar los libros cuyo autor no sea 'Paenza' ni 'Borges' usábamos:
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 que no se encuentran (coindicen) con la lista de valores.
Recuerde: siempre que sea posible, emplee condiciones de búsqueda positivas ("in"), evite las
negativas ("not in") porque con ellas se evalún todos los registros y esto hace más lenta la
recuperación de los datos.
33 - Búsqueda de patrones (like - not like)
Existe 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. Por
ejemplo, sabemos recuperar los libros cuyo autor sea igual a la cadena "Borges":
El operador igual ("=") nos permite comparar cadenas de caracteres, pero al realizar la
comparación, busca coincidencias de cadenas completas, realiza una búsqueda exacta.
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
cadenas de 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. Para
recuperar todos los registros cuyo autor contenga la cadena "Borges" debemos tipear:
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
no recordamos si se escribe "Carroll" o "Carrolt", entonces tipeamos esta condición:
Para seleccionar los libros cuya editorial comienza con las letras entre la "P" y la "S" usamos la
siguiente sintaxis:
select titulo,autor,editorial
from libros
where editorial like '[P-S]%';
Ejemplos:
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 a caracter. Por ejemplo, queremos buscar todos los libros cuyo precio se encuentre entre
10.00 y 19.99:
Para búsquedas de caracteres comodines como literales, debe incluirlo dentro de corchetes, por
ejemplo, si busca:
Una empresa almacena los datos de sus empleados en una tabla "empleados".
1- Elimine la tabla, si existe:
if object_id('empleados') is not null
drop table empleados;
2- Cree la tabla:
create table empleados(
nombre varchar(30),
documento char(8),
domicilio varchar(30),
fechaingreso datetime,
seccion varchar(20),
sueldo decimal(6,2),
primary key(documento)
);
5- Muestre todos los empleados cuyo domicilio comience con "Co" y tengan un
"8" (2 registros)
8- Recupere todos los nombres que tengan una "y" o una "j" en su nombre o
apellido (3 registros)
10- Muestre los nombres y sección de los empleados que pertenecen a secciones
que NO comiencen con
"S" o "G" (2 registros)
11- Muestre todos los nombres y sueldos de los empleados cuyos sueldos
incluyen centavos (3
registros)
Imaginemos que nuestra tabla "libros" contiene muchos registros. Para averiguar la cantidad sin
necesidad 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 valor
nulo.
También podemos utilizar esta función junto con la cláusula "where" para una consulta más
especí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), usamos
la 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
colocamos como argumento el nombre de un campo, se contabilizan los registros cuyo valor en
ese campo NO es nulo.
"count_big(*)" cuenta la cantidad de registros de una tabla, incluyendo los valores nulos y
duplicados.
select count_big(*)
from libros;
Note que incluye todos los libros aunque tengan valor nulo en algún campo.
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;
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:
La función "sum()" retorna la suma de los valores que contiene el campo especificado. Si
queremos saber la cantidad total de libros que tenemos disponibles para la venta, debemos sumar
todos 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 queremos
el máximo valor.
La función "avg()" retorna el valor promedio de los valores del campo especificado. Queremos
saber el promedio del precio de los libros referentes a "PHP":
select avg(precio)
from libros
where titulo like '%PHP%';
Si realiza una consulta con la función "count" de un campo que contiene 18 registros, 2 de los
cuales contienen valor nulo, el resultado devuelve un total de 16 filas porque no considera
aquellos con 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".
2- Cree la tabla:
create table empleados(
nombre varchar(30),
documento char(8),
domicilio varchar(30),
seccion varchar(20),
sueldo decimal(6,2),
cantidadhijos tinyint,
primary key(documento)
);
6- Muestre el sueldo más alto y el más bajo colocando un alias (5000 y 2000)
8- Muestre el promedio de sueldos de todo los empleados (3400. Note que hay un
sueldo nulo y no es
tenido en cuenta)
9- Muestre el promedio de sueldos de los empleados de la sección "Secretaría"
(2100)
Las funciones de agregado solas producen un valor de resumen para todos los registros de un
campo. Podemos generar valores de resumen para un solo campo, combinando las funciones de
agregado 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:
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 se
realice el agrupamiento, también colocamos el nombre del campo a recuperar; la sintaxis básica
es la siguiente:
También se puede agrupar por más de un campo, en tal caso, luego del "group by" se listan los
campos, separados por comas. Todos los campos que se especifican en la cláusula "group by"
deben estar en la lista de selección.
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 que deseamos que se realice el agrupamiento (editorial):
Como resultado aparecen los nombres de las editoriales y la cantidad de registros de cada una,
sin contar los que tienen precio nulo.
Recuerde la diferencia de los valores que retorna la función "count()" cuando enviamos como
argumento un asterisco o el nombre de un campo: en el primer caso cuenta todos los registros
incluyendo los que tienen valor nulo, en el segundo, los registros en los cuales el campo
especificado es no nulo.
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:
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
a 30 pesos:
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 la
columna de agregado, debemos emplear la palabra clave "all" al lado de "group by":
Entonces, usamos "group by" para organizar registros en grupos y obtener un resumen de dichos
grupos. SQL Server produce una columna de valores por cada grupo, devolviendo filas por cada
grupo especificado.
6- Necesitamos el total del monto de las compras agrupadas por sexo (3 filas)
9- Cuente y agrupe por ciudad sin tener en cuenta los visitantes que no tienen
mail (3 filas):
10- Realice la misma consulta anterior, pero use la palabra clave "all" para
mostrar todos los
valores de ciudad, incluyendo las que devuelven cero o "null" en la columna de
agregado (4 filas)
Ver solución
Segundo problema:
Una empresa almacena los datos de sus empleados en una tabla "empleados".
1- Elimine la tabla, si existe:
if object_id('empleados') is not null
drop table empleados;
2- Cree la tabla:
create table empleados(
nombre varchar(30),
documento char(8),
domicilio varchar(30),
seccion varchar(20),
sueldo decimal(6,2),
cantidadhijos tinyint,
fechaingreso datetime,
primary key(documento)
);
8- Realice la misma consulta anterior pero esta vez incluya las secciones que
devuelven cero o
"null" en la columna de agregado (5 filas)
Ver solución
Si queremos saber la cantidad de libros agrupados por editorial usamos la siguiente instrucción
ya aprendida:
Si queremos saber la cantidad de libros agrupados por editorial pero considerando sólo algunos
grupos, por ejemplo, los que devuelvan un valor mayor a 2, usamos la siguiente instrucción:
Se utiliza "having", seguido de la condición de búsqueda, para seleccionar ciertas filas retornadas
por 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:
En algunos casos es posible confundir las cláusulas "where" y "having". Queremos contar los
registros agrupados por editorial sin tener en cuenta a la editorial "Planeta".
Analicemos las siguientes sentencias:
Ambas devuelven el mismo resultado, pero son diferentes. La primera, selecciona todos los
registros 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 cuenta
correspondiente a la editorial "Planeta".
Veamos otros ejemplos combinando "where" y "having". Queremos la cantidad de libros, sin
considerar los que tienen precio nulo, agrupados por editorial, sin considerar la 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ón dada 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 aquellas
editoriales 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
seleccionar las filas que tengan un valor menor a 100 y mayor a 30:
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.
6- Obtenga el total de los clientes que viven en calle "San Martin" (where),
agrupados por provincia
(group by), teniendo en cuenta todos los valores (all), de aquellas ciudades
que tengan menos de 2
clientes (having) y omitiendo la fila correspondiente a la ciudad de "Cordoba"
(having) (4 filas
devueltas)
Ver solución
Segundo problema:
Un comercio que tiene un stand en una feria registra en una tabla llamada
"visitantes" algunos datos
de las personas que visitan o compran en su stand para luego enviarle
publicidad de sus productos.
1- Elimine la tabla "visitantes", si existe:
if object_id('visitantes') is not null
drop table visitantes;
5- Obtenga el total de las compras agrupados por ciudad y sexo (group by),
teniendo en cuenta todos
los valores (all), considerando sólo los montos de compra superiores a 50
(where), los visitantes
con teléfono (where), sin considerar la ciudad de "Cordoba" (having),
ordenados por ciudad (order
by) (3 filas)
6- Muestre el monto mayor de compra agrupado por ciudad, siempre que dicho
valor supere los 50 pesos
(having), considerando sólo los visitantes de sexo femenino y domicilio
conocido (where) (2 filas)
7- Agrupe por ciudad y sexo, muestre para cada grupo el total de visitantes,
la suma de sus compras
y el promedio de compras, ordenado por la suma total y considerando las filas
con promedio superior
a 30 (3 filas)
Ver solución
Tenemos la tabla "visitantes" con los siguientes campos: nombre, edad, sexo, domicilio, ciudad,
telefono, montocompra.
Esta consulta muestra el total de visitantes agrupados por ciudad; pero si queremos además la
cantidad total de visitantes, debemos realizar otra consulta:
Para obtener ambos resultados en una sola consulta podemos usar "with rollup" que nos
devolverá ambas salidas en una sola consulta:
La consulta anterior retorna los registros agrupados por ciudad y una fila extra en la que la
primera columna 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
extras al resultado de una consulta, que muestran operaciones de resumen.
Si agrupamos por 2 campos, "ciudad" y "sexo":
La salida muestra los totales por ciudad y sexo y produce tantas filas extras como valores existen
del primer campo por el que se agrupa ("ciudad" en este caso), mostrando los totales para cada
valor, con la columna correspondiente al segundo campo por el que se agrupa ("sexo" en este
ejemplo) conteniendo "null", y 1 fila extra mostrando el total de todos los visitantes (con las
columnas 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".
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
resultados de resumen de los subgrupos. Si se agrupa por 2 campos SQL Server genera tantas
filas extras como valores existen del primer campo (con el segundo campo seteado a "null") y
una fila extra con ambos campos conteniendo "null".
Con "rollup" se puede emplear "where" y "having", pero no es compatible con "all".
Segundo problema:
Un instituto de enseñanza guarda las notas de sus alumnos en una tabla llamada
"notas".
1- Elimine la tabla si existe:
if object_id('notas') is not null
drop table notas;
Ver solución
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;
Es decir, "cube" genera filas de resumen de subgrupos para todas las combinaciones posibles de
los valores de los campos por los que agrupamos.
Con "cube" se puede emplear "where" y "having", pero no es compatible con "all".
2- Cree la tabla:
create table ventas(
numero int identity,
montocompra decimal(6,2),
tipopago char(1),--c=contado, t=tarjeta
vendedor varchar(30),
primary key (numero)
);
Segundo problema:
Un comercio que tiene un stand en una feria registra en una tabla llamada
"visitantes" algunos datos
de las personas que visitan o compran en su stand para luego enviarle
publicidad de sus productos.
1- Elimine la tabla "visitantes", si existe:
if object_id('visitantes') is not null
drop table visitantes;
5- Calcule la edad promedio de los visitantes agrupando por sexo y ciudad, sin
considerar los que no
tienen mail, use ambos modificadores de "group by" ("rollup" y "cube"):
select sexo,ciudad,
avg(edad) as 'edad promedio'
from visitantes
where mail is not null and
mail <>'no tiene'
group by sexo,ciudad
with rollup;
Se generan 2 filas con el promedio de edad por sexo de cada ciudad y 1 fila
con el promedio de edad
de todos los visitantes.
select sexo,ciudad,
avg(edad) as 'edad promedio'
from visitantes
where mail is not null and
mail <>'no tiene'
group by sexo,ciudad
with cube;
Se generan 2 filas con el promedio de edad por sexo de cada ciudad, 1 fila con
el promedio de edad
de todos los visitantes y 3 filas con el promedio de edad por ciudad.
Ver solución
41 - Función grouping
La función "grouping" se emplea con los operadores "rollup" y "cube" para distinguir los valores
de detalle y de resumen en el resultado. Es decir, permite diferenciar si los valores "null" que
aparecen en 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 el
valor 1 para indicar que la fila representa los valores de resumen de "rollup" o "cube" y el valor 0
para representar los valores de campo.
Sólo se puede emplear la función "grouping" en los campos que aparecen en la cláusula "group
by".
y 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;
ciudad cantidad
-------------------------
NULL 1
Alta Gracia 1
Cordoba 3
NULL 5
select ciudad,
count(*) as cantidad,
grouping(ciudad) as resumen
from visitantes
group by ciudad
with rollup;
La última fila contiene en la columna generada por "grouping" el valor 1, indicando que es la fila
de resumen generada por "rollup"; la primera fila, contiene en dicha columna el valor 0, que
indica que el valor "null" es un valor del campo "ciudad".
Entonces, si emplea los operadores "rollup" y "cube" y los campos por los cuales agrupa admiten
valores nulos, utilice la función "grouping" para distinguir los valores de detalle y de resumen en
el resultado.
41 - Función grouping
Primer problema:
Una empresa tiene registrados sus empleados en una tabla llamada "empleados".
1- Elimine la tabla si existe:
if object_id('empleados') is not null
drop table empleados;
Se usa con las funciones de agrupamiento: avg(), count(), max(), min(), sum().
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 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
de resumen 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
luego de "by" deben estar en el "order by". Listando varios campos luego del "by" corta un grupo
en subgrupos 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 un
subconjunto de los campos que aparecen después de "order by" y estar en el mismo orden. Si la
cláusula "order by" tiene los siguientes campos:
En una misma instrucción se pueden colocar varias cláusulas "compute" combinadas con varias
cláusulas "compute by":
Los tipos de datos ntext, text e image no se pueden incluir en una cláusula "compute" o "compute
by".
6- Realice la misma consulta anterior pero empleando "compute by" para obtener
resultados parciales
por documento,barrio y ciudad.
10- Combine cláusulas "compute" con "compute by" para averiguar el total de
monto a pagar por
propietario y el promedio de monto de todos (4 resultados parciales y 1
general)
Ver solución
Note que en los tres casos anteriores aparece "null" como un valor para "autor"· Si sólo
queremos la lista de autores conocidos, es decir, no queremos incluir "null" en la lista, podemos
utilizar la sentencia siguiente:
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;
Podemos combinarla con "where". Por ejemplo, queremos conocer los distintos autores de la
editorial "Planeta":
También puede utilizarse con "group by" para contar los diferentes autores por editorial:
La cláusula "distinct" afecta a todos los campos presentados. Para mostrar los títulos y editoriales
de los libros sin repetir títulos ni editoriales, usamos:
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".
Segundo problema:
La provincia almacena en una tabla llamada "inmuebles" los siguientes datos de
los inmuebles y sus
propietarios para cobrar impuestos:
1- Elimine la tabla si existe:
if object_id('inmuebles') is not null
drop table inmuebles;
Ver solución
44 - Cláusula top
La palabra clave "top" se emplea para obtener sólo una cantidad limitada de registros, los
primeros n registros de una consulta.
Con la siguiente consulta obtenemos todos los datos de los primeros 2 libros de la tabla:
Es decir, luego del "select" se coloca "top" seguido de un número entero positivo y luego se
continúa con la consulta.
En la consulta anterior solicitamos los títulos y autores de los 3 primeros libros, ordenados por
autor.
Cuando se combina con "order by" es posible emplear también la cláusula "with ties". Esta
cláusula permite incluir en la seleccion, todos los registros que tengan el mismo valor del campo
por el que se 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+1 tiene el mismo valor que n, y el n+2, etc.), lo incluye en la selección.
Veamos un ejemplo:
Esta consulta solicita el retorno de los primeros 3 registros; en caso que el registro número 4 (y
los posteriores), tengan el mismo valor en "autor" que el último registro retornado (número 3),
también aparecerán en la selección.
Si colocamos un valor para "top" que supera la cantidad de registros de la tabla, SQL Server
muestra todos los registros.
44 - Cláusula top
Primer problema:
Una empresa tiene registrados sus empleados en una tabla llamada "empleados".
1- Elimine la tabla si existe:
if object_id('empleados') is not null
drop table empleados;
6- Realice la misma consulta anterior pero incluya todos los registros que
tengan el mismo valor en
"seccion" que el último (8 registros)
8- Realice la misma consulta anterior pero incluya todos los valores iguales
al último registro
retornado (5 registros)
Ver solución
45 - Clave primaria compuesta
Las claves primarias pueden ser simples, formadas por un solo campo o compuestas, más de un
campo.
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
ser nulos.
Existe una playa de estacionamiento que almacena cada día los datos de los vehículos que
ingresan en la tabla llamada "vehiculos" con los siguientes campos:
Necesitamos definir una clave primaria para una tabla con los datos descriptos arriba. No
podemos usar solamente la patente porque un mismo auto puede ingresar más de una vez en el
día a la playa; 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
identificar un 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
ser clave.
En este ejemplo, un auto puede ingresar varias veces en un día a la playa, pero siempre será a
distinta hora.
Usamos 2 campos como clave, la patente junto con la hora de llegada, así identificamos
unívocamente cada registro.
Para establecer más de un campo como clave primaria usamos la siguiente sintaxis:
Al ingresar los registros, SQL Server controla que los valores para los campos establecidos como
clave primaria no estén repetidos en la tabla; si estuviesen repetidos, muestra un mensaje y la
inserció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 clave
primaria compuesta, es decir formada por más de un campo.
Segundo problema:
Un club dicta clases de distintos deportes. En una tabla llamada "inscriptos"
almacena la
información necesaria.
1- Elimine la tabla "inscriptos" si existe:
if object_id('inscriptos') is not null
drop table inscriptos;
Ver solución
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.
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 luego
agregar las restricciones.
Se pueden crear, modificar y eliminar las restricciones sin eliminar la tabla y volver a crearla.
Cuando se agrega una restricción a una tabla, SQL Server comprueba los datos existentes.
Hay varios tipos de restricciones.
47 - Restricción default
La restricción "default" especifica un valor por defecto para un campo cuando no se inserta
explí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:
Cada vez que establecíamos un valor por defecto para un campo de una tabla, SQL Server creaba
automá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
que consiste "DF" (por default), seguido del nombre de la tabla, el nombre del campo y letras y
números aleatorios.
Podemos agregar una restricción "default" a una tabla existente con la sintaxis básica siguiente:
Por convención, cuando demos el nombre a las restricciones "default" emplearemos un formato
similar 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 la
propiedad "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, podemos
establecer 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 procedimiento
almacenado "sp_helpcontraint":
sp_helpconstraint libros;
Entonces, la restricción "default" especifica un valor por defecto para un campo cuando no se
inserta explícitamente en un "insert", se puede establecer uno por campo y no se puede emplear
junto con la propiedad "identity".
47 - Restricción default
Primer problema:
Un comercio que tiene un stand en una feria registra en una tabla llamada
"visitantes" algunos datos
de las personas que visitan o compran en su stand para luego enviarle
publicidad de sus productos.
1- Elimine la tabla "visitantes", si existe:
if object_id('visitantes') is not null
drop table visitantes;
5- Ingrese algunos registros sin valor para los campos con restricción
"default":
insert into visitantes
values ('Susana Molina',35,'Colon 123',default,59.80);
insert into visitantes (nombre,edad,domicilio)
values ('Marcos Torres',29,'Carlos Paz');
insert into visitantes
values ('Mariana Juarez',45,'Carlos Paz',null,23.90);
Segundo problema:
Una playa de estacionamiento almacena cada día los datos de los vehículos que
ingresan en la tabla
llamada "vehiculos".
1- Elimine la tabla, si existe:
if object_id('vehiculos') is not null
drop table vehiculos;
2- Cree la tabla:
create table vehiculos(
patente char(6) not null,
tipo char(1),--'a'=auto, 'm'=moto
horallegada datetime,
horasalida datetime
);
Ver solución
48 - Restricción check
La restricción "check" especifica los valores que acepta un campo, evitando que se ingresen
valores inapropiados.
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 el
precio para los mayoristas).
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.
La condición puede hacer referencia a otros campos de la misma tabla. Por ejemplo, podemos
controlar que el precio mayorista no sea mayor al precio minorista:
Un campo puede tener varias restricciones restricciones "check" y una restricción "check" puede
incluir varios campos.
Las condiciones para restricciones "check" también pueden pueden incluir un patrón o una lista
de valores. 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'));
Si un campo permite valores nulos, "null" es un valor aceptado aunque no esté incluido en la
condición de restricción.
Si intentamos establecer una restricción "check" para un campo que entra en conflicto con otra
restricció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 una
restricción "default" establecida para el mismo campo, SQL Server lo permite; pero al intentar
ingresar un registro, aparece un mensaje de error.
48 - Restricción check
Primer problema:
Una empresa tiene registrados datos de sus empleados en una tabla llamada
"empleados".
1- Elimine la tabla si existe:
if object_id('empleados') is not null
drop table empleados;
5- Intente agregar otra restricción "check" al campo sueldo para asegurar que
ninguno supere el
valor 5000:
alter table empleados
add constraint CK_empleados_sueldo_maximo
check (sueldo<=5000);
La sentencia no se ejecuta porque hay un sueldo que no cumple la restricción.
Segundo problema:
Una playa de estacionamiento almacena los datos de los vehículos que ingresan
en la tabla llamada
"vehiculos".
1- Elimine la tabla, si existe:
if object_id('vehiculos') is not null
drop table vehiculos;
2- Cree la tabla:
create table vehiculos(
numero int identity,
patente char(6),
tipo char(4),
fechahoraentrada datetime,
fechahorasalida datetime
);
6- Agregue una restricción "check" que especifique que el campo "tipo" acepte
solamente los valores
"auto" y "moto":
alter table vehiculos
add constraint CK_vehiculos_tipo_valores
check (tipo in ('auto','moto'));
10- Agregue una restricción "check" para asegurarse que la fecha de entrada a
la playa no sea
posterior a la fecha y hora actual:
alter table vehiculos
add constraint CK_vehiculos_fechahoraentrada_actual
check (fechahoraentrada<=getdate());
Ver solución
Podemos hacerlo cuando agregamos la restricción "check" a una tabla para que SQL Server
acepte los valores ya almacenados que infringen la restricción. Para ello debemos incluir la
opción "with nocheck" en la instrucción "alter table":
La restricción no se aplica en los datos existentes, pero si intentamos ingresar un nuevo valor que
no cumpla la restricción, SQL Server no lo permite.
También podemos deshabilitar las restricciones para agregar o actualizar datos sin comprobarla:
Para habilitar una restricción deshabilitada se ejecuta la misma instrucción pero con la cláusula
"check" o "check all":
Si se emplea "check constraint all" no se coloca nombre de restricciones, habilita todas las
restricciones que tiene la tabla nombrada.
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
debe eliminar ("default" y las que veremos posteriormente).
8- Establezca una restricción "check" para "seccion" que permita solamente los
valores "Sistemas",
"Administracion" y "Contaduría":
alter table empleados
add constraint CK_empleados_seccion_lista
check (seccion in ('Sistemas','Administracion','Contaduria'));
No lo permite porque existe un valor fuera de la lista.
Ahora veremos las restricciones que se aplican a las tablas, que aseguran valores únicos para
cada registro.
Anteriormente, para establecer una clave primaria para una tabla empleábamos la siguiente
sintaxis al crear la tabla, por ejemplo:
Cada vez que establecíamos la clave primaria para la tabla, SQL Server creaba automáticamente
una restricción "primary key" para dicha tabla. Dicha restricción, a la cual no le dábamos un
nombre, 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ásica
siguiente:
En el siguiente ejemplo definimos una restricción "primary key" para nuestra tabla "libros" para
asegurarnos que cada libro tendrá un código diferente y único:
Con esta restricción, si intentamos ingresar un registro con un valor para el campo "codigo" que
ya existe o el valor "null", aparece un mensaje de error, porque no se permiten valores
duplicados ni nulos. 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, SQL
Server controla los datos existentes para confirmar que cumplen las exigencias de la restricción,
si no los cumple, la restricción no se aplica y aparece un mensaje de error. Por ejemplo, si
intentamos definir la restricción "primary key" para "libros" y hay registros con códigos
repetidos o con un valor "null", la restricción no se establece.
Cuando establecíamos una clave primaria al definir la tabla, automáticamente SQL Server
redefinía el 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 definen identity).
SQL Server permite definir solamente una restricción "primary key" por tabla, que asegura la
unicidad de cada registro de una 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
no tiene sentido ya que el valor por defecto solamente podrá ingresarse una vez; si intenta
ingresarse cuando otro registro ya lo tiene almacenado, aparecerá un mensaje de error indicando
que se intenta duplicar la clave.
4- Intente establecer una restricción "primary key" para la tabla para que el
documento no se repita
ni admita valores nulos:
alter table empleados
add constraint PK_empleados_documento
primary key(documento);
No lo permite porque la tabla contiene datos que no cumplen con la
restricción, debemos eliminar (o
modificar) el registro que tiene documento duplicado:
delete from empleados
where nombre='Carlos Fuentes';
Segundo problema:
Una empresa de remises tiene registrada la información de sus vehículos en una
tabla llamada
"remis".
1- Elimine la tabla si existe:
if object_id('remis') is not null
drop table remis;
Ver solución
51 - Restricción unique
Hemos 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".
Se emplea cuando ya se estableció una clave primaria (como un número de legajo) pero se
necesita asegurar que otros datos también sean únicos y no se repitan (como número de
documento).
La sintaxis general es la siguiente:
Ejemplo:
Por convención, cuando demos el nombre a las restricciones "unique" seguiremos la misma
estructura: "UQ_NOMBRETABLA_NOMBRECAMPO". Quizá parezca innecesario colocar el
nombre de la tabla, pero cuando empleemos varias tablas verá que es útil identificar las
restricciones por tipo, tabla y campo.
Recuerde que cuando agregamos una restricción a una tabla que contiene información, SQL
Server controla los datos existentes para confirmar que cumplen la condición de la restricción, si
no los cumple, la restricción no se aplica y aparece un mensaje de error. En el caso del ejemplo
anterior, si la tabla contiene números de documento duplicados, la restricción no podrá
establecerse; si podrá establecerse si tiene valores nulos.
51 - Restricción unique
Primer problema:
Una empresa de remises tiene registrada la información de sus vehículos en una
tabla llamada
"remis".
1- Elimine la tabla si existe:
if object_id('remis') is not null
drop table remis;
4- Intente agregar una restricción "unique" para asegurarse que la patente del
remis no tomará
valores repetidos.
No se puede porque hay valores duplicados.
52 - Información de restricciones
(sp_helpconstraint)
El procedimiento almacenado "sp_helpconstraint" seguido del nombre de una tabla muestra la
información referente a todas las restricciones establecidas en dicha tabla, devuelve las
siguientes columnas:
- delete_action: solamente es aplicable para restricciones de tipo "foreign key" (la veremos
posteriormente).
- update_action: sólo es aplicable para restricciones de tipo "foreign key" (la veremos
posteriormente).
52 - Información de restricciones
(sp_helpconstraint)
El procedimiento almacenado "sp_helpconstraint" seguido del nombre de una tabla muestra la
información referente a todas las restricciones establecidas en dicha tabla, devuelve las
siguientes columnas:
- delete_action: solamente es aplicable para restricciones de tipo "foreign key" (la veremos
posteriormente).
- update_action: sólo es aplicable para restricciones de tipo "foreign key" (la veremos
posteriormente).
2- Cree la tabla:
create table vehiculos(
patente char(6) not null,
tipo char(1),--'a'=auto, 'm'=moto
horallegada datetime not null,
horasalida datetime
);
3- Establezca una restricción "check" que admita solamente los valores "a" y
"m" para el campo
"tipo":
alter table vehiculos
add constraint CK_vehiculos_tipo
check (tipo in ('a','m'));
5- Establezca una restricción "check" para el campo "patente" para que acepte
3 letras seguidas de 3
dígitos:
alter table vehiculos
add constraint CK_vehiculos_patente_patron
check (patente like '[A-Z][A-Z][A-Z][0-9][0-9][0-9]');
6- Agregue una restricción "primary key" que incluya los campos "patente" y
"horallegada":
alter table vehiculos
add constraint PK_vehiculos_patentellegada
primary key(patente,horallegada);
7- Ingrese un vehículo:
insert into vehiculos values('SDR456','a','2005/10/10 10:10',null);
I) DE LOS CAMPOS (hace referencia a los valores válidos para un campo determinado).
Pueden ser:
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 valores duplicados ni valores nulos. Se crea un índice automáticamente.
b) UNIQUE: impide la duplicación de claves alternas (no primarias). Se permiten valores
nulos. Se crea un índice automáticamente.
2. REGLAS (rules) y
3. VALORES PREDETERMINADOS (defaults).
Las reglas especifican los valores que se pueden ingresar en un campo, asegurando que los datos
se encuentren en un intervalo de valores específico, coincidan con una lista de valores o sigan un
patrón.
Una regla se asocia a un campo de una tabla (o a un tipo de dato definido por el usuario, tema
que veremos posteriormente).
Entonces, 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 se
asocia 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.
Creamos una regla para restringir los valores que se pueden ingresar en un campo "sueldo" de
una tabla llamada "empleados", estableciendo un intervalo de valores:
Si intentamos agregar (o actualizar) un registro con valor para el campo "sueldo" que no esté en
el intervalo de valores especificado en la regla, aparece un mensaje de error indicando que hay
conflicto 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 lo
hace al aplicar restricciones; si no los cumple, la regla se asocia igualmente; pero al ejecutar una
instrucción "insert" o "update" muestra un mensaje de error, es decir, actúa en inserciones y
actualizaciones.
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 reeemplaza
la asociación anterior; pero la primera regla no desaparece, solamente se deshace la asociación.
La función que cumple una regla es básicamente la misma que una restricción "check", las
siguientes características explican algunas diferencias entre ellas:
- podemos definir varias restricciones "check" sobre un campo, un campo solamente puede tener
una regla asociada a él;
- una restricción "check" se almacena con la tabla, cuando ésta se elimina, las restricciones
también se borran. Las reglas son objetos diferentes e independientes de las tablas, si eliminamos
una 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 distintos
campos (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
de ellas 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, en
tal caso en la columna "Object_type" aparece "rule".
3- Cree la tabla:
create table vehiculos(
patente char(6) not null,
tipo char(1),--'a'=auto, 'm'=moto
horallegada datetime not null,
horasalida datetime
);
5- Cree una regla para restringir los valores que se pueden ingresar en un
campo "patente" (3 letras
seguidas de 3 dígitos):
create rule RG_patente_patron
as @patente like '[A-Z][A-Z][A-Z][0-9][0-9][0-9]'
10- Cree otra regla que controle los valores para el campo "tipo" para que
solamente puedan
ingresarse los caracteres "a" y "m".
13- Cree otra regla llamada "RG_vehiculos_tipo2" que controle los valores para
el campo "tipo" para
que solamente puedan ingresarse los caracteres "a", "c" y "m".
16- Cree una regla que permita fechas menores o iguales a la actual.
19- Intente establecer una restricción "check" que asegure que la fecha y hora
de llegada a la playa
no sea posterior a la fecha y hora de salida:
alter table vehiculos
add constraint CK_vehiculos_llegada_salida
check(horallegada<=horasalida);
No lo permite porque hay un registro que no cumple la restricción.
22- Cree una restricción "default" que almacene el valor "b" en el campo
"tipo:
alter table vehiculos
add constraint DF_vehiculos_tipo
default 'b'
for tipo;
Note que esta restricción va contra la regla asociada al campo "tipo" que
solamente permite los
valores "a", "c" y "m". SQL Server no informa el conflicto hasta que no
intenta ingresar el valor
por defecto.
23- Intente ingresar un registro con el valor por defecto para el campo
"tipo":
insert into vehiculos values ('STU456',default,'1990-02-01 10:10','1990-02-01
15:30');
No lo permite porque va contra la regla asociada al campo "tipo".
55 - Eliminar y dasasociar reglas
(sp_unbindrule - drop rule)
Para eliminar una regla, primero se debe deshacer la asociación, ejecutando el procedimiento
almacenado del sistema "sp_unbindrule":
No es posible eliminar una regla si está asociada a un campo. Si intentamos hacerlo, aparece un
mensaje de error y la eliminación no se realiza.
Si eliminamos una tabla, las asociaciones de reglas de sus campos desaparecen, pero las reglas
siguen existiendo.
3- Cree la tabla:
create table vehiculos(
patente char(6) not null,
tipo char(1),--'a'=auto, 'm'=moto
horallegada datetime not null,
horasalida datetime
);
4- Cree una regla para restringir los valores que se pueden ingresar en un
campo "patente" (3 letras
seguidas de 3 dígitos):
create rule RG_patente_patron
as @patente like '[A-Z][A-Z][A-Z][0-9][0-9][0-9]';
7- Cree otra regla que controle los valores para el campo "tipo" para que
solamente puedan
ingresarse los caracteres "a" y "m":
create rule RG_vehiculos_tipo
as @tipo in ('a','m')
10- Cree otra regla llamada "RG_vehiculos_tipo2" que controle los valores para
el campo "tipo" para
que solamente puedan ingresarse los caracteres "a", "c" y "m":
create rule RG_vehiculos_tipo2
as @tipo in ('a','c','m');
sp_help NOMBREREGLA;
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 ver
las reglas asociadas a una tabla con este procedimiento almacenado:
sp_helpconstraint NOMBRETABLA;
- constraint_type: indica que es una regla con "RULE", nombrando el campo al que está
asociada.
Para ver el texto de una regla empleamos el procedimiento almacenado "sp_helptext" seguido del
nombre de la regla:
sp_helptext NOMBREREGLA;
También se puede consultar la tabla del sistema "sysobjects", que nos muestra el nombre y varios
datos 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":
Si queremos ver todas las reglas creadas por nosotros, podemos tipear:
Los valores predeterminados se asocian con uno o varios campos (o tipos de datos definidos por
el usuario); 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 del
campo al que está asociado.
Sintaxis básica:
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
puede tener UN valor predeterminado asociado a él,
- una restricción "default" se almacena con la tabla, cuando ésta se elimina, las restricciones
también. Los valores predeterminados son objetos diferentes e independientes de las tablas, si
eliminamos una tabla, las asociaciones desaparecen, pero los valores predeterminados siguen
existiendo en la base de datos.
- una restricción "default" se establece para un solo campo; un valor predeterminado puede
asociarse a distintos campos (inclusive, de diferentes tablas).
- una restricción "default" no puede establecerse sobre un campo "identity", tampoco un valor
predeterminado.
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 al
intentar 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,
la nueva asociación reemplaza a la anterior.
En el siguiente creamos un valor predeterminado que inserta ceros con el formato válido para un
número de teléfono:
Con "sp_helpconstraint" podemos ver los valores predeterminados asociados a los campos de
una tabla.
Con "sp_help" podemos ver todos los objetos de la base de datos activa, incluyendo los valores
predeterminados, en tal caso en la columna "Object_type" aparece "default".
3- Cree la tabla:
create table clientes(
legajo char(4),
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(15),
provincia varchar(20) default 'Cordoba',
fechaingreso datetime
);
4- Cree una regla para establecer un patrón para los valores que se ingresen
en el campo "legajo" (2
letras seguido de 2 cifras) llamada "RG_legajo_patron":
11- Ingrese un registro con valores por defecto para los campos "domicilio" y
"ciudad" y vea qué
almacenaron.
15- Ingrese algunos registros para ver cómo se almacenan los valores para los
cuales no se insertan
datos.
18- Cree una regla que entre en conflicto con el valor predeterminado
"VP_legajo_patron".
sp_unbindefault 'TABLA.CAMPO';
sp_unbindefault 'empleados.sueldo';
3- Cree la tabla:
create table libros(
codigo int identity,
titulo varchar(40) not null,
autor varchar(30),
editorial varchar(20),
precio decimal(5,2),
cantidad smallint
);
4- Cree una regla para impedir que se ingresen valores negativos, llamada
"RG_positivo".
15- Ingrese un registro con valores por defecto para todos los campos, excepto
"titulo" y vea qué se
almacenó.
16- Ingrese otro registro con valor predeterminado para el campo "precio" y
vea cómo se almacenó.
59 - Información de valores predeterminados
Para obtener información de los valores predeterminados podemos emplear los mismos
procedimientos almacenados que usamos para las reglas.
Si empleamos "sp_help", vemos todos los objetos de la base de datos activa (incluyendo los
valores predeterminados); en la columna "Object_type" (tipo de objeto) muestra "default".
sp_help NOMBREVALORPREDETERMINADO;
"sp_helpconstraint" retorna una lista de todas las restricciones que tiene una tabla. También los
valores predeterminados asociados; muestra la siguiente información:
Con "sp_helptext" seguido del nombre de un valor predeterminado podemos ver el texto de
cualquier valor predeterminado:
sp_helptext NOMBREVALORPREDETERMINADO;
También se puede consultar la tabla del sistema "sysobjects", que nos muestra el nombre y varios
datos 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":
Si queremos ver todos los valores predeterminados creados por nosotros, podemos tipear:
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 una
tabla 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.
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.
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
por los cuales se realizan búsqueda con frecuencia: claves primarias, claves externas o campos
que combinan tablas.
No se recomienda crear índices por campos que no se usan con frecuencia en consultas o no
contienen valores únicos.
1) Un INDICE AGRUPADO es similar a una guía telefónica, los registros con el mismo valor de
campo se agrupan juntos. Un índice agrupado determina la secuencia de almacenamiento de los
registros en una tabla.
Se utilizan para campos por los que se realizan busquedas con frecuencia o se accede siguiendo
un 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.
Es recomendable crear los índices agrupados antes que los no agrupados, porque los primeros
modifican 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 índice
agrupado 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.
62 - Creación de índices
Para crear índices empleamos la instrucción "create index".
En este ejemplo se crea un índice agrupado único para el campo "codigo" de la tabla "libros":
Para identificar los índices fácilmente, podemos agregar un prefijo al nombre del índice, por
ejemplo "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":
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 - tema
que veremos posteriormente).
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 una
restricción "unique", si no se especifica, el índice será no agrupado (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
que cree un índice NO agrupado:
Muestra el nombre del índice, si es agrupado (o no), primary (o unique) y el campo por el cual se
indexa.
Todos los índices de la base de datos activa se almacenan en la tabla del sistema "sysindexes",
podemos consultar dicha tabla tipeando:
Para ver todos los índices de la base de datos activa creados por nosotros podemos tipear la
siguiente consulta:
62 - Creación de índices
Primer problema:
Un profesor guarda algunos datos de sus alumnos en una tabla llamada
"alumnos".
1- Elimine la tabla si existe y créela con la siguiente estructura:
if object_id('alumnos') is not null
drop table alumnos;
create table alumnos(
legajo char(5) not null,
documento char(8) not null,
apellido varchar(30),
nombre varchar(30),
notafinal decimal(4,2)
);
13- Consulte la tabla "sysindexes", para ver los nombres de todos los índices
creados para
"alumnos":
select name from sysindexes
where name like '%alumnos%';
4 índices.
17- Consulte la tabla "sysindexes", para ver los nombres de todos los índices
creados para
"alumnos":
select name from sysindexes
where name like '%alumnos%';
5 índices.
18- Consulte la tabla "sysindexes", para ver los nombres de todos los índices
creados por usted:
select name from sysindexes
where name like 'I_%';
3 índices. Recuerde que los índices que crea SQL Server automáticamente al
agregarse una restricción
"primary" o "unique" no comienzan con "I_".
Ver solución
63 - Regenerar índices
Vimos 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
ello evitamos eliminarlo y volver a crearlo. La sintaxis es la siguiente:
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 la
misma 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
campo de 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":
Esta opción no puede emplearse con índices creados a partir de una restricción "primary key" o
"unique".
63 - Regenerar índices
Primer problema:
Un profesor guarda algunos datos de sus alumnos en una tabla llamada
"alumnos".
1- Elimine la tabla si existe y créela con la siguiente estructura:
if object_id('alumnos') is not null
drop table alumnos;
create table alumnos(
legajo char(5) not null,
documento char(8) not null,
apellido varchar(30),
nombre varchar(30),
notafinal decimal(4,2)
);
16- Modifique el índice "I_alumnos_legajo" para que sea único y conserve todas
las otras
características.
63 - Regenerar índices
Primer problema:
Un profesor guarda algunos datos de sus alumnos en una tabla llamada
"alumnos".
1- Elimine la tabla si existe y créela con la siguiente estructura:
if object_id('alumnos') is not null
drop table alumnos;
create table alumnos(
legajo char(5) not null,
documento char(8) not null,
apellido varchar(30),
nombre varchar(30),
notafinal decimal(4,2)
);
16- Modifique el índice "I_alumnos_legajo" para que sea único y conserve todas
las otras
características.
64 - Eliminar índices
Primer problema:
Un profesor guarda algunos datos de sus alumnos en una tabla llamada
"alumnos".
1- Elimine la tabla si existe y créela con la siguiente estructura:
if object_id('alumnos') is not null
drop table alumnos;
create table alumnos(
legajo char(5) not null,
documento char(8) not null,
apellido varchar(30),
nombre varchar(30),
notafinal decimal(4,2)
);
64 - Eliminar índices
Primer problema:
Un profesor guarda algunos datos de sus alumnos en una tabla llamada
"alumnos".
1- Elimine la tabla si existe y créela con la siguiente estructura:
if object_id('alumnos') is not null
drop table alumnos;
create table alumnos(
legajo char(5) not null,
documento char(8) not null,
apellido varchar(30),
nombre varchar(30),
notafinal decimal(4,2)
);
Para evitar la repetición de datos y ocupar menos espacio, se separa la información en varias
tablas. 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:
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 libro
agregamos un campo que hace referencia al código de la editorial en la tabla "libros" y en
"editoriales".
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 consultar
ambas 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:
Hay hay tres tipos de combinaciones. En los siguientes capítulos explicamos cada una de ellas.
La combinación interna emplea "join", que es la forma abreviada de "inner join". Se emplea para
obtener información de dos tablas y combinar dicha información en una salida.
select CAMPOS
from TABLA1
join TABLA2
on CONDICIONdeCOMBINACION;
Ejemplo:
- 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 una
tabla se combinará con qué registro de la otra tabla, con "on". Se debe especificar la condición
para 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án
ambas 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 las
tablas referenciadas tienen campos con igual nombre, esto es necesario para evitar confusiones y
ambiguedades 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" es ambiguo.
Entonces, si las tablas que combinamos tienen nombres de campos iguales, DEBE especificarse
a qué tabla pertenece anteponiendo el nombre de la tabla al nombre del campo, separado por un
punto (.).
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 los
campos clave que identifican al registro.
Se puede incluir en la consulta join la cláusula "where" para restringir los registros que retorna el
resultado; también "order by", "distinct", etc..
Se emplea este tipo de combinación para encontrar registros de la primera tabla que se
correspondan con los registros de la otra, es decir, que cumplan la condición del "on". Si un valor
de la primera tabla no se encuentra en la segunda tabla, el registro no aparece.
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 hace
más legible la consulta si es larga y compleja, pero en algunas consultas es absolutamente
necesario.
Segundo problema:
Un club dicta clases de distintos deportes. Almacena la información en una
tabla llamada
"inscriptos" que incluye el documento, el nombre, el deporte y si la matricula
esta paga o no y una
tabla llamada "inasistencias" que incluye el documento, el deporte y la fecha
de la inasistencia.
1- Elimine las tablas si existen y cree las tablas:
if (object_id('inscriptos')) is not null
drop table inscriptos;
if (object_id('inasistencias')) is not null
drop table inasistencias;
Ver solución
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 los
registros de la segunda tabla que no la cumplen; es decir, muestran todos los registros de las
tablas 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 de
las tablas y la información que cumple con la condición. Las combinaciones externas se realizan
solamente entre 2 tablas.
Hay tres tipos de combinaciones externas: "left outer join", "right outer join" y "full outer join";
se pueden abreviar con "left join", "right join" y "full join" respectivamente.
Se emplea una combinación externa izquierda para mostrar todos los registros de la tabla de la
izquierda. Si no encuentra coincidencia con la tabla de la derecha, el registro muestra los campos
de la segunda tabla seteados a "null".
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,
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".
Es importante la posición en que se colocan las tablas en un "left join", la tabla de la izquierda es
la que 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 la
derecha, se genera una fila extra (una por cada valor no encontrado) con todos los campos
correspondientes a la tabla derecha seteados a "null". La sintaxis básica es la siguiente:
select CAMPOS
from TABLAIZQUIERDA
left join TABLADERECHA
on CONDICION;
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
editorial no 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
considerando solamente los registros que encuentran coincidencia 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;
También podemos mostrar las editoriales que NO están presentes en "libros", es decir, que NO
encuentran 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 null;
Una combinación externa derecha ("right outer join" o "right join") opera del mismo modo sólo
que la tabla derecha es la que localiza los registros en la tabla izquierda.
El resultado mostrará el título y nombre de la editorial; 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".
Es FUNDAMENTAL tener en cuenta la posición en que se colocan las tablas en los "outer join".
En un "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
primera tabla (izquierda).
En la siguiente consulta empleamos un "left join" para conseguir el mismo resultado que el "right
join" 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 "left
join"; 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
valor de 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
izquierda seteados 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 consulta
considerando 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 encuentran
coincidencia 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;
Una combinación externa completa ("full outer join" o "full join") retorna todos los registros de
ambas 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 la
tabla de la derecha no encuentra correspondencia en la tabla izquierda, los campos de esta última
aparecen 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 los
libros cuyo código de editorial no existe en la tabla "editoriales" y las editoriales de las cuales no
hay correspondencia en "libros".
4- Empleando un "left join" con "deportes" obtenga todos los datos de los
inscriptos (7 registros)
6- Muestre los deportes para los cuales no hay inscriptos, empleando un "left
join" (1 registro)
8- Emplee un "full join" para obtener todos los datos de ambas tablas,
incluyendo las inscripciones
a deportes inexistentes en "deportes" y los deportes que no tienen inscriptos
(8 registros)
Ver solución
select CAMPOS
from TABLA1
cross join TABLA2;
Veamos un ejemplo. Un pequeño restaurante almacena los nombres y precios de sus comidas en
una tabla llamada "comidas" y en una tabla denominada "postres" los mismos datos de sus
postres.
Si necesitamos conocer todas las combinaciones posibles para un menú, cada comida con cada
postre, empleamos un "cross join":
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.
5- Forme las parejas pero teniendo en cuenta que no tengan una diferencia
superior a 10 años (8
registros)
Ver solución
Segundo problema:
Una empresa de seguridad almacena los datos de sus guardias de seguridad en
una tabla llamada
"guardias". también almacena los distintos sitios que solicitaron sus
servicios en una tabla llamada
"tareas".
1- Elimine las tablas "guardias" y "tareas" si existen:
if object_id('guardias') is not null
drop table guardias;
if object_id('tareas') is not null
drop table tareas;
4- La empresa quiere que todos sus empleados realicen todas las tareas.
Realice una "cross join" (20
registros)
5- En este caso, la empresa quiere que todos los guardias de sexo femenino
realicen las tareas de
"vigilancia interior" y los de sexo masculino de "vigilancia exterior".
Realice una "cross join" con
un "where" que controle tal requisito (10 registros)
Ver solución
71 - Autocombinación
Dijimos que es posible combinar una tabla consigo misma.
Un pequeño restaurante tiene almacenadas sus comidas en una tabla llamada "comidas" que
consta 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:
En la consulta anterior aparecen filas duplicadas, para evitarlo debemos emplear un "where":
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 debemos
utilizar 2 alias para la tabla. Para evitar que aparezcan filas duplicadas, debemos emplear un
"where".
71 - Autocombinación
Primer 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;
Segundo problema:
Varios clubes de barrio se organizaron para realizar campeonatos entre ellos.
La tabla llamada
"equipos" guarda la informacion de los distintos equipos que jugarán.
1- Elimine la tabla, si existe y créela nuevamente:
if object_id('equipos') is not null
drop table equipos;
4- Cada equipo jugará con todos los demás 2 veces, una vez en cada sede.
Realice un "cross join"
para combinar los equipos teniendo en cuenta que un equipo no juega consigo
mismo (12 registros)
6- Realice un "cross join" para combinar los equipos para que cada equipo
juegue con cada uno de los
otros una sola vez (6 registros)
Ver solución
72 - Combinaciones y funciones de
agrupamiento
Podemos 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:
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
libros de cada editorial usamos la función "max()", hacemos un "left join" y agrupamos por
nombre de la editorial:
En la sentencia anterior, mostrará, para la editorial de la cual no haya libros, el valor "null" en la
columna calculada.
72 - Combinaciones y funciones de
agrupamiento
Primer problema:
Un comercio que tiene un stand en una feria registra en una tabla llamada
"visitantes" algunos datos
de las personas que visitan o compran en su stand para luego enviarle
publicidad de sus productos y
en 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;
73 - Combinación de más de dos tablas
Podemos hacer un "join" con más de dos tablas.
Cada join combina 2 tablas. Se pueden emplear varios join para enlazar varias tablas. Cada
resultado 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 se
combinará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
y comprensible.
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
editorial no existe en "editoriales", esto es porque realizamos una combinación interna.
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
no coincidencia 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 tablas
deben 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 las
tablas y los tipos de "join"; recuerde que la tabla resultado del primer join es la que se combina
con el segundo join, no la segunda tabla nombrada. En el ejemplo anterior, el "left join" no se
realiza entre las tablas "libros" y "editoriales" sino entre el resultado del "right join" y la tabla
"editoriales".
10- Muestre todos los datos de las inscripciones (excepto los códigos)
incluyendo aquellas
inscripciones cuyo código de deporte no existe en "deportes" y cuyo documento
de socio no se
encuentra en "socios".
11- Muestre todas las inscripciones del socio con documento "22222222".
Ver solución
Podemos emplear "update" o "delete" con "join" para actualizar o eliminar registros de una tabla
consultando 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":
delete libros
from libros
join editoriales
on codigoeditorial = editoriales.codigo
where editoriales.nombre='Emece';
75 - Clave foránea
Un campo que no es clave primaria en una tabla y sirve para enlazar sus valores con otra tabla en
la 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:
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. Si
modificamos 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 el
tipo, longitud o atributos de una clave foránea, ésta puede quedar inhabilitada para hacer los
enlaces.
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.
Con la restricción "foreign key" se define un campo (o varios) cuyos valores coinciden con la
clave primaria de la misma tabla o de otra, es decir, se define una referencia a un campo con una
restricció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
las externas. Por ejemplo, controla que si se agrega un código de editorial en la tabla "libros", tal
código exista en la tabla "editoriales".
También controla que no pueda eliminarse un registro de una tabla ni modificar la clave primaria
si una clave externa hace referencia al registro. Por ejemplo, que no se pueda eliminar o
modificar un código de "editoriales" si existen libros con dicho código.
La siguiente es la sintaxis parcial general para agregar una restricción "foreign key":
Analicémosla:
- luego de "foreign key", entre paréntesis se coloca el campo de la tabla a la que le aplicamos la
restricción que será establecida como clave foránea,
Para agregar una restricción "foreign key" al campo "codigoeditorial" de "libros", tipeamos:
En el ejemplo implementamos una restricción "foreign key" para asegurarnos que el código de la
editorial 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 Server
controla los datos existentes para confirmar que cumplen con la restricción, si no los cumple, la
restricción no se aplica y aparece un mensaje de error. Por ejemplo, si intentamos agregar una
restricción "foreign key" a la tabla "libros" y existe un libro con un valor de código para editorial
que no 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 un
mensaje de error. Si al ingresar un registro (un libro), no colocamos el valor para el campo clave
foránea (codigoeditorial), almacenará "null", porque esta restricción permite valores nulos (a
menos que se haya especificado lo contrario al definir el campo).
Actúa en eliminaciones y actualizaciones. Si intentamos eliminar un registro o modificar un
valor de clave primaria de una tabla si una clave foránea hace referencia a dicho registro, SQL
Server no lo permite (excepto si se permite la acción en cascada, tema que veremos
posteriormente). Por ejemplo, si intentamos eliminar una editorial a la que se hace referencia en
"libros", aparece un mensaje de error.
La cantidad y tipo de datos de los campos especificados luego de "foreign key" DEBEN
coincidir con 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 entre
distintas tablas.
No se puede eliminar una tabla referenciada en una restricción "foreign key", aparece un mensaje
de 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 para
eliminaciones y actualizaciones, el estado (temas que veremos más adelante), el nombre del
campo y la tabla y campo que referencia.
Una mutual almacena los datos de sus afiliados en una tabla llamada "afiliados". Algunos
afiliados inscriben a sus familiares. La tabla contiene un campo que hace referencia al afiliado
que lo incorporó a la mutual, del cual dependen.
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 se
ingrese en el campo "afiliadotitular" exista en la tabla "afiliados":
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 de
error.
Si intentamos eliminar un afiliado que es titular de otros afiliados, no se podrá hacer, a menos
que se haya especificado la acción en cascada (próximo tema).
3- Intente agregar una restricción "foreign key" para evitar que en el campo
"referenciadopor" se
ingrese un valor de código de cliente que no exista.
No se permite porque existe un registro que no cumple con la restricción que
se intenta establecer.
Si intentamos eliminar un registro de la tabla referenciada por una restricción "foreign key" cuyo
valor de clave primaria existe referenciada en la tabla que tiene dicha restricción, la acción no se
ejecuta y aparece un mensaje de error. Esto sucede porque, por defecto, para eliminaciones, la
opción de la restricción "foreign key" es "no action". Lo mismo sucede si intentamos actualizar
un valor de clave primaria de una tabla referenciada por una "foreign key" existente en la tabla
principal.
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
modificaciones de 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
tabla referenciada (TABLA2) que tengan referencia en la tabla principal (TABLA1), se genere
un error y la acción no se realice; es la opción predeterminada.
Veamos un ejemplo. Definimos una restricción "foreign key" a la tabla "libros" estableciendo el
campo "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
la acción en cascada para las actualizaciones y eliminaciones:
Segundo problema:
Un club dicta clases de distintos deportes. En una tabla llamada "deportes"
guarda la información de
los distintos deportes que se enseñan; en una tabla "socios", los datos de los
socios y en una tabla
"inscripciones" almacena la información necesaria para las inscripciones de
los distintos socios a
los distintos deportes.
1- Elimine las tablas si existen:
if object_id('inscripciones') is not null
drop table inscripciones;
if object_id('deportes') is not null
drop table deportes;
if object_id('socios') is not null
drop table socios;
Ver solució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
cumplir la restricción.
Se pueden deshabilitar las restricciones "check" y "foreign key", a las demás se las debe
eliminar.
En el siguiente ejemplo agregamos una restricción "foreign key" que controla que todos los
códigos de editorial tengan un código válido, es decir, dicho código exista en "editoriales". La
restricción no se aplica en los datos existentes pero si en los siguientes ingresos, modificaciones
y actualizaciones:
Para habilitar una restricción deshabilitada se ejecuta la misma instrucción pero con la cláusula
"check" o "check all":
Si se emplea "check constraint all" no se coloca nombre de restricciones, habilita todas las
restricciones 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".
Podemos eliminar una restricción "foreign key" con "alter table". La sintaxis básica es la misma
que para cualquier otra restricción:
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 se
elimina.
4- Intente agregar una restricción "foreign key" para que los códigos de
provincia de "clientes"
existan en "provincias" con acción en cascada para actualizaciones y
eliminaciones, sin especificar
la opción de comprobación de datos:
alter table clientes
add constraint FK_clientes_codigoprovincia
foreign key (codigoprovincia)
references provincias(codigo)
on update cascade
on delete cascade;
No se puede porque al no especificar opción para la comprobación de datos, por
defecto es "check" y
hay un registro que no cumple con la restricción.
5- Agregue la restricción anterior pero deshabilitando la comprobación de
datos existentes:
alter table clientes
with nocheck
add constraint FK_clientes_codigoprovincia
foreign key (codigoprovincia)
references provincias(codigo)
on update cascade
on delete cascade;
- update_action: sólo es aplicable para restricciones de tipo "foreign key". Indica si la acción de
actualización es: No Action, Cascade, or n/a. Indica "n/a" en cualquier restricción para la que no
se aplique.
- 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
que haga referencia al campo "codigo" de "editoriales y permita actualizaciones en cascada y no
eliminaciones (por defecto "no action");
- una restricción "foreign key" para establecer el campo "codigoautor" como clave externa que
haga referencia 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.
- 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
que haga referencia al campo "codigo" de "editoriales y permita actualizaciones en cascada y no
eliminaciones (por defecto "no action");
- una restricción "foreign key" para establecer el campo "codigoautor" como clave externa que
haga referencia 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.
82 - Unión
El operador "union" combina el resultado de dos o más instrucciones "select" en un único
resultado.
Se usa cuando los datos que se quieren obtener pertenecen a distintas tablas y no se puede
acceder a ellos con una sola consulta.
Es necesario que las tablas referenciadas tengan tipos de datos similares, la misma cantidad de
campos y el mismo orden de campos en la lista de selección de cada consulta. No se incluyen las
filas duplicadas en el resultado, a menos que coloque la opción "all".
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" y
los datos de los profesores en otra denominada "profesores".
La academia necesita el nombre y domicilio de profesores y alumnos para enviarles una tarjeta
de invitación.
Para obtener los datos necesarios de ambas tablas en una sola consulta necesitamos realizar una
unión:
El primer "select" devuelve el nombre y domicilio de todos los alumnos; el segundo, el nombre y
domicilio de todos los profesores.
Los encabezados del resultado de una unión son los que se especifican en el primer "select".
82 - Unión
Primer problema:
Un supermercado almacena en una tabla denominada "proveedores" los datos de
las compañías que le
proveen de mercaderías; en una tabla llamada "clientes", los datos de los
comercios que le compran y
en otra tabla "empleados" los datos de los empleados.
1- Elimine las tablas si existen:
if object_id('clientes') is not null
drop table clientes;
if object_id('proveedores') is not null
drop table proveedores;
if object_id('empleados') is not null
drop table empleados;
Para agregar un nuevo campo a una tabla empleamos la siguiente sintaxis básica:
En el siguiente ejemplo agregamos el campo "cantidad" a la tabla "libros", de tipo tinyint, que
acepta valores nulos:
SQL Server no permite agregar campos "not null" a menos que se especifique un valor por
defecto:
En el ejemplo anterior, se agregó una restricción "default" para el nuevo campo, que puede
verificarse ejecutando el procedimiento almacenado "sp_helpconstraint".
Al agregar un campo puede especificarse que sea "identity" (siempre que no exista otro campo
identity).
No pueden eliminarse los campos que son usados por un índice o tengan restricciones. No puede
eliminarse un campo si es el único en la tabla.
9- Verifique la eliminación:
sp_columns empleados;
Modificamos el campo "titulo" extendiendo su longitud y para que NO admita valores nulos:
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:
SQL Server tiene algunas excepciones al momento de modificar los campos. No permite
modificar:
- 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.
- campos que afecten a los datos existentes cuando una tabla contiene registros (ejemplo: un
campo contiene valores nulos y se pretende redefinirlo como "not null"; un campo int guarda un
valor 300 y se pretende modificarlo a tinyint, etc.).
3- Controle la modificación:
sp_columns empleados;
10- Intente agregar un registro con el valor por defecto para "ciudad":
insert into empleados values(3,'33333333','Juan Perez','Sarmiento
856',default,500,4);
No se puede porque el campo acepta 10 caracteres y el valor por defecto tiene
12 caracteres.
11- Modifique el campo "ciudad" sin que afecte la restricción dándole una
longitud de 15 caracteres.
85 - Agregar campos y restricciones (alter
table)
Podemos 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:
Agregamos a la tabla "libros", el campo "titulo" de tipo varchar(30) y una restricción "unique"
con índice agrupado:
Agregamos a la tabla "libros", el campo "codigo" de tipo int identity not null y una restricción
"primary key" con índice no agrupado:
Agregamos a la tabla "libros", el campo "precio" de tipo decimal(6,2) y una restricción "check":
86 - Campos calculados
Un campo calculado es un campo que no se almacena físicamente en la tabla. SQL Server
emplea una fórmula que detalla el usuario al definir dicho campo para calcular el valor según
otros campos de la misma tabla.
- insertarse ni actualizarse.
Puede ser empleado como llave de un índice o parte de restricciones "primary key" o "unique" si
la expresión que la define no cambia en cada consulta.
Creamos un campo calculado denominado "sueldototal" que suma al sueldo básico de cada
empleado la cantidad abonada por los hijos (100 por cada hijo):
Los campos de los cuales depende el campo calculado no pueden eliminarse, se debe eliminar
primero el campo calculado.
86 - Campos calculados
Primer problema:
Un comercio almacena los datos de los artículos para la venta en una tabla
denominada "articulos".
1- Elimine la tabla, si existe y créela nuevamente:
if object_id('articulos') is not null
drop table articulos;
Para darle un nombre a un tipo de dato definido por el usuario debe considerar las mismas reglas
que para cualquier identificador. No puede haber dos objetos con igual nombre en la misma base
de datos.
Para crear un tipo de datos definido por el usuario se emplea el procedimiento almacenado del
sistema "sp_addtype". Sintaxis básica:
Creamos un tipo de datos definido por el usuario llamado "tipo_documento" que admite valores
nulos:
Ejecutando el procedimiento almacenado "sp_help" junto al nombre del tipo de dato definido por
el usuario se obtiene información del mismo (nombre, el tipo de dato en que se basa, la longitud,
si acepta 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 los
tipos de datos:
El parámetro "futureonly" es opcional, especifica que si existen campos (de cualquier tabla) con
este tipo de dato, no se asocien a la regla; si creamos una nueva tabla con este tipo de dato, si
deberán cumplir la regla. Si no se especifica este parámetro, todos los campos de este tipo de
dato, 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 la
regla, 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.
Si asocia una regla a un campo cuyo tipo de dato definido por el usuario ya tiene una regla
asociada, la nueva regla se aplica al campo, pero el tipo de dato continúa asociado a la regla. La
regla asociada al campo prevalece sobre la asociada al tipo de dato. Por ejemplo, tenemos un
campo "precio" de un tipo de dato definido por el usuario "tipo_precio", este tipo de dato tiene
asociada una regla "RG_precio0a99" (precio entre 0 y 99), luego asociamos al campo "precio" la
regla "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
contra la 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
la columna "rule_name" se muestra el nombre de la regla asociada a dicho tipo de dato; muestran
"none" cuando no tiene regla asociada.
7- Cree la regla que permita valores integer desde 1990 (año en que se
inauguró el comercio) y el
año actual:
create rule RG_año
as @año between 1990 and datepart(year,getdate());
10- Cree la tabla "clientes" con 3 campos: nombre (30 caracteres), añoingreso
(tipo_año) y domicilio
(30 caracteres):
create table clientes(
documento char(8),
nombre varchar(30),
añoingreso tipo_año
);
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.
17- Intente agregar una fecha de ingreso fuera del intervalo que admite la
regla en cualquiera de
las tablas (ambas tienen la asociación):
insert into empleados values('33333333','Romina Guzman',1900);
Mensaje de error.
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;
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.
El parámetro "futureonly" es opcional, especifica que si existen campos (de cualquier tabla) con
este tipo de dato, no se asocien al valor predeterminado; si creamos una nueva tabla con este tipo
de dato, si estará asociado al valor predeterminado. Si no se especifica este parámetro, todos los
campos 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 valor
predeterminado asociado, el último lo reemplaza.
sp_unbindefault 'TIPODEDATODEFINIDOPORELUSUARIO';
Debe tener en cuenta que NO se puede aplicar una restricción "default" en un campo con un tipo
de datos definido por el usuario si dicho campo o tipo de dato tienen asociado un valor
predeterminado.
Si un campo de un tipo de dato definido por el usuario tiene una restricción "default" y luego se
asocia un valor predeterminado al tipo de dato, el valor predeterminado no queda asociado en el
campo 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
la columna "default_name" se muestra el nombre del valor predeterminado asociado a dicho tipo
de dato; muestra "none" cuando no tiene ningún valor predeterminado asociado.
5- Cree la tabla "empleados" con 3 campos: documento (char de 8), nombre (30
caracteres) y
añoingreso (tipo_año):
create table empleados(
documento char(8),
nombre varchar(30),
añoingreso tipo_año
);
10- Cree la tabla "clientes" con 3 campos: nombre (30 caracteres), añoingreso
(tipo_año) y domicilio
(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.
18- Ingrese un registro en ambas tablas con valores por defecto y vea qué se
almacenó en el año de
ingreso:
insert into empleados default values;
select *from empleados;
insert into clientes default values;
select *from clientes;
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:
Consultamos la tabla "systypes" para ver si existe el tipo de dato "tipo_documento", si es así, lo
eliminamos:
No se puede eliminar un tipo de datos definido por el usuario si alguna tabla (u otro objeto) hace
uso 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 reglas
y valores predeterminados, pero tales reglas y valores predeterminados, no se eliminan, siguen
existiendo en la base de datos.
5- Cree la regla que permita valores integer desde 1990 (fecha en que se
inauguró el comercio) y el
año actual:
create rule RG_año
as @año between 1990 and datepart(year,getdate());
91 - Subconsultas
Una 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 en
varios pasos lógicos y se obtiene el resultado con una única instrucción y cuando la consulta
depende de los resultados de otra consulta.
Generalmente, una subconsulta se puede reemplazar por combinaciones y estas últimas son más
eficientes.
- 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 el
mismo resultado que una combinación (join).
1. las que retornan un solo valor escalar que se utiliza con un operador de comparación o en lugar
de una expresión.
2. las que retornan una lista de valores, se combinan con "in", o los operadores "any", "some" y
"all".
3. los que testean la existencia con "exists".
- si el "where" de la consulta exterior incluye un campo, este debe ser compatible con el campo
en la lista de selección de la subconsulta.
- las subconsultas luego de un operador de comparación (que no es seguido por "any" o "all") no
pueden incluir cláusulas "group by" ni "having".
- una subconsulta puede estar anidada dentro del "where" o "having" de una consulta externa o
dentro de otra subconsulta.
- si una tabla se nombra solamente en un subconsulta y no en la consulta externa, los campos no
serán incluidos en la salida (en la lista de selección de la consulta externa).
Las subconsultas que retornan un solo valor escalar se utiliza con un operador de comparación o
en lugar de una expresión:
select CAMPOS
from TABLA
where CAMPO OPERADOR (SUBCONSULTA);
Si queremos saber el precio de un determinado libro y la diferencia con el precio del libro más
costoso, 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
conseguirlo en 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 del
libro y el máximo valor de precio.
Note que el campo del "where" de la consulta exterior es compatible con el valor retornado por la
expresión de la subconsulta.
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".
2- Créela con los campos necesarios. Agregue una restricción "primary key"
para el campo "documento"
y una "check" para validar que el campo "nota" se encuentre entre los valores
0 y 10:
create table alumnos(
documento char(8),
nombre varchar(30),
nota decimal(4,2),
primary key(documento),
constraint CK_alumnos_nota_valores check (nota>=0 and nota <=10),
);
4- Obtenga todos los datos de los alumnos con la nota más alta, empleando
subconsulta.
2 registros.
6- Muestre los alumnos que tienen una nota menor al promedio, su nota, y la
diferencia con el
promedio.
3 registros.
93 - Subconsultas con in
Vimos que una subconsulta puede reemplazar una expresión. Dicha subconsulta debe devolver
un valor escalar o una lista de valores de un campo; las subconsultas que retornan una lista de
valores 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
retorna resultados, la consulta exterior los usa.
Este ejemplo muestra los nombres de las editoriales que ha publicado libros de un determinado
autor:
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 la
consulta exterior luego emplea al recuperar los datos.
Una combinación (join) siempre puede ser expresada como una subconsulta; pero una
subconsulta no siempre puede reemplazarse por una combinación que retorne el mismo
resultado. Si es posible, 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í puede
verificar 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 una
subconsulta; 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');
93 - Subconsultas con in
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes",
también tiene una tabla
"ciudades" donde registra los nombres de las ciudades.
1- Elimine las tablas "clientes" y "ciudades", si existen:
if (object_id('ciudades')) is not null
drop table ciudades;
if (object_id('clientes')) is not null
drop table clientes;
Compara un valor escalar con los valores de un campo y devuelven "true" si la comparación con
cada valor de la lista de la subconsulta es verdadera, sino "false".
...VALORESCALAR OPERADORDECOMPARACION
ANY (SUBCONSULTA);
Queremos saber los títulos de los libros de "Borges" que pertenecen a editoriales que han
publicado también libros de "Richard Bach", es decir, si los libros de "Borges" coinciden con
ALGUNA 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 la
subconsulta 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
de la lista de la consulta externa se encuentran en la lista de valores devuelta por la consulta
interna.
Sintaxis:
Queremos saber si TODAS las editoriales que publicaron libros de "Borges" coinciden con
TODAS las 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 la
subconsulta 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.
Queremos saber si ALGUN precio de los libros de "Borges" es mayor a ALGUN precio de los
libros de "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 retornada
por la subconsulta; si ALGUNO cumple la condición, es decir, es mayor a ALGUN precio de
"Richard Bach", se lista.
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 retornada
por la subconsulta; si cumple la condición, es decir, si es mayor a TODOS los precios de
"Richard Bach" (o al mayor), se lista.
9- Muestre los deportes en los cuales el socio 2 pagó más cuotas que TODOS los
deportes en que se
inscribió el socio 1.
1 registro.
95 - Subconsultas correlacionadas
Un almacén almacena la información de sus ventas en una tabla llamada "facturas" en la cual
guarda el número de factura, la fecha y el nombre del cliente y una tabla denominada "detalles"
en la cual se almacenan los distintos items correspondientes a cada factura: el nombre del
artículo, el precio (unitario) y la cantidad.
Se necesita una lista de todas las facturas que incluya el número, la fecha, el cliente, la cantidad
de 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 total
from facturas as f;
El segundo "select" retorna una lista de valores de una sola columna con la cantidad de items por
factura (el número de factura lo toma del "select" exterior); el tercer "select" retorna una lista de
valores 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.
95 - Subconsultas correlacionadas
Primer problema:
Un club dicta clases de distintos deportes a sus socios. El club tiene una
tabla llamada
"inscriptos" en la cual almacena el número de "socio", el código del deporte
en el cual se inscribe
y la cantidad de cuotas pagas (desde 0 hasta 10 que es el total por todo el
año), y una tabla
denominada "socios" en la que guarda los datos personales de cada socio.
1- Elimine las tablas si existen:
if object_id('inscriptos') is not null
drop table inscriptos;
if object_id('socios') is not null
drop table socios;
2- Cree las tablas:
create table socios(
numero int identity,
documento char(8),
nombre varchar(30),
domicilio varchar(30),
primary key (numero)
);
96 - Exists y No Exists
Los operadores "exists" y "not exists" se emplean para determinar si hay o no datos en una lista
de valores.
Estos operadores pueden emplearse con subconsultas correlacionadas para restringir el resultado
de 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
no retornan registros).
Cuando se coloca en una subconsulta el operador "exists", SQL Server analiza si hay datos que
coinciden con la subconsulta, no se devuelve ningún registro, es como un test de existencia; SQL
Server termina la recuperación de registros cuando por lo menos un registro cumple la condición
"where" de la 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');
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');
96 - Exists y No Exists
Primer problema:
Un club dicta clases de distintos deportes a sus socios. El club tiene una
tabla llamada
"inscriptos" en la cual almacena el número de "socio", el código del deporte
en el cual se inscribe
y la cantidad de cuotas pagas (desde 0 hasta 10 que es el total por todo el
año), y una tabla
denominada "socios" en la que guarda los datos personales de cada socio.
1- Elimine las tablas si existen:
if object_id('inscriptos') is not null
drop table inscriptos;
if object_id('socios') is not null
drop table socios;
6- Muestre todos los datos de los socios que han pagado todas las cuotas.
1 registro.
Ver solución
97 - Subconsulta simil autocombinación
Algunas sentencias en las cuales la consulta interna y la externa emplean la misma tabla pueden
reemplazarse por una autocombinación.
Por ejemplo, queremos una lista de los libros que han sido publicados por distintas editoriales.
Otro ejemplo: Buscamos todos los libros que tienen el mismo precio que "El aleph" empleando
subconsulta:
select titulo
from libros
where titulo<>'El aleph' and
precio =
(select precio
from libros
where titulo='El aleph');
Buscamos los libros cuyo precio supere el precio promedio de los libros por editorial:
select l1.titulo,l1.editorial,l1.precio
from libros as l1
where l1.precio >
(select avg(l2.precio)
from libros as l2
where l1.editorial= l2.editorial);
Por cada valor de l1, se evalúa la subconsulta, si el precio es mayor que el promedio.
2- Cree la tabla:
create table deportes(
nombre varchar(15),
profesor varchar(30),
dia varchar(10),
cuota decimal(5,2),
);
6- Buscamos todos los deportes que se dictan el mismo día que un determinado
deporte (natacion)
empleando subconsulta.
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 sintaxis
básica es la siguiente:
select ALIASdeTABLADERIVADA.CAMPO
from (TABLADERIVADA) as ALIAS;
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 y será 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 el
monto 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.
La subconsulta es una combinación que retorna una lista de valores que la consulta externa
emplea al seleccionar los registros para la eliminación.
5- Elimine todas las inscripciones de los socios que deben alguna matrícula.
5 registros eliminados.
Ver solución
Un profesor almacena las notas de sus alumnos en una tabla llamada "alumnos". Tiene otra tabla
llamada "aprobados", con algunos campos iguales a la tabla "alumnos" pero en ella solamente
almacenará los alumnos que han aprobado el ciclo.
Entonces, se puede insertar registros en una tabla con la salida devuelta por una consulta a otra
tabla; para ello escribimos la consulta y le anteponemos "insert into" junto al nombre de la tabla
en la cual ingresaremos los registros y los campos que se cargarán (si se ingresan todos los
campos no es necesario listarlos).
La cantidad de columnas devueltas en la consulta debe ser la misma que la cantidad de campos a
cargar en el "insert".
Se pueden insertar valores en una tabla con el resultado de una consulta que incluya cualquier
tipo de "join".
2-Créelas:
create table clientes(
codigo int identity,
nombre varchar(30),
domicilio varchar(30),
primary key(codigo)
);
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" que
contenga los nombres de las editoriales.
La tabla "editoriales", que no existe, contendrá solamente un campo llamado "nombre". La tabla
libros contiene varios registros.
Podemos crear la tabla "editoriales" con el campo "nombre" consultando la tabla "libros" y en el
mismo momento insertar la información:
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
los campos listados de la tabla consultada; si se quiere dar otro nombre a los campos de la nueva
tabla se deben especificar alias.
Podemos emplear "group by", funciones de agrupamiento y "order by" en las consultas. También
podemos emplear "select... into" con combinaciones, para crear una tabla que contenga datos de
2 o más tablas.
6-Cree una tabla llamada "secciones" que contenga las secciones de la empresa
(primero elimínela, si
existe):
if object_id('secciones') is not null
drop table secciones;
10- Se necesita una tabla llamada "maximossueldos" que contenga los mismos
campos que "empleados" y
guarde los 3 empleados con sueldos más altos. Primero eliminamos, si existe,
la tabla
"maximossueldos":
if object_id('maximossueldos') is not null
drop table maximossueldos;
select top 3 *
into maximossueldos
from empleados
order by sueldo;
12- Se necesita una nueva tabla llamada "sucursalCordoba" que contenga los
nombres y sección de los
empleados de la ciudad de Córdoba. En primer lugar, eliminamos la tabla, si
existe. Luego, consulte
las tablas "empleados" y "sucursales" y guarde el resultado en la nueva tabla:
if object_id('sucursalCordoba') is not null
drop table sucursalCordoba;
select nombre,ciudad
into sucursalCordoba
from empleados
join sucursales
on codigosucursal=codigo
where ciudad='Cordoba';
102 - go
Esto solo se aplica cuando instale el SQL Server en su máquina.
Habrá notado que no se puede ejecutar un procedimiento almacenado luego de otras sentencias a
menos que se incluya "execute" (o "exec").
muestra un mensaje de error porque no puede procesar ambas sentencias como un solo lote. Para
que no ocurra debemos tipear:
Las siguientes sentencias no pueden ejecutarse en el mismo lote: create rule, create default,create
view, create procedure, create trigger. Cada una de ellas necesita ejecutarse separándolas con
"go". Por ejemplo:
create table....
go
create rule...
go
Recuerde 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 y
ejecute los comandos desde el Query Analyzer.
103 - Vistas
Una vista es una alternativa para mostrar datos de varias tablas. Una vista es como una tabla
virtual que almacena una consulta. Los datos accesibles a través de la vista no están almacenados
en la base de datos como un objeto.
Entonces, una vista almacena una consulta como un objeto para utilizarse posteriormente. Las
tablas consultadas en una vista se llaman tablas base. En general, se puede dar un nombre a
cualquier consulta y almacenarla como una vista.
Una vista suele llamarse también tabla virtual porque los resultados que retorna y la manera de
referenciarlas es la misma que para una tabla.
- simplificar la administración de los permisos de usuario: se pueden dar al usuario permisos para
que solamente pueda acceder a los datos a través de vistas, en lugar de concederle permisos para
acceder a ciertos campos, así se protegen las tablas base de cambios en su estructura.
Los nombres para vistas deben seguir las mismas reglas que cualquier identificador. Para
distinguir una tabla de una vista podemos fijar una convención para darle nombres, por ejemplo,
colocar el sufijo “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 debe
colocar 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 no lo hubiésemos hecho aparecería un mensaje de error porque dicha expresión DEBE
tener un encabezado, 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
el ejemplo, al campo "s.nombre" le colocamos un alias porque ya había un encabezado (el alias
de la concatenación) llamado "nombre" y no pueden repetirse, si sucediera, aparecería un
mensaje de error.
La diferencia es que se colocan entre paréntesis los encabezados de las columnas que aparecerán
en la vista. Si no los colocamos y empleamos la sintaxis vista anteriormente, se emplean los
nombres de los campos o alias (que en este caso habría que agregar) colocados en el "select" que
define la vista. Los nombres que se colocan entre paréntesis deben ser tantos como los campos o
expresiones que se definen en la vista.
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 para
asegurarnos que el resultado que retorna es el imaginado.
- no puede incluir las cláusulas "compute" ni "compute by" ni la palabra clave "into";
7- Muestre (consultando la vista) los cursos (deporte y día) para los cuales
no hay inscriptos.
8- Muestre los nombres de los socios que no se han inscripto en ningún curso
(consultando la vista)
11- Consulte la vista y muestre los nombres de los profesores y los días en
que asisten al club para
dictar sus clases.
"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 enviamos
como argumento el nombre de una vista, obtenemos la fecha de creación, propietario, los campos
y demás información.
"sp_helptext" seguido del nombre de una vista nos muestra el texto que la define, excepto si ha
sido 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
sp_depends vista_empleados;
aparecen las tablas (y demás objetos) de las cuales depende la vista, es decir, las tablas
referenciadas en la misma.
sp_depends empleados;
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:
sp_helptext NOMBREVISTA;
Podemos ocultar el texto que define una vista empleando la siguiente sintaxis al crearla:
"with encryption" indica a SQL Server que codifique las sentencias que definen la vista.
Si se elimina una tabla a la que hace referencia una vista, la vista no se elimina, hay que
eliminarla explícitamente.
La vista definida anteriormente muestra solamente algunos de los datos de los empleados de la
sección "Administracion". Además, solamente se permiten modificaciones a los empleados de
esa sección.
Podemos actualizar el nombre, apellido y sexo a través de la vista, pero no el campo "seccion"
porque está restringuido.
6- Consulte la vista:
select *from vista_clientes;
108 - Vistas (modificar datos de una tabla a
través de vistas)
Si 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 en
cuenta 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 que
combina varias tablas pero la modificación solamente debe afectar a una sola tabla.
- pueden generar errores si afectan a campos a las que la vista no hace referencia. Por ejemplo, si
se ingresa un registro en una vista que consulta una tabla que tiene campos not null que no están
incluidos en la vista.
- la opción "with check option" obliga a todas las instrucciones de modificación que se ejecutan
en la 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 la
definicion de la misma.
4- Realice un join para mostrar todos los datos de todas las tablas, sin
repetirlos:
select documento,nombre,domicilio,c.numero,deporte,dia, profesor,matricula
from socios as s
join inscriptos as i
on s.documento=documentosocio
join cursos as c
on c.numero=i.numero;
Con "alter view" se modifica la definición de una vista sin afectar los procedimientos
almacenados y los permisos. Si elimina una vista y vuelve a crearla, debe reasignar los permisos
asociados a ella.
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 al
ejecutar "create view"; debe alterar la vista.
6- Consulte la vista:
select *from vista_deudores;
17- Cree la vista "vista_socios" que muestre todos los campos de la tabla
"socios".
110 - Lenguaje de control de flujo (case)
La 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
end
Por 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 ejecuta
el "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" que
consta de los siguientes campos:
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 un valor:
- 0, 1, 2 ó 3: 'libre';
- 4, 5 ó 6: 'regular';
- 7, 8, 9 ó 10: 'promocionado';
Esta es la sentencia:
Note que cada "where" compara un valor puntual, por ello los valores devueltos son iguales para
algunos casos. Note que como omitimos la parte "else", en caso que el valor no encuentre
coincidencia con ninguno valor "when", retorna "null".
case
when VALORACOMPARAR OPERADOR VALOR1 then RESULTADO1
when VALORACOMPARAR OPERADOR VALOR2 then RESULTADO2
...
else RESULTADO3
end
Mostramos los nombres de los alumnos y en una columna extra llamada "resultado" empleamos
un case que teste si la nota es menor a 4, está entre 4 y 7 o supera el 7:
Puede utilizar una expresión "case" en cualquier lugar en el que pueda utilizar una expresión.
2- Cree la tabla:
create table empleados(
documento char(8) not null,
nombre varchar(30) not null,
sexo char(1),
fechanacimiento datetime,
fechaingreso datetime,
cantidadhijos tinyint,
sueldo decimal(5,2),
primary key(documento)
);
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 ser
ejecutado si una condición se cumple y si no se cumple, se debe ejecutar otro bloque de
sentencias diferente.
- "while": ejecuta repetidamente una instrucción siempre que la condición sea verdadera.
Veamos un ejemplo. Tenemos nuestra tabla "libros"; queremos mostrar todos los títulos de los
cuales no hay libros disponibles (cantidad=0), si no hay, mostrar un mensaje indicando tal
situación:
Note que si la condición es verdadera, se deben ejecutar 2 sentencias. Por lo tanto, se deben
encerrar en un bloque "begin...end".
En el siguiente ejemplo eliminamos los libros cuya cantidad es cero; si no hay, mostramos un
mensaje:
2- Cree la tabla:
create table empleados(
documento char(8) not null,
nombre varchar(30) not null,
sexo char(1),
fechanacimiento datetime,
sueldo decimal(5,2),
primary key(documento)
);
Segundo problema:
Un teatro con varias salas guarda la información de las entradas vendidas en
una tabla llamada
"entradas".
1- Elimine la tabla, si existe:
if object_id('entradas') is not null
drop table entradas;
2- Cree la tabla:
create table entradas(
sala tinyint,
fechahora datetime,
capacidad smallint,
entradasvendidas smallint,
primary key(sala,fechahora)
);
Ver solución
Las variables de usuario son específicas de cada conexión y son liberadas automáticamente al
abandonar la conexión.
Las variables de usuario comienzan con "@" (arroba) seguido del nombre (sin espacios), dicho
nombre puede contener cualquier caracter.
Una variable debe ser declarada antes de usarse. Una variable local se declara así:
colocando "declare" el nombre de la variable que comienza con el símbolo arroba (@) y el tipo
de dato. Ejemplo:
Una variable declarada existe dentro del entorno en que se declara; debemos declarar y emplear
la variable en el mismo lote de sentencias, porque si declaramos una variable y luego, en otro
bloque de sentencias pretendemos emplearla, dicha variable ya no existe. Por ejemplo, si
ejecutamos estas sentencias en diferentes lotes:
Debemos tipear:
set @edad=45
Para almacenar un valor en una variable se coloca el signo igual (=) entre la variable y el valor a
asignar.
select @nombre;
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
una librería. Para ello podemos emplear una variable para almacenar el precio más alto:
declare @mayorprecio
select @mayorprecio:=max(precio) from libros
y 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
de un tipo de dato definido por el usuario.
2- Créelas con los campos necesarios. Agregue una restricción "primary key"
para el campo
"documento" y una restricción "foreign key" para que en la tabla "notas" el
documento del alumno
haga referencia al documento de la tabla "alumnos":
create table alumnos(
documento char(8) not null
constraint CK_alumnos_documento check (documento like '[0-9][0-9][0-9][0-9]
[0-9][0-9][0-9][0-9]'),
nombre varchar(30),
constraint PK_alumnos
primary key(documento)
);
113 - Tipos de datos text, ntext y image
Los tipos de datos "ntext", "text" e "image" representan tipos de datos de longitud fija y variable
en los que se pueden guardar gran cantidad de información, caracteres unicode y no unicode y
datos binarios.
"image" es un tipo de dato de longitud variable que puede contener de 0 a 2000000000 bytes (2
GB) 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 caso
de los tipos "char", o "varchar".
Como estos tipos de datos tiene gran tamaño, SQL Server los almacena fuera de los registros, en
su 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 campo
seguido del tipo de dato:
...
NOMBRECAMPO text
....
- Se pueden asociar valores predeterminados pero no reglas a campos de estos tipos de datos.
7- Intente alterar el campo de tipo "text" para que no acepte valores nulos:
alter table visitas
alter column comentarios text not null;
No lo permite.
13- Ingrese un registro con valores por defecto y recupere todos los
registros:
insert into visitas default values;
select *from visitas;
15- Cree un valor por defecto que almacene el valor "Sin comentarios":
create default VP_Sincomentarios
as 'Sin comentarios';
17- Ingrese un registro con valores por defecto y recupere todos los
registros:
insert into visitas default values;
select *from visitas;
Ver solución
La función "textptr" devuelve el valor del puntero a texto que corresponde al campo text, ntext o
image; tal valor puede emplearse para manipular los datos de este tipo, con las funciones para
leer, escribir y actualizar.
Sintaxis:
textptr(CAMPO);
En el campo de tipo "text" no se almacenan los datos sino la dirección en la cual se encuentran
los datos. Podemos ver esa dirección tipeando la siguiente sentencia:
Si la consulta retorna más de un registro, "textptr" retorna un puntero a texto del último registro
devuelto.
Los argumentos son: el nombre de la tabla y campo y el nombre del puntero a texto que se va a
controlar. Retorna 1 si el puntero es válido y 0 si no lo es. No se puede emplear "updatetext",
"writetext" y "readtext" si el puntero no es válido.
La siguiente consulta muestra si los punteros son válidos en cada registro del campo "sinopsis"
de la tabla "libros":
select titulo,
textvalid('libros.sinopsis', textptr(sinopsis)) as 'Puntero valido'
from libros;
Solo disponemos punto y coma al final para que SQL Server ejecute todas las instrucciones en
un solo lote y exista la variable @puntero.
Analicemos la sintaxis:
- DESPLAZAMIENTO: número de bytes (para text o image) o caracteres (ntext) que se mueve
el puntero antes de comenzar a leer.
Leemos la información almacenada en el campo "sinopsis" de "libros" del registro con código 2,
desde la posición 9, 50 caracteres:
116 - Tipo de dato text - ntext e image
(escribir)
La función "writetext" sobreescribe (reemplaza) el texto de un campo "text", "ntext" o "image".
No puede emplearse en vistas.
Sintaxis:
Este ejemplo coloca el puntero a texto en una variable "@puntero" y luego "writetext" almacena
el nuevo texto en el registro apuntado por "@puntero":
Recuerde que si al insertar registros se ingresa un valor "null" en un campo "text", "ntext" o
"image" o no se ingresan datos, no se crea un puntero válido y al intentar escribir dicho campo
ocurre un error, porque la función "writetext" requiere un puntero válido. Para evitarlo podemos
chequer el puntero antes de pasárselo a la función de escritura:
Para actualizar campos de estos tipos también empleamos "updatetext", que permite cambiar una
porción del campo (o todo el campo). La sintaxis básica es la siguiente:
Analizamos la sintaxis:
- 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 la cantidad de bytes (para campos text e image) o caracteres (para campos ntext) que
debe moverse el 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.
- 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 del puntero que apunta al tipo de dato text, ntext o image (retornado por la función
"textptr"), de esta forma:
TABLA.CAMPO PUNTERO;
Tenemos la tabla libros, con un campo de tipo text llamado "sinopsis"; hay un registro cargado
con el 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:
Entonces, declaramos una variable llamada "@puntero"; guardamos en la variable el valor del
puntero, 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, no
borramos ningún byte y colocamos el texto a agregar; el campo ahora contendrá "Para aprencer
PHP 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 queremos
actualizar 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 texto al campo "sinopsis" del libro con código 1 de la tabla "ofertas"; finalmente
actualizamos el registro de "ofertas" con el texto de "libros".
Entonces, se emplea "updatetext" para modificar datos de campos de tipo text, ntext e image,
pudiendo cambiar una porción del texto.
Con este tipo de datos también puede utilizarse "like", pero "like" solamente puede incluirse en
la cláusula "where".
select titulo,substring(sinopsis,1,20)
from libros;
1) del sistema: están almacenados en la base de datos "master" y llevan el prefijo "sp_"; permiten
recuperar información de las tablas del sistema y pueden ejecutarse en cualquier base de datos.
3) temporales: pueden ser locales, cuyos nombres comienzan con un signo numeral (#), o
globales, cuyos nombres comienzan con 2 signos numeral (##). Los procedimientos almacenados
temporales locales están disponibles en la sesión de un solo usuario y se eliminan
automáticamente al finalizar la sesión; los globales están disponibles en las sesiones de todos los
usuarios.
Al crear un procedimiento almacenado, las instrucciones que contiene se analizan para verificar
si son correctas sintácticamente. Si no se detectan errores, SQL Server guarda el nombre del
procedimiento almacenado en la tabla del sistema "sysobjects" y su contenido en la tabla del
sistema "syscomments" en la base de datos activa. Si se encuentra algún error, no se crea.
Ventajas:
- comparten la lógica de la aplicación con las otras aplicaciones, con lo cual el acceso y las
modificaciones de los datos se hacen en un solo sitio.
- permiten realizar todas las operaciones que los usuarios necesitan evitando que tengan acceso
directo a las tablas.
- reducen el tráfico de red; en vez de enviar muchas instrucciones, los usuarios realizan
operaciones enviando una única instrucción, lo cual disminuye el número de solicitudes entre el
cliente y el servidor.
En primer lugar se deben tipear y probar las instrucciones que se incluyen en el procedimiento
almacenado, luego, si se obtiene el resultado esperado, se crea el procedimiento.
Los procedimientos almacenados pueden hacer referencia a tablas, vistas, a funciones definidas
por el usuario, a otros procedimientos almacenados y a tablas temporales.
Si un procedimiento almacenado crea una tabla temporal, dicha tabla sólo existe dentro del
procedimiento y desaparece al finalizar el mismo. Lo mismo sucede con las variables.
Para diferenciar los procedimientos almacenados del sistema de los procedimientos almacenados
locales use un prefijo diferente a "sp_" cuando les de el nombre.
exec pa_libros_limite_stock;
Cuando realizamos un ejercicio nuevo, siempre realizamos las mismas tareas: eliminamos la
tabla si existe, la creamos y luego ingresamos algunos registros. Podemos crear un
procedimiento almacenado que contenga todas estas instrucciones:
Y luego lo ejecutamos cada vez que comenzamos un nuevo ejercicio y así evitamos tipear tantas
sentencias:
exec pa_crear_libros;
Si el procedimiento que queremos eliminar no existe, aparece un mensaje de error, para evitarlo,
podemos emplear esta sintaxis:
Se recomienda ejecutar el procedimiento almacenado del sistema "sp_depends" para ver si algún
objeto depende del procedimiento que deseamos eliminar.
Podemos eliminar una tabla de la cual dependa un procedimiento, SQL Server lo permite, pero
luego, al ejecutar el procedimiento, aparecerá un mensaje de error porque la tabla referenciada no
existe.
Los parámetros se definen luego del nombre del procedimiento, comenzando el nombre con un
signo arroba (@). Los parámetros son locales al procedimiento, es decir, existen solamente
dentro del 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).
Creamos un procedimiento que recibe el nombre de un autor como parámetro para mostrar todos
los libros del autor solicitado:
Cuando pasamos valores con el nombre del parámetro, el orden en que se colocan puede
alterarse.
No podríamos ejecutar el procedimiento anterior sin valores para los parámetros. Si queremos
ejecutar un procedimiento que permita omitir los valores para los parámetros debemos, al crear
el procedimiento, definir valores por defecto para cada parámetro:
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 sin
especificar 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 puede
interrumpir la secuencia.
16- Ejecute el procedimiento sin enviar parámetro para que tome el valor por
defecto.
Muestra los 5 registros.
Ver solución
Los parámetros de salida pueden ser de cualquier tipo de datos, excepto text, ntext e image.
Declaramos una variable para guardar el valor devuelto por el procedimiento; ejecutamos el
procedimiento enviándole 2 valores y mostramos el resultado.
La instrucción que realiza la llamada al procedimiento debe contener un nombre de variable para
almacenar el valor retornado.
Creamos un procedimiento almacenado que muestre los títulos, editorial y precio de los libros de
un determinado autor (enviado como parámetro de entrada) y nos retorne la suma y el promedio
de los precios de todos los libros del autor enviado:
Ejecutamos el procedimiento y vemos el contenido de las variables en las que almacenamos los
parámetros de salida del procedimiento:
Creamos un procedimiento que muestre todos los libros de un autor determinado que se ingresa
como parámetro. Si no se ingresa un valor, o se ingresa "null", se muestra un mensaje y se sale
del procedimiento:
Creamos un procedimiento almacenado que ingresa registros en la tabla "libros". Los parámetros
correspondientes al título y autor DEBEN ingresarse con un valor distinto de "null", los demás
son opcionales. El procedimiento retorna "1" si la inserción se realiza, es decir, si se ingresan
valores para título y autor y "0", en caso que título o autor sean nulos:
Para ver el resultado, debemos declarar una variable en la cual se almacene el valor devuelto por
el procedimiento; luego, ejecutar el procedimiento asignándole el valor devuelto a la variable,
finalmente mostramos el contenido de la variable:
11- Ejecute los mismos pasos, pero esta vez envíe solamente un valor para el
parámetro "documento".
Retorna "0", lo que indica que el registro no fue actualizado.
- "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 un
procedimiento 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 que
define el procedimiento, excepto si ha sido encriptado.
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 los
objetos que dependen del objeto nombrado. Por ejemplo, ejecutamos "sp_depends" seguido del
nombre de un procedimiento:
sp_depends pa_autor_promedio;
aparecen las tablas (y demás objetos) de las cuales depende el procedimiento, es decir, las tablas
referenciadas en el mismo. Podemos ejecutar el procedimiento seguido del nombre de una tabla:
sp_depends libros;
- La tabla del sistema "sysobjects": 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 un procedimiento almacenado,
muestra "P". Ejemplo:
Si queremos ver todos los procedimientos almacenados creados por nosotros, podemos tipear:
Si no quiere que los usuarios puedan leer el contenido del procedimiento podemos indicarle a
SQL Server que codifique la entrada a la tabla "syscomments" que contiene el texto. Para ello,
debemos colocar la opción "with encryption" al crear el procedimiento:
Si quiere modificar un procedimiento que se creó con la opción "with encryption" y quiere
conservarla, debe incluirla al alterarlo.
6- Cree el procedimiento para que seleccione todos los datos de los alumnos
cuya nota es igual o
superior a 4.
Creamos un procedimiento almacenado que reciba 2 números enteros y nos retorne el producto
de los mismos:
Creamos otro procedimiento que nos retorne el factorial de un número, tal procedimiento llamará
al procedimiento "pa_multiplicar":
Cuando un procedimiento (A) llama a otro (B), el segundo (B) tiene acceso a
todos los objetos que cree el primero (A).
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 de
ejecución para el procedimiento sino que lo compile cada vez que se ejecute.
En este caso la sintaxis es la siguiente:
Podemos crear todos los procedimientos que necesitemos para que realicen todas las operaciones
y consultas.
131 - Procedimientos Almacenados (con join)
Primer problema:
Una librería almacena los datos de los libros en una tabla denominada "libros"
y en una tabla
"ventas" las ventas de los mismos.
1- Elimine las tablas si existen y créelas:
if (object_id('libros')) is not null
drop table libros;
if (object_id('ventas')) is not null
drop table ventas;
5- Ejecute el procedimiento:
pa_ventas;
7- Cree un procedimiento que permita ingresar una venta en "ventas" con los
siguientes datos: código
del libro y cantidad que se vende. El procedimiento debe controlar que haya
libros disponibles (es
decir, que la cantidad que se vende sea mayor o igual a la cantidad existente
del libro) y luego
restar la cantidad vendida de la tabla "libros":
create procedure pa_vender
@codigo int=null,
@cantidad int=1
as
--verificamos que el código exista
if not exists (select *from libros where codigo=@codigo) or (@codigo is
null)
select 'Ingrese un codigo de libro válido'
else
begin --verificamos que haya stock
declare @disponibles int
select @disponibles= cantidad from libros where codigo=@codigo
if (@disponibles<@cantidad)
select 'Solo hay '+cast(@disponibles as varchar(10))+' disponibles'
else
begin
declare @precio decimal(6,2)
select @precio= precio from libros where codigo=@codigo
insert into ventas values(@codigo,@precio,@cantidad)
update libros set cantidad=cantidad-@cantidad where @codigo=codigo
end
end;
Pueden ser locales (son visibles sólo en la sesión actual) o globales (visibles por todas las
sesiones).
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.
Para referenciarla en otras consultas, se debe incluir el numeral(#), que es parte del nombre. Por
ejemplo:
Una tabla temporal no puede tener una restricción "foreign key" ni ser indexada, tampoco puede
ser 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.
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:
133 - Funciones
SQL Server ofrece varios tipos de funciones para realizar distintas operaciones. Hemos visto y
empleado varias de ellas.
Se pueden emplear las funciones del sistema en cualquier lugar en el que se permita una
expresión en una sentencia "select".
- deterministicas: siempre retornan el mismo resultado si se las invoca enviando el mismo valor
de entrada. 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 mismo
valor 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 propias
funciones.
Sabemos que una función es un conjunto de sentencias que operan como una unidad lógica, una
rutina que retorna un valor. Una función tiene un nombre, acepta parámetros de entrada y retorna
un valor escalar o una tabla.
Los parámetros de entrada pueden ser de cualquier tipo, excepto timestamp, cursor y table.
No todas las sentencias SQL son válidas dentro de una función. NO es posible emplear en ellas
funciones no determinadas (como getdate()) ni sentencias de modificación o actualización de
tablas o vistas. Si podemos emplear sentencias de asignación, de control de flujo (if), de
modificación y eliminación de variables locales.
SQL Server admite 3 tipos de funciones definidas por el usuario clasificadas según el valor
retornado:
Las funciones definidas por el usuario se crean con la instrucción "create function" y se eliminan
con "drop function".
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):
Luego del nombre se colocan (opcionalmente) los parámetros de entrada con su tipo.
El cuerpo de la función, se define en un bloque "begin...end" que contiene las instrucciones que
retornan 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:
select dbo.f_promedio(5.5,8.5);
Si llamamos a la función anterior sin enviarle los valores para los parámetros:
select dbo.f_promedio();
Creamos una función a la cual le enviamos una fecha y nos retorna el nombre del mes en
español:
Luego de los parámetros de entrada se indica el tipo de dato que retorna luego de "returns"; luego
de "as" comienza el bloque "begin...end" dentro del cual se encuentran las instrucciones de
procesamiento y el valor retornado luego de "return".
Las funciones que retornan un valor escalar pueden emplearse en cualquier consulta donde se
coloca un campo.
Recuerde que al invocar una función escalar, se debe especificar el propietario y el nombre de la
función:
select nombre,
dbo.f_nombreMes(fechaingreso) as 'mes de ingreso'
from empleados;
No olvide que cuando invocamos funciones que tienen definidos parámetros de entrada
DEBEMOS suministrar SIEMPRE un valor para él.
Podemos colocar un valor por defecto al parámetro, pero al invocar la función, para que tome el
valor por defecto DEBEMOS especificar "default". Por ejemplo, si llamamos a la función
anterior sin enviarle un valor:
select dbo.f_nombreMes();
Para que tome el valor por defecto debemos enviar "default" como argumento:
select dbo.f_nombreMes(default);
5- Cree la función "f_nombreDia" que recibe una fecha (tipo string) y nos
retorne el nombre del día
en español.
7- Cree la función "f_horario" que recibe una fecha (tipo string) y nos
retorne la hora y minutos.
9- Cree la función "f_fecha" que recibe una fecha (tipo string) y nos retorne
la fecha (sin hora ni
minutos)
10- Muestre todas las consultas del médico llamado 'Alfredo Acosta',
incluyendo el día (emplee la
función "f_nombreDia", la fecha (emplee la función "f_fecha"), el horario
(emplee la función
"f_horario") y el nombre del paciente.
11- Muestre todos los turnos para el día sábado, junto con la fecha, de todos
los médicos.
Segundo problema:
Una empresa almacena datos de sus empleados en una tabla denominada
"empleados".
1- Elimine la tabla si existe y créela con la siguiente estructura:
if object_id('empleados') is not null
drop table empleados;
create table empleados(
documento char(8) not null,
nombre varchar(30),
fechanacimiento datetime,
fechaingreso datetime,
telefono char(12),
mail varchar(50)
);
9- Llame a la función para que tome el valor por defecto del segundo
argumento.
11- Cree una función para reemplazar un valor "null" por el texto "No tiene".
Ver solución
También es similar a una vista; pero en las vistas solamente podemos emplear "select", mientras
que en funciones definidas por el usuario podemos incluir sentencias como "if", llamadas a
funciones, procedimientos, etc.
Sintaxis:
Como 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
datos a 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 las
instrucciones 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ón retorna una tabla con el codigo, título, autor y precio de todos los libros cuyo precio sea
inferior al parámetro:
Las funciones que retornan una tabla pueden llamarse sin especificar propietario:
Dijimos que este tipo de función puede ser referenciada en el "from" de una consulta; la
siguiente consulta realiza un join entre la tabla "libros" y la tabla retornada por la función
"f_ofertas":
Se puede llamar a la función como si fuese una tabla o vista listando algunos campos:
5- Cree una función que reciba como parámetro el texto "total" o "parcial" y
muestre, en el primer
caso, todos los datos de los empleados y en el segundo caso (si recibe el
valor "parcial"): el
documento, apellido, ciudad y año de nacimiento.
137 - Funciones con valores de tabla en línea
Una función con valores de tabla en línea retorna una tabla que es el resultado de una única
instrucción "select".
Es similar a una vista, pero más flexible en el empleo de parámetros. En una vista no se puede
incluir un parámetro, lo que hacemos es agregar una cláusula "where" al ejecutar la vista. Las
funciones con valores de tabla en línea funcionan como una vista con parámetros.
Sintaxis:
Como todas las funciones definidas por el usuario, se crea con "create function" seguido del
nombre que le damos a la función; luego declaramos los parámetros de entrada con su tipo de
dato 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 a
retornar porque queda establecido en el "select".
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:
Recuerde a que todas las funciones que tienen definidos parámetros se les DEBE suministrar
valores 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.
Las funciones definidas por el usuario pueden modificarse con la instrucción "alter function".
Sintaxis general:
Sintaxis para modificar una función de varias instrucciones que retorna una tabla:
Veamos un ejemplo. Creamos una función que retorna una tabla en línea:
Para ello debemos agregar al crearlas la opción "with encryption" antes de "as".
En funciones escalares:
En funciones de tabla de varias sentencias se coloca luego del formato de la tabla a retornar:
Veamos un ejemplo:
- "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 "scalar
function" 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 el
propietario, el tipo de función y la fecha de creación; si es una función de tabla, los campos de la
tabla retornada.
- "sp_helptext": seguido del nombre de una función definida por el usuario nos muestra el texto
que define la función, excepto si ha sido encriptado.
- "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)
y 2) nombre y tipo de los objetos que dependen del objeto nombrado (que lo referencian). Por
ejemplo, 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
no existe ningún objeto que la referencie.
sp_depends libros;
aparecen las funciones (y demás objetos) que dependen de ella (que la referencian). No aparecen
objetos 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 base
de datos actual. La columna "xtype" indica el tipo de objeto. Si es una función definida por el
usuario escalar, muestra "FN", si es una función de tabla de varias sentencias, muestra "TF" y si
es una 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 el
usuario, podemos tipear:
select name,xtype as tipo,crdate as fecha
from sysobjects
where xtype in ('FN','TF','IF');
Se crean para conservar la integridad referencial y la coherencia entre los datos entre distintas
tablas.
Si se intenta modificar (agregar, actualizar o eliminar) datos de una tabla en la que se definió un
disparador para alguna de estas acciones (inserción, actualización y eliminación), el disparador
se ejecuta (se dispara) en forma automática.
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
se ha definido un disparador, el disparador se ejecuta automáticamente.
- son apropiados para mantener la integridad de los datos, no para obtener resultados de
consultas.
Los disparadores, a diferencia de las restricciones "check", pueden hacer referencia a campos de
otras tablas. Por ejemplo, puede crearse un trigger de inserción en la tabla "ventas" que
compruebe 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 nuevo
registro en "ventas" no se realice.
Los triggers se crean con la instrucción "create trigger". Esta instrucción especifica la tabla en la
que se define el disparador, los eventos para los que se ejecuta y las instrucciones que contiene.
Sintaxis básica:
Analizamos la sintaxis:
- "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 que
activará el trigger. Puede ser "insert", "update" o "delete". Debe colocarse al menos UNA acción,
si se coloca más de una, deben separarse con comas.
- luego de "as" viene el cuerpo del trigger, se especifican las condiciones y acciones del
disparador; es decir, las condiciones que determinan cuando un intento de inserción,
actualización o 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 a objetos
de otra base de datos.
- 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 "insert
trigger" para una tabla que ya tiene otro "insert trigger".
Analizamos la sintaxis:
"create trigger" junto al nombre del disparador; "on" seguido del nombre de la tabla para la cual
se establece el trigger.
Luego de "for" se coloca el evento (en este caso "insert"), lo que indica que las inserciones sobre
la tabla activarán el trigger.
Luego de "as" se especifican las condiciones y acciones, es decir, las condiciones que determinan
cuando 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 se
intenta vender sea menor o igual al stock del libro y actualiza el campo "stock" de "libros",
restando al valor anterior la cantidad vendida:
Dentro del trigger se puede acceder a esta tabla virtual "inserted" que contiene todos los registros
insertados, es lo que hicimos en el disparador creado anteriormente, lo que solicitamos es que se
le reste al "stock" de "libros", la cantidad ingresada en el nuevo registro de "ventas", valor que
recuperamos de la tabla "inserted".
"rollback transaction" es la sentencia que deshace la transacción, es decir, borra todas las
modificaciones que se produjeron en la última transacción restableciendo todo al estado anterior.
Para identificar fácilmente los disparadores de otros objetos se recomienda usar un prefijo y
darles el nombre de la tabla para la cual se crean junto al tipo de acción.
4- Cree un disparador para que se ejecute cada vez que una instrucción
"insert" ingrese datos en
"empleados"; el mismo debe verificar que el sueldo del empleado no sea mayor
al sueldo máximo
establecido para la sección, si lo es, debe mostrar un mensaje indicando tal
situación y deshacer la
transacción.
Segundo problema:
Un club de barrio almacena los datos de sus socios en una tabla llamada
"socios", los datos de las
inscripciones en una tabla denominada "inscriptos" y en una tabla "morosos"
almacena el documento de
los socios inscriptos que deben matrícula.
1- Elimine 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;
11- Realice la inscripción de un socio que deba matrículas con el valor 's'
para "matricula".
El disparador "dis_inscriptos_insertar" se ejecuta y no permite la
transacción; el disparador
"dis_inscriptos_insertar2" no llega a ejecutarse.
12- Realice la inscripción de un socio que deba matrículas con el valor 'n'
para "matricula".
El disparador "dis_inscriptos_insertar" se ejecuta y no permite la
transacción; el disparador
"dis_inscriptos_insertar2" no llega a ejecutarse.
13- Creamos un disparador sobre la tabla "socios" para que no permita ingresar
nuevos socios. El
mismo debe mostrar un mensaje al dispararse y deshacer la transacción.
Ver solución
Sintaxis básica:
Analizamos la sintaxis:
"create trigger" junto al nombre del disparador; "on" seguido del nombre de la tabla para la cual
se establece el trigger.
Luego de "for" se coloca el evento (en este caso "delete"), lo que indica que las eliminaciones
sobre la tabla activarán el trigger.
Luego de "as" se especifican las condiciones que determinan cuando un intento de eliminación
causa las acciones que el trigger realizará.
El disparador del siguiente ejemplo se crea para la tabla "ventas", para que cada vez que se
elimine un registro de "ventas", se actualice el campo "stock" de la tabla "libros" (por ejemplo, si
el comprador devuelve los libros comprados):
Cuando se activa un disparador "delete", los registros eliminados en la tabla del disparador se
agregan a una tabla llamada "deleted". La tabla "deleted" es una tabla virtual que conserva una
copia de los registros eliminados; tiene una estructura similar a la tabla en que se define el
disparador, es decir, la tabla en que se intenta la acción.
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 la
cantidad de registros que se están eliminando; si se está eliminando más de un registro, el
disparador retorna un mensaje de error y deshace la transacción:
Si se ejecuta un "delete" sobre "libros" que afecte a varios registros, se activa el disparador y
evita la transacción.
Si se ejecuta el siguiente "delete", que afecta a un solo registro, se activa el disparador y permite
la transacción:
8- Intente eliminar varios artículos, algunos con stock y otros sin stock.
El trigger se dispara y deshace la transacción, es decir, ningún artículo fue
eliminado, tampoco los
que tienen stock igual a 0.
Sintaxis básica:
Analizamos la sintaxis:
"create trigger" junto al nombre del disparador; "on" seguido del nombre de la tabla para la cual
se establece el trigger.
Luego de "for" se coloca el evento (en este caso "update"), lo que indica que las actualizaciones
sobre la tabla activarán el trigger.
Luego de "as" se especifican las condiciones y acciones, es decir, las condiciones que determinan
cuando 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":
Cuando se ejecuta una instrucción "update" en una tabla que tiene definido un disparador, los
registros originales (antes de ser actualizados) se mueven a la tabla virtual "deleted" y los
registros actualizados (con los nuevos valores) se copian a la tabla virtual "inserted". Dentro del
trigger se puede acceder a estas tablas.
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, el
disparador se activa, pero permite la transacción.
Creamos un disparador de actualización que muestra el valor anterior y nuevo valor de los
registros actualizados:
Empleamos "if update" para que el trigger controle si la actualización se realiza en ciertos
campos permitidos (titulo, autor y editorial) y no en los campos prohibidos (precio y stock)); si
se modifican los campos permitidos y ninguno de los no permitidos, mostrará los antiguos y
nuevos valores consultando las tablas "deleted" e "inserted", en caso que se actualice un campo
no permitido, el disparador muestra un mensaje y deshace la transacción.
Note que el disparador no controla los intentos de actualización sobre el campo "codigo", esto es
porque 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.
5- Cree otro disparador para la tabla "inscriptos" que se active ante una
sentencia "update". Si se
actualiza el pago de la matrícula a 's', el socio debe eliminarse de la tabla
"morosos"; no debe
permitir modificar a 'n' una matrícula paga.
145 - Disparadores (varios eventos)
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 separarse
con comas.
Creamos un trigger para evitar que se inscriban socios que deben matrículas y no permitir que se
eliminen las inscripciones de socios deudores. El trigger se define para ambos eventos en la
misma sentencia de creación.
El trigger controla:
- si se ingresa una nueva inscripción y no se paga la matrícula, dicho socio se ingresa a la tabla
"morosos".
145 - Disparadores (varios eventos)
Primer problema:
Una empresa almacena los datos de sus empleados en una tabla denominada
"empleados" y los datos de
las distintas sucursales en una tabla "sucursales".
1- Elimine las tablas si existen:
if object_id('empleados') is not null
drop table empleados;
if object_id('sucursales') is not null
drop table sucursales;
2- Cree las tablas, con las siguientes estructuras:
create table sucursales(
codigo int identity,
domicilio varchar(30),
constraint PK_sucursales primary key (codigo)
);
También podemos especificar el momento de disparo del trigger. El momento de disparo indica
que 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.
Entonces, 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 lo
dispara.
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 los
datos de ambas tablas:
Creamos un disparador sobre la vista "vista_empleados_clientes" para inserción, que redirija las
inserciones a la tabla correspondiente:
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), se
ejecuten las sentencias del trigger, es decir, se ingresen los registros en las tablas
correspondientes.
a) "after": el trigger se dispara cuando las acciones especificadas (insert, delete y/o update) son
ejecutadas; todas las acciones en cascada de una restricción "foreign key" y las comprobaciones
de restricciones "check" deben realizarse con éxito antes de ejecutarse el trigger. Es la opción por
defecto si solamente colocamos "for" (equivalente a "after").
La sintaxis es:
b) "instead of": sobreescribe la acción desencadenadora del trigger. Se puede definir solamente
un disparador de este tipo para cada acción (insert, delete o update) sobre una tabla o vista.
Sintaxis:
Consideraciones:
- 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
tengan una "foreign key" que especifique una acción "on delete cascade" y "on update cascade"
respectivamente.
Los cursos tiene un número que los identifica, y según el deporte, hay un
límite de inscriptos (por
ejemplo, en tenis, no pueden inscribirse más de 4 socios; en natación,
solamente se aceptan 6
alumnos como máximo). Cuando un curso está completo, es decir, hay tantos
inscriptos como valor
tiene el campo "cantidadmaxima"), el socio queda inscripto en forma
condicional. El club guarda esa
información en una tabla denominada "condicionales" que luego analiza, porque
si se inscriben muchos
para un deporte determinado, se abrirá otro curso.
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):
Cuando se elimina una tabla o vista que tiene asociados triggers, todos los triggers asociados se
eliminan automáticamente.
- "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.
- "sp_helptext": seguido del nombre de un disparador nos muestra el texto que define el trigger,
excepto si ha sido encriptado.
1) el nombre, tipo, campos, etc. de los objetos de los cuales depende el objeto enviado
(referenciados por el objeto) y
2) nombre y tipo de los objetos que dependen del objeto nombrado (que lo referencian).
sp_depends dis_inscriptos_insertar;
En la columna "name" nos muestra las tablas (y demás objetos si hubiese) de las cuales depende
el trigger, es decir, las tablas referenciadas en el mismo; el tipo de objeto en la columna "type"
(en este 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
del campo 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, su
nombre 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 o
vista. Por ejemplo:
sp_helptrigger inscriptos;
El nombre del trigger, su propietario; en las 3 columnas siguientes indica para qué evento se ha
definido (un valor 1 indica que está definido para tal evento); las 2 últimas columnas indican el
momento de disparo (un valor 1 se interpreta como verdadero y un 0 como falso). En el ejemplo,
el disparador "dis_inscriptos_insertar" está definido para el evento de inserción (valor 1 en
"isinsert") y es "instead of" (valor 1 en "isinsteadof").
- La tabla del sistema "sysobjects": 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 un trigger muestra "TR".
Si queremos ver el nombre, tipo y fecha de creación de todos los disparadores, podemos tipear:
Se puede cambiar el evento del disparador. Por ejemplo, si creó un disparador para "insert" y
luego se modifica el evento por "update", el disparador se ejecutará cada vez que se actualice la
tabla.
Si se deshabilita un disparador, éste sigue existiendo, pero al ejecutar una instrucción "insert",
"update" o "delete" en la tabla, no se activa.
Se pueden deshabilitar (o habilitar) varios disparadores en una sola sentencia, separando sus
nombres con comas. El siguiente ejemplo deshabilitamos dos triggers definidos sobre la tabla
empleados:
Sintaxis para habilitar (o deshabilitar) todos los disparadores de una tabla específica:
alter table NOMBRETABLA
ENABLE | DISABLE TRIGGER all;
Podemos encriptar los triggers para evitar que sean leídos con "sp_helptext". Para ello debemos
agregar al crearlos la opción "with encryption" luego del nombre de la tabla o vista:
Si ejecutamos el procedimiento almacenado del sistema "sp_helptext" seguido del nombre del
trigger creado anteriormente, SQL Server mostrará un mensaje indicando que tal disparador ha
sido encriptado.
1) procesar todos los registros: todos los registros afectados deberán cumplir los criterios del
disparador para que se produzca la acción, o
2) permitir acciones condicionales: puede definir un disparador que controle si cada registro
afectado cumple con la condición; si algún registro no la cumple, la acción no se produce para tal
registro pero si para los demás que si la cumplen.
No podemos revertir la transacción con "rollback transaction" porque en ese caso TODOS los
registros modificados volverían a los valores anteriores, y lo que necesitamos es que solamente
aquellos que quedaron con valor negativo vuelvan a su valor original.
Tampoco podemos evitar que se actualicen todos los registros porque se actualizan antes que las
acciones del trigger se ejecuten.
Lo que hacemos es, en el cuerpo del trigger, averiguar si alguno de los registros actualizados
tiene stock negativo; si es así, volvemos a actualizarlo al valor anterior a la transacción.
5- Vea el resultado:
select *from empleados;
Solamente se eliminaron aquellos que no pertenecen a la sección "Gerencia".
Ver solución