Vous êtes sur la page 1sur 222

Ya explicamos que al crear una tabla debemos elegir la estructura adecuada, esto es, definir los

campos y sus tipos ms precisos, segn el caso.

Para almacenar valores de tipo FECHA Y HORA SQL Server dispone de dos tipos:

1) datetime: puede almacenar valores desde 01 de enero de 1753 hasta 31 de diciembre de 9999.

2) smalldatetime: el rango va de 01 de enero de 1900 hasta 06 de junio de 2079.

Las fechas se ingresan entre comillas simples.

Para almacenar valores de tipo fecha se permiten como separadores "/", "-" y ".".

SQL Server reconoce varios formatos de entrada de datos de tipo fecha. Para establecer el orden
de las partes de una fecha (dia, mes y ao) empleamos "set dateformat". Estos son los formatos:

-mdy: 4/15/96 (mes y da con 1 2 dgitos y ao con 2 4 dgitos),


-myd: 4/96/15,
-dmy: 15/4/1996
-dym: 15/96/4,
-ydm: 96/15/4,
-ydm: 1996/15/4,

Para ingresar una fecha con formato "da-mes-ao", tipeamos:

set dateformat dmy;

El formato por defecto es "mdy".

Todos los valores de tipo "datetime" se muestran en formato "ao-mes-da hora:minuto:segundo


.milisegundos", independientemente del formato de ingreso que hayamos seteado.

Podemos ingresar una fecha, sin hora, en tal caso la hora se guarda como "00:00:00". Por
ejemplo, si ingresamos '25-12-01' (ao de 2 dgitos), 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'.

Podemos emplear los operadores relacionales vistos para comparar fechas.

Tipo Bytes de almacenamiento


_______________________________________
datetime 8
smalldatetime 4

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:
insert into libros
values ('Uno','Richard Bach','Planeta');

Tambin es posible ingresar valores para algunos campos. Ingresamos valores solamente para los
campos "titulo" y "autor":

insert into libros (titulo, autor)


values ('El aleph','Borges');

SQL Server almacenar el valor "null" en el campo "editorial", para el cual no hemos explicitado
un valor.

Al ingresar registros debemos tener en cuenta:

- la lista de campos debe coincidir en cantidad y tipo de valores con la lista de valores luego de
"values". Si se listan ms (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 clusula "default" (tema que veremos a continuacin).

Hemos visto que si al insertar registros no se especifica un valor para un campo que admite
valores nulos, se ingresa automaticamente "null" y si el campo est declarado "identity", se
inserta el siguiente de la secuencia. A estos valores se les denomina valores por defecto o
predeterminados.

Un valor por defecto se inserta cuando no est presente al ingresar un registro y en algunos casos
en que el dato ingresado es invlido.

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 explcitamente con la clusula "default".

Para todos los tipos, excepto los declarados "identity", se pueden explicitar valores por defecto
con la clusula "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":

create table libros(


codigo int identity,
titulo varchar(40),
autor varchar(30) not null default 'Desconocido',
editorial varchar(20),
precio decimal(5,2),
cantidad tinyint default 0
);

Si al ingresar un nuevo registro omitimos los valores para el campo "autor" y "cantidad", Sql 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 clusula "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.

Tambin se puede utilizar "default" para dar el valor por defecto a los campos en sentencias
"insert", por ejemplo:

insert into libros (titulo,autor,precio,cantidad)


values ('El gato con botas',default,default,100);

Si todos los campos de una tabla tienen valores predeterminados (ya sea por ser "identity",
permitir valores nulos o tener un valor por defecto), se puede ingresar un registro de la siguiente
manera:

insert into libros default values;

La sentencia anterior almacenar un registro con los valores predetermiandos para cada uno de
sus campos.

Entonces, la clusula "default" permite especificar el valor por defecto de un campo. Si no se


explicita, el valor por defecto es "null", siempre que el campo no haya sido declarado "not null".

Los campos para los cuales no se ingresan valores en un "insert" tomarn los valores por defecto:

- si tiene el atributo "identity": el valor de inicio de la secuencia si es el primero o el siguiente


valor de la secuencia, no admite clusula "default";

- si permite valores nulos y no tiene clusula "default", almacenar "null";

- si est declarado explcitamente "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 clusula "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 slo 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.

Aprendimos que los operadores son smbolos que permiten realizar distintos tipos de operaciones.
Dijimos que SQL Server tiene 4 tipos de operadores: 1) relacionales o de comparacin (los vimos),
2) lgicos (lo veremos ms adelante, 3) aritmticos y 4) de concatenacin.

Los operadores aritmticos permiten realizar clculos con valores numricos.


Son: multiplicacin (*), divisin (/) y mdulo (%) (el resto de dividir nmeros enteros), suma (+) y
resta (-).

Es posible obtener salidas en las cuales una columna sea el resultado de un clculo y no un campo
de una tabla.

Si queremos ver los ttulos, 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 ttulo podemos multiplicar el precio por la
cantidad por cada ttulo, pero tambin podemos hacer que SQL Server realice el clculo y lo
incluya en una columna extra en la salida:

select titulo, precio,cantidad,


precio*cantidad
from libros;

Si queremos saber el precio de cada libro con un 10% de descuento podemos incluir en la
sentencia los siguientes clculos:

select titulo,precio,
precio-(precio*0.1)
from libros;

Tambin podemos actualizar los datos empleando operadores aritmticos:

update libros set precio=precio-(precio*0.1);

Todas las operaciones matemticas retornan "null" en caso de error. Ejemplo:

select 5/0;

Los operadores de concatenacin: permite concatenar cadenas, el ms (+).

Para concatenar el ttulo, el autor y la editorial de cada libro usamos el operador de


concatenacin ("+"):

select titulo+'-'+autor+'-'+editorial
from libros;

Note que concatenamos adems unos guiones para separar los campos.

Primer problema:

Un comercio que vende artculos de computacin registra los datos de sus artculos en
una tabla con
ese nombre.
1- Elimine la tabla si existe:
if object_id ('articulos') is not null
drop table articulos;

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)
);

3- Ingrese algunos registros:


insert into articulos (nombre, descripcion, precio,cantidad)
values ('impresora','Epson Stylus C45',400.80,20);
insert into articulos (nombre, descripcion, precio)
values ('impresora','Epson Stylus C85',500);
insert into articulos (nombre, descripcion, precio)
values ('monitor','Samsung 14',800);
insert into articulos (nombre, descripcion, precio,cantidad)
values ('teclado','ingles Biswal',100,50);

4- El comercio quiere aumentar los precios de todos sus artculos en un 15%. Actualice
todos los
precios empleando operadores aritmticos.

Update artculos set precio=precio-(precio*0.15)

5- Vea el resultado:
select *from articulos;

6- Muestre todos los artculos, concatenando el nombre y la descripcin de cada uno


de ellos
separados por coma.

7- Reste a la cantidad de todos los teclados, el valor 5, empleando el operador


aritmtico menos ("-")
if object_id ('articulos') is not null
drop table articulos;

create table articulos(


codigo int identity,
nombre varchar(20),
descripcion varchar(30),
precio smallmoney,
cantidad tinyint default 0,
primary key (codigo)
);

insert into articulos (nombre, descripcion, precio,cantidad)


values ('impresora','Epson Stylus C45',400.80,20);
insert into articulos (nombre, descripcion, precio)
values ('impresora','Epson Stylus C85',500);
insert into articulos (nombre, descripcion, precio)
values ('monitor','Samsung 14',800);
insert into articulos (nombre, descripcion, precio,cantidad)
values ('teclado','ingles Biswal',100,50);

update articulos set precio=precio+(precio*0.15);

select *from articulos;

select nombre+','+descripcion
from articulos;

update articulos set cantidad=cantidad-5


where nombre='teclado';

select *from articulos;

Una manera de hacer ms 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 informacin 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 ms de una
palabra, es necesario colocarla entre comillas simples:

select nombre as 'Nombre y apellido',


domicilio,telefono
from agenda;

Un alias puede contener hasta 128 caracteres.


Tambin se puede crear un alias para columnas calculadas.

La palabra clave "as" es opcional en algunos casos, pero es conveniente usarla.

Entonces, un "alias" se usa como nombre de un campo o de una expresin. En estos casos, son
opcionales, sirven para hacer ms comprensible el resultado; en otros casos, que veremos ms
adelante, son obligatorios.

Una funcin es un conjunto de sentencias que operan como una unidad lgica.

Una funcin tiene un nombre, retorna un parmetro de salida y opcionalmente acepta


parmetros 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:

- de configuracin: retornan informacin referida a la configuracin.


Ejemplo:

select @@version;

retorna la fecha, versin y tipo de procesador de SQL Server.

- de cursores: retornan informacin sobre el estado de un cursor.

- de fecha y hora: operan con valores "datetime" y "smalldatetime". Reciben un parmetro de tipo
fecha y hora y retornan un valor de cadena, numrico o de fecha y hora.

- matemticas: realizan operaciones numricas, geomtricas y trigonomtricas.

- de metadatos: informan sobre las bases de datos y los objetos.

- de seguridad: devuelven informacin referente a usuarios y funciones.


- de cadena: operan con valores "char", "varchar", "nchar", "nvarchar", "binary" y "varbinary" y
devuelven un valor de cadena o numrico.

- del sistema: informan sobre opciones, objetos y configuraciones del sistema. Ejemplo:

select user_name();

- estadsticas del sistema: retornan informacin referente al rendimiento del sistema.

- texto e imagen: realizan operaciones con valor de entrada de tipo text o image y retornan
informacin referente al mismo.

3) de conjuntos de filas: retornan conjuntos de registros.

Se pueden emplear las funciones del sistema en cualquier lugar en el que se permita una
expresin en una sentencia "select".

Estudiaremos algunas de ellas.

Microsoft SQL Server tiene algunas funciones para trabajar con cadenas de caracteres. Estas son
algunas:

- substring(cadena,inicio,longitud): devuelve una parte de la cadena especificada como primer


argumento, empezando desde la posicin especificada por el segundo argumento y de tantos
caracteres de longitud como indica el tercer argumento. Ejemplo:

select substring('Buenas tardes',8,6);

retorna "tardes".

- str(numero,longitud,cantidaddecimales): convierte nmeros a caracteres; el primer parmetro


indica el valor numrico a convertir, el segundo la longitud del resultado (debe ser mayor o igual
a la parte entera del nmero ms el signo si lo tuviese) y el tercero, la cantidad de decimales. El
segundo y tercer argumento son opcionales y deben ser positivos. String significa cadena en
ingls.

Ejemplo: se convierte el valor numrico "123.456" a cadena, especificando 7 de longitud y 3


decimales:

select str(123.456,7,3);

select str(-123.456,7,3);

retorna '-123.46';

Si no se colocan el segundo y tercer argumeno, la longitud predeterminada es 10 y la cantidad de


decimales 0 y se redondea a entero. Ejemplo: se convierte el valor numrico "123.456" a cadena:

select str(123.456);
retorna '123';

select str(123.456,3);

retorna '123';

Si el segundo parmetro es menor a la parte entera del nmero, devuelve asteriscos (*). Ejemplo:
select str(123.456,2,3);

retorna "**".

- stuff(cadena1,inicio,cantidad,cadena2): inserta la cadena enviada como cuarto argumento, en


la posicin indicada en el segundo argumento, reemplazando la cantidad de caracteres indicada
por el tercer argumento en la cadena que es primer parmetro. Stuff significa rellenar en ingls.
Ejemplo:

select stuff('abcde',3,2,'opqrs');

retorna "abopqrse". Es decir, coloca en la posicin 2 la cadena "opqrs" y reemplaza 2 caracteres


de la primer cadena.

Los argumentos numricos 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 carcter.

- len(cadena): retorna la longitud de la cadena enviada como argumento. "len" viene de length,
que significa longitud en ingls. Ejemplo:

select len('Hola');

devuelve 4.

- char(x): retorna un caracter en cdigo ASCII del entero enviado como argumento. Ejemplo:

select char(65);

retorna "A".

- left(cadena,longitud): retorna la cantidad (longitud) de caracteres de la cadena comenzando


desde la izquierda, primer caracter. Ejemplo:

select left('buenos dias',8);

retorna "buenos d".

- right(cadena,longitud): retorna la cantidad (longitud) de caracteres de la cadena comenzando


desde la derecha, ltimo caracter. Ejemplo:

select right('buenos dias',8);


retorna "nos dias".

-lower(cadena): retornan la cadena con todos los caracteres en minsculas. lower significa
reducir en ingls. Ejemplo:

select lower('HOLA ESTUDIAnte');

retorna "hola estudiante".

-upper(cadena): retornan la cadena con todos los caracteres en maysculas. Ejemplo:

select upper('HOLA ESTUDIAnte');

-ltrim(cadena): retorna la cadena con los espacios de la izquierda eliminados. Trim significa
recortar. Ejemplo:

select ltrim(' Hola ');

retorna "Hola ".

- rtrim(cadena): retorna la cadena con los espacios de la derecha eliminados. Ejemplo:

select rtrim(' Hola ');

retorna " Hola".

- replace(cadena,cadenareemplazo,cadenareemplazar): retorna la cadena con todas las


ocurrencias de la subcadena reemplazo por la subcadena a reemplazar. Ejemplo:

select replace('xxx.sqlserverya.com','x','w');

retorna "www.sqlserverya.com'.

- reverse(cadena): devuelve la cadena invirtiendo el order de los caracteres. Ejemplo:

select reverse('Hola');

retorna "aloH".

- patindex(patron,cadena): devuelve la posicin de comienzo (de la primera ocurrencia) del


patrn especificado en la cadena enviada como segundo argumento. Si no la encuentra retorna 0.
Ejemplos:

select patindex('%Luis%', 'Jorge Luis Borges');

retorna 7.

select patindex('%or%', 'Jorge Luis Borges');

retorna 2.
select patindex('%ar%', 'Jorge Luis Borges');

retorna 0.

- charindex(subcadena,cadena,inicio): devuelve la posicin donde comienza la subcadena en la


cadena, comenzando la bsqueda desde la posicin indicada por "inicio". Si el tercer argumento
no se coloca, la bsqueda se inicia desde 0. Si no la encuentra, retorna 0. Ejemplos:

select charindex('or','Jorge Luis Borges',5);

retorna 13.

select charindex('or','Jorge Luis Borges');

retorna 2.

select charindex('or','Jorge Luis Borges',14);

retorna 0.

select charindex('or', 'Jorge Luis Borges');

retorna 0.

- replicate(cadena,cantidad): repite una cadena la cantidad de veces especificada. Ejemplo:

select replicate ('Hola',3);

retorna "HolaHolaHola";

- space(cantidad): retorna una cadena de espacios de longitud indicada por "cantidad", que
debe ser un valor positivo. Ejemplo:

select 'Hola'+space(1)+'que tal';

retorna "Hola que tal".

Se pueden emplear estas funciones enviando como argumento el nombre de un campo de tipo
caracter.

Problema:

Trabajamos con la tabla "libros" de una librera.


Eliminamos la tabla si existe:

if object_id ('libros') is not null


drop table libros;

Creamos la tabla:
create table libros(
codigo int identity,
titulo varchar(40) not null,
autor varchar(20) default 'Desconocido',
editorial varchar(20),
precio decimal(6,2),
cantidad tinyint default 0,
primary key (codigo)
);

Ingresamos algunos registros:

insert into libros (titulo,autor,editorial,precio)


values('El aleph','Borges','Emece',25);
insert into libros
values('Java en 10 minutos','Mario Molina','Siglo XXI',50.40,100);
insert into libros (titulo,autor,editorial,precio,cantidad)
values('Alicia en el pais de las maravillas','Lewis
Carroll','Emece',15,50);

Mostramos slo los 12 primeros caracteres de los ttulos de los libros y sus autores, empleando la
funcin "substring()":

select substring(titulo,1,12) as titulo


from libros;

Mostramos slo los 12 primeros caracteres de los ttulos de los libros y sus autores, ahora
empleando la funcin "left()":

select left(titulo,12) as titulo


from libros;

Mostramos los ttulos de los libros y sus precios convirtiendo este ltimo a cadena de caracteres
con un solo decimal, empleando la funcin "str":

select titulo,
str(precio,6,1)
from libros;

Mostramos los ttulos de los libros y sus precios convirtiendo este ltimo a cadena de caracteres
especificando un solo argumento:

select titulo,
str(precio)
from libros;

Se redondea a entero.

Mostramos los ttulos, autores y editoriales de todos libros, al ltimo campo lo queremos en
maysculas:

select titulo, autor, upper(editorial)


from libros;
if object_id ('libros') is not null

drop table libros;

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)

);

insert into libros (titulo,autor,editorial,precio)

values('El aleph','Borges','Emece',25);

insert into libros

values('Java en 10 minutos','Mario Molina','Siglo XXI',50.40,100);

insert into libros (titulo,autor,editorial,precio,cantidad)

values('Alicia en el pais de las maravillas','Lewis Carroll','Emece',15,50);

select substring(titulo,1,12) as titulo

from libros;

select left(titulo,12) as titulo

from libros;
select titulo,

str(precio,6,1)

from libros;

select titulo,

str(precio)

from libros;

select titulo, autor, upper(editorial)

from libros;

Las funciones matemticas realizan operaciones con expresiones numricas y retornan un


resultado, operan con tipos de datos numricos.

Microsoft SQL Server tiene algunas funciones para trabajar con nmeros. Aqu presentamos
algunas.

-abs(x): retorna el valor absoluto del argumento "x". Ejemplo:

select abs(-20);

retorna 20.

-ceiling(x): redondea hacia arriba el argumento "x". Ejemplo:

select ceiling(12.34);

retorna 13.

-floor(x): redondea hacia abajo el argumento "x". Ejemplo:

select floor(12.34);

retorna 12.

- %: %: devuelve el resto de una divisin. Ejemplos:


select 10%3;

retorna 1.

select 10%2;

retorna 0.

-power(x,y): retorna el valor de "x" elevado a la "y" potencia. Ejemplo:

select power(2,3);

retorna 8.

-round(numero,longitud): retorna un nmero redondeado a la longitud especificada. "longitud"


debe ser tinyint, smallint o int. Si "longitud" es positivo, el nmero de decimales es redondeado
segn "longitud"; si es negativo, el nmero es redondeado desde la parte entera segn el valor de
"longitud". Ejemplos:

select round(123.456,1);

retorna "123.400", es decir, redondea desde el primer decimal.

select round(123.456,2);

retorna "123.460", es decir, redondea desde el segundo decimal.

select round(123.456,-1);

retorna "120.000", es decir, redondea desde el primer valor entero (hacia la izquierda).

select round(123.456,-2);

retorna "100.000", es decir, redondea desde el segundo valor entero (hacia la izquierda).

-sign(x): si el argumento es un valor positivo devuelve 1;-1 si es negativo y si es 0, 0.

-square(x): retorna el cuadrado del argumento. Ejemplo:

select square(3); retorna 9.

-srqt(x): devuelve la raiz cuadrada del valor enviado como argumento.

SQL Server dispone de funciones trigonomtricas que retornan radianes.

Se pueden emplear estas funciones enviando como argumento el nombre de un campo de tipo
numrico.

Problema:
Trabajamos con la tabla "libros" de una librera.
Eliminamos la tabla si existe:

if object_id ('libros') is not null


drop table libros;

Creamos la tabla:

create table libros(


codigo int identity,
titulo varchar(40) not null,
autor varchar(20) default 'Desconocido',
editorial varchar(20),
precio decimal(6,2),
primary key (codigo)
);

Ingresamos algunos registros:

insert into libros (titulo,autor,editorial,precio)


values('El aleph','Borges','Emece',25.33);
insert into libros
values('Java en 10 minutos','Mario Molina','Siglo XXI',50.65);
insert into libros (titulo,autor,editorial,precio)
values('Alicia en el pais de las maravillas','Lewis
Carroll','Emece',19.95);

Vamos a mostrar los precios de los libros redondeando el valor hacia abajo y hacia arriba:

select titulo,autor,precio,
floor(precio) as abajo,
ceiling(precio) as arriba
from libros;

if object_id ('libros') is not null

drop table libros;

create table libros(

codigo int identity,

titulo varchar(40) not null,

autor varchar(20) default 'Desconocido',

editorial varchar(20),

precio decimal(6,2),
primary key (codigo)

);

insert into libros (titulo,autor,editorial,precio)

values('El aleph','Borges','Emece',25.33);

insert into libros

values('Java en 10 minutos','Mario Molina','Siglo XXI',50.65);

insert into libros (titulo,autor,editorial,precio)

values('Alicia en el pais de las maravillas','Lewis Carroll','Emece',19.95);

select titulo,autor,precio,

floor(precio) as abajo,

ceiling(precio) as arriba

from libros;

Microsoft SQL Server ofrece algunas funciones para trabajar con fechas y horas. Estas son
algunas:

- getdate(): retorna la fecha y hora actuales. Ejemplo:

select getdate();

- datepart(partedefecha,fecha): retorna la parte especfica de una fecha, el ao, trimestre,


da, hora, etc.

Los valores para "partedefecha" pueden ser: year (ao), quarter (cuarto), month (mes), day (dia),
week (semana), hour (hora), minute (minuto), second (segundo) y millisecond (milisegundo).
Ejemplos:

select datepart(month,getdate());

retorna el nmero de mes actual;

select datepart(day,getdate());
retorna el da actual;

select datepart(hour,getdate());

retorna la hora actual;

- datename(partedefecha,fecha): retorna el nombre de una parte especfica de una fecha. Los


valores para "partedefecha" pueden ser los mismos que se explicaron anteriormente. Ejemplos:

select datename(month,getdate());

retorna el nombre del mes actual;

select datename(day,getdate());

- dateadd(partedelafecha,numero,fecha): agrega un intervalo a la fecha especificada, es decir,


retorna una fecha adicionando a la fecha enviada como tercer argumento, el intervalo de tiempo
indicado por el primer parmetro, tantas veces como lo indica el segundo parmetro. Los valores
para el primer argumento pueden ser: year (ao), quarter (cuarto), month (mes), day (dia), week
(semana), hour (hora), minute (minuto), second (segundo) y millisecond (milisegundo). Ejemplos:

select dateadd(day,3,'1980/11/02');

retorna "1980/11/05", agrega 3 das.

select dateadd(month,3,'1980/11/02');

retorna "1981/02/02", agrega 3 meses.

select dateadd(hour,2,'1980/11/02');

retorna "1980/02/02 2:00:00", agrega 2 horas.

select dateadd(minute,16,'1980/11/02');

retorna "1980/02/02 00:16:00", agrega 16 minutos.

- datediff(partedelafecha,fecha1,fecha2): calcula el intervalo de tiempo (segn el primer


argumento) entre las 2 fechas. El resultado es un valor entero que corresponde a fecha2-fecha1.
Los valores de "partedelafecha) pueden ser los mismos que se especificaron anteriormente.
Ejemplos:

select datediff (day,'2005/10/28','2006/10/28');

retorna 365 (das).

select datediff(month,'2005/10/28','2006/11/29');

retorna 13 (meses).

- day(fecha): retorna el da de la fecha especificada. Ejemplo:


select day(getdate());

- month(fecha): retorna el mes de la fecha especificada. Ejemplo:

select month(getdate());

- year(fecha): retorna el ao de la fecha especificada. Ejemplo:

select year(getdate());

Se pueden emplear estas funciones enviando como argumento el nombre de un campo de tipo
datetime o smalldatetime.

Problema:

Trabajamos con la tabla "libros" de una librera.


Eliminamos la tabla si existe:

if object_id ('libros') is not null


drop table libros;

Creamos la tabla:

create table libros(


titulo varchar(40) not null,
autor varchar(20) default 'Desconocido',
editorial varchar(20),
edicion datetime,
precio decimal(6,2)
);

Ingresamos algunos registros:

insert into libros


values('El aleph','Borges','Emece','1980/10/10',25.33);
insert into libros
values('Java en 10 minutos','Mario Molina','Siglo
XXI','2000/05/05',50.65);
insert into libros
values('Alicia en el pais de las maravillas','Lewis
Carroll','Emece','2000/08/09',19.95);
insert into libros
values('Aprenda PHP','Mario Molina','Siglo XXI','2000/02/04',45);

Mostramos el ttulo del libro y el ao de edicin:

select titulo, datepart (year,edicion) from libros;


Mostramos el ttulo del libro y el nombre del mes de edicin:

select titulo, datename (month,edicion) from libros;

Mostramos el ttulo del libro y los aos que tienen de editados:

select titulo, datediff(year,edicion,getdate()) from libros;

Muestre los ttulos de los libros que se editaron el da 9, de cualquier mes de cualquier ao:

select titulo from libros


where datepart(day,edicion)=9;

Podemos ordenar el resultado de un "select" para que los registros se muestren ordenados por
algn campo, para ello usamos la clusula "order by".

La sintaxis bsica es la siguiente:

select *from NOMBRETABLA


order by CAMPO;

Por ejemplo, recuperamos los registros de la tabla "libros" ordenados por el ttulo:

select *from libros


order by titulo;

Aparecen los registros ordenados alfabticamente por el campo especificado.

Tambin podemos colocar el nmero de orden del campo por el que queremos que se ordene en
lugar de su nombre, es decir, referenciar a los campos por su posicin en la lista de seleccin.
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;

Tambin podemos ordenar por varios campos, por ejemplo, por "titulo" y "editorial":

select *from libros


order by titulo,editorial;

Incluso, podemos ordenar en distintos sentidos, por ejemplo, por "titulo" en sentido ascendente y
"editorial" en sentido descendente:
select *from libros
order by titulo asc, editorial desc;

Debe aclararse al lado de cada campo, pues estas palabras claves afectan al campo
inmediatamente anterior.

Es posible ordenar por un campo que no se lista en la seleccin.

Se permite ordenar por valores calculados o expresiones.

La clusula "order by" no puede emplearse para campos text, ntext e image.

if object_id('visitas') is not null


drop table visitas;

create table visitas (


numero int identity,
nombre varchar(30) default 'Anonimo',
mail varchar(50),
pais varchar (20),
fecha datetime,
primary key(numero)
);

insert into visitas (nombre,mail,pais,fecha)


values ('Ana Maria Lopez','AnaMaria@hotmail.com','Argentina','2006-10-10 10:10');
insert into visitas (nombre,mail,pais,fecha)
values ('Gustavo Gonzalez','GustavoGGonzalez@hotmail.com','Chile','2006-10-10
21:30');
insert into visitas (nombre,mail,pais,fecha)
values ('Juancito','JuanJosePerez@hotmail.com','Argentina','2006-10-11 15:45');
insert into visitas (nombre,mail,pais,fecha)
values ('Fabiola Martinez','MartinezFabiola@hotmail.com','Mexico','2006-10-12
08:15');
insert into visitas (nombre,mail,pais,fecha)
values ('Fabiola Martinez','MartinezFabiola@hotmail.com','Mexico','2006-09-12
20:45');
insert into visitas (nombre,mail,pais,fecha)
values ('Juancito','JuanJosePerez@hotmail.com','Argentina','2006-09-12 16:20');
insert into visitas (nombre,mail,pais,fecha)
values ('Juancito','JuanJosePerez@hotmail.com','Argentina','2006-09-15 16:25');

select *from visitas


order by fecha desc;

select nombre,pais,datename(month,fecha)
from visitas
order by pais,datename(month,fecha) desc;

select nombre,mail,
datename(month,fecha) mes,
datename(day,fecha) dia,
datename(hour,fecha) hora
from visitas
order by 3,4,5;

select mail, pais


from visitas
where datename(month,fecha)='October'
order by 2;

Hasta el momento, hemos aprendido a establecer una condicin con "where" utilizando
operadores relacionales. Podemos establecer ms de una condicin con la clusula "where", para
ello aprenderemos los operadores lgicos.

Son los siguientes:

- and, significa "y",


- or, significa "y/o",
- not, significa "no", invierte el resultado
- (), parntesis

Los operadores lgicos se usan para combinar condiciones.

Si queremos recuperar todos los libros cuyo autor sea igual a "Borges" y cuyo precio no supere los
20 pesos, necesitamos 2 condiciones:

select *from libros


where (autor='Borges') and
(precio<=20);

Los registros recuperados en una sentencia que une 2 condiciones con el operador "and", cumplen
con las 2 condiciones.

Queremos ver los libros cuyo autor sea "Borges" y/o cuya editorial sea "Planeta":

select *from libros


where autor='Borges' or
editorial='Planeta';

En la sentencia anterior usamos el operador "or"; indicamos que recupere los libros en los cuales
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 condicin, con la segunda condicin 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 condicin dada, por ejemplo, aquellos cuya
editorial NO sea "Planeta":
select *from libros
where not editorial='Planeta';

El operador "not" invierte el resultado de la condicin a la cual antecede.

Los registros recuperados en una sentencia en la cual aparece el operador "not", no cumplen con
la condicin a la cual afecta el "NOT".

Los parntesis se usan para encerrar condiciones, para que se evalen como una sola expresin.
Cuando explicitamos varias condiciones con diferentes operadores lgicos (combinamos "and",
"or") permite establecer el orden de prioridad de la evaluacin; adems permite diferenciar las
expresiones ms claramente.

Por ejemplo, las siguientes expresiones devuelven un resultado diferente:

select*from libros
where (autor='Borges') or
(editorial='Paidos' and precio<20);

select *from libros


where (autor='Borges' or editorial='Paidos') and
(precio<20);

Si bien los parntesis no son obligatorios en todos los casos, se recomienda utilizarlos para evitar
confusiones.

El orden de prioridad de los operadores lgicos es el siguiente: "not" se aplica antes que "and" y
"and" antes que "or", si no se especifica un orden de evaluacin mediante el uso de parntesis.
El orden en el que se evalan los operadores con igual nivel de precedencia es indefinido, por
ello se recomienda usar los parntesis.

Entonces, para establecer ms de una condicin en un "where" es necesario emplear operadores


lgicos. "and" significa "y", indica que se cumplan ambas condiciones; "or" significa "y/o", indica
que se cumpla una u otra condicin (o ambas); "not" significa "no", indica que no se cumpla la
condicin especificada.

Trabaje con la tabla llamada "medicamentos" de una farmacia.


1- Elimine la tabla, si existe:
if object_id('medicamentos') is not null
drop table medicamentos;

2- Cree la tabla con la siguiente estructura:


create table medicamentos(
codigo int identity,
nombre varchar(20),
laboratorio varchar(20),
precio decimal(5,2),
cantidad tinyint,
primary key(codigo)
);
3- Ingrese algunos registros:
insert into medicamentos
values('Sertal','Roche',5.2,100);
insert into medicamentos
values('Buscapina','Roche',4.10,200);
insert into medicamentos
values('Amoxidal 500','Bayer',15.60,100);
insert into medicamentos
values('Paracetamol 500','Bago',1.90,200);
insert into medicamentos
values('Bayaspirina','Bayer',2.10,150);
insert into medicamentos
values('Amoxidal jarabe','Bayer',5.10,250);

4- Recupere los cdigos y nombres de los medicamentos cuyo laboratorio sea 'Roche' y
cuyo precio sea
menor a 5 (1 registro cumple con ambas condiciones)

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.

6- Muestre todos los medicamentos cuyo laboratorio NO sea "Bayer" y cuya cantidad
sea=100 (1
registro)

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 condicin a la cual
antecede, no a
las siguientes. Los resultados de los puntos 6 y 7 son diferentes.

8- Elimine todos los registros cuyo laboratorio sea igual a "Bayer" y su precio sea
mayor a 10 (1
registro eliminado)

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)
if object_id('medicamentos') is not null
drop table medicamentos;

create table medicamentos(


codigo int identity,
nombre varchar(20),
laboratorio varchar(20),
precio decimal(5,2),
cantidad tinyint,
primary key(codigo)
);

insert into medicamentos


values('Sertal','Roche',5.2,100);
insert into medicamentos
values('Buscapina','Roche',4.10,200);
insert into medicamentos
values('Amoxidal 500','Bayer',15.60,100);
insert into medicamentos
values('Paracetamol 500','Bago',1.90,200);
insert into medicamentos
values('Bayaspirina','Bayer',2.10,150);
insert into medicamentos
values('Amoxidal jarabe','Bayer',5.10,250);

select codigo,nombre
from medicamentos
where laboratorio='Roche' and
precio<5;

select * from medicamentos


where laboratorio='Roche' or
precio<5;

select * from medicamentos


where not laboratorio='Bayer' and
cantidad=100;

select * from medicamentos


where laboratorio='Bayer' and
not cantidad=100;

delete from medicamentos


where laboratorio='Bayer' and
precio>10;

update medicamentos set cantidad=200


where laboratorio='Roche' and
precio>5;

delete from medicamentos


where laboratorio='Bayer' or
precio<3;

Hemos aprendido los operadores relacionales "=" (igual), "<>" (distinto), ">" (mayor), "<" (menor),
">=" (mayor o igual) y "<=" (menor o igual). Dijimos que no eran los nicos.

Existen otro operador relacional "is null".

Se emplea el operador "is null" para recuperar los registros en los cuales est almacenado el valor
"null" en un campo especfico:

select *from libros


where editorial is null;

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 bsqueda positivas ("is null"), evite las negativas
("is not null") porque con ellas se evalan todos los registros y esto hace ms lenta la
recuperacin de los datos.

if object_id('peliculas') is not null


drop table peliculas;

create table peliculas(


codigo int identity,
titulo varchar(40) not null,
actor varchar(20),
duracion tinyint,
primary key (codigo)
);

insert into peliculas


values('Mision imposible','Tom Cruise',120);
insert into peliculas
values('Harry Potter y la piedra filosofal','Daniel R.',null);
insert into peliculas
values('Harry Potter y la camara secreta','Daniel R.',190);
insert into peliculas
values('Mision imposible 2','Tom Cruise',120);
insert into peliculas
values('Mujer bonita',null,120);
insert into peliculas
values('Tootsie','D. Hoffman',90);
insert into peliculas (titulo)
values('Un oso rojo');

select *from peliculas


where actor is null;
update peliculas set duracion=0
where duracion is null;

delete from peliculas


where actor is null and
duracion=0;

select * from peliculas;

Hemos visto los operadores relacionales: = (igual), <> (distinto), > (mayor), < (menor), >= (mayor
o igual), <= (menor o igual), is null/is not null (si un valor es NULL o no).

Otro operador relacional es "between", trabajan con intervalos de valores.

Hasta ahora, para recuperar de la tabla "libros" los libros con precio mayor o igual a 20 y menor o
igual a 40, usamos 2 condiciones unidas por el operador lgico "and":

select *from libros


where precio>=20 and
precio<=40;

Podemos usar "between" y as simplificar la consulta:

select *from libros


where precio between 20 and 40;

Averiguamos si el valor de un campo dado (precio) est entre los valores mnimo y mximo
especificados (20 y 40 respectivamente).

"between" significa "entre". Trabaja con intervalo de valores.


Este operador se puede emplear con tipos de datos numricos y money (en tales casos incluyen
los valores mnimo y mximo) y tipos de datos fecha y hora (incluye slo el valor mnimo).

No tiene en cuenta los valores "null".

Si agregamos el operador "not" antes de "between" el resultado se invierte, es decir, se recuperan


los registros que estn fuera del intervalo especificado. Por ejemplo, recuperamos los libros cuyo
precio NO se encuentre entre 20 y 35, es decir, los menores a 15 y mayores a 25:

select *from libros


where precio not between 20 and 35;

Siempre que sea posible, emplee condiciones de bsqueda positivas ("between"), evite las
negativas ("not between") porque hace ms lenta la recuperacin de los datos.

Entonces, se puede usar el operador "between" para reducir las condiciones "where".
En una pgina web se guardan los siguientes datos de las visitas: nmero 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;

2- Crela con la siguiente estructura:


create table visitas (
numero int identity,
nombre varchar(30) default 'Anonimo',
mail varchar(50),
pais varchar (20),
fechayhora datetime,
primary key(numero)
);

3- Ingrese algunos registros:


insert into visitas (nombre,mail,pais,fechayhora)
values ('Ana Maria Lopez','AnaMaria@hotmail.com','Argentina','2006-10-10 10:10');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Gustavo Gonzalez','GustavoGGonzalez@gotmail.com','Chile','2006-10-10
21:30');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Juancito','JuanJosePerez@hotmail.com','Argentina','2006-10-11 15:45');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Fabiola Martinez','MartinezFabiola@hotmail.com','Mexico','2006-10-12
08:15');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Fabiola Martinez','MartinezFabiola@hotmail.com','Mexico','2006-09-12
20:45');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Juancito','JuanJosePerez@gmail.com','Argentina','2006-09-12 16:20');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Juancito','JuanJosePerez@hotmail.com','Argentina','2006-09-15 16:25');
insert into visitas (nombre,mail,pais)
values ('Federico1','federicogarcia@xaxamail.com','Argentina');

4- Seleccione los usuarios que visitaron la pgina entre el '2006-09-12' y '2006-10-11'


(5
registros)
Note que incluye los de fecha mayor o igual al valor mnimo y menores al valor
mximo, y que los
valores null no se incluyen.

5- Recupere las visitas cuyo nmero se encuentra entre 2 y 5 (4 registros)


Note que incluye los valores lmites.

if object_id('visitas') is not null


drop table visitas;

create table visitas (


numero int identity,
nombre varchar(30) default 'Anonimo',
mail varchar(50),
pais varchar (20),
fechayhora datetime,
primary key(numero)
);

insert into visitas (nombre,mail,pais,fechayhora)


values ('Ana Maria Lopez','AnaMaria@hotmail.com','Argentina','2006-10-10 10:10');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Gustavo Gonzalez','GustavoGGonzalez@gotmail.com','Chile','2006-10-10
21:30');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Juancito','JuanJosePerez@hotmail.com','Argentina','2006-10-11 15:45');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Fabiola Martinez','MartinezFabiola@hotmail.com','Mexico','2006-10-12
08:15');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Fabiola Martinez','MartinezFabiola@hotmail.com','Mexico','2006-09-12
20:45');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Juancito','JuanJosePerez@gmail.com','Argentina','2006-09-12 16:20');
insert into visitas (nombre,mail,pais,fechayhora)
values ('Juancito','JuanJosePerez@hotmail.com','Argentina','2006-09-15 16:25');
insert into visitas (nombre,mail,pais)
values ('Federico1','federicogarcia@xaxamail.com','Argentina');

select *from visitas


where fechayhora between '2006-09-12' and '2006-10-11';

select *from visitas


where numero between 2 and 5;

Se utiliza "in" para averiguar si el valor de un campo est incluido en una lista de valores
especificada.

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' usbamos 2 condiciones:

select *from libros


where autor='Borges' or autor='Paenza';

Podemos usar "in" y simplificar la consulta:


select *from libros
where autor in('Borges','Paenza');

Para recuperar los libros cuyo autor no sea 'Paenza' ni 'Borges' usbamos:

select *from libros


where autor<>'Borges' and
autor<>'Paenza';

Tambin podemos usar "in" anteponiendo "not":

select *from libros


where autor not in ('Borges','Paenza');

Empleando "in" averiguamos si el valor del campo est incluido en la lista de valores especificada;
con "not" antecediendo la condicin, invertimos el resultado, es decir, recuperamos los valores
que no se encuentran (coindicen) con la lista de valores.

Los valores "null" no se consideran.

Recuerde: siempre que sea posible, emplee condiciones de bsqueda positivas ("in"), evite las
negativas ("not in") porque con ellas se evaln todos los registros y esto hace ms lenta la
recuperacin de los datos.

Trabaje con la tabla llamada "medicamentos" de una farmacia.


1- Elimine la tabla, si existe:
if object_id('medicamentos') is not null
drop table medicamentos;

2- Cree la tabla con la siguiente estructura:


create table medicamentos(
codigo int identity,
nombre varchar(20),
laboratorio varchar(20),
precio decimal(6,2),
cantidad tinyint,
fechavencimiento datetime not null,
primary key(codigo)
);

3- Ingrese algunos registros:


insert into medicamentos
values('Sertal','Roche',5.2,1,'2005-02-01');
insert into medicamentos
values('Buscapina','Roche',4.10,3,'2006-03-01');
insert into medicamentos
values('Amoxidal 500','Bayer',15.60,100,'2007-05-01');
insert into medicamentos
values('Paracetamol 500','Bago',1.90,20,'2008-02-01');
insert into medicamentos
values('Bayaspirina','Bayer',2.10,150,'2009-12-01');
insert into medicamentos
values('Amoxidal jarabe','Bayer',5.10,250,'2010-10-01');

4- Recupere los nombres y precios de los medicamentos cuyo laboratorio sea "Bayer" o
"Bago"
empleando el operador "in" (4 registros)

5- Seleccione los remedios cuya cantidad se encuentre entre 1 y 5 empleando el


operador "between" y
luego el operador "in" (2 registros):
select *from medicamentos
where cantidad between 1 and 5;
select *from medicamentos
where cantidad in (1,2,3,4,5);
Note que es ms conveniente emplear, en este caso, el operador ""between".

if object_id('medicamentos') is not null


drop table medicamentos;

create table medicamentos(


codigo int identity,
nombre varchar(20),
laboratorio varchar(20),
precio decimal(6,2),
cantidad tinyint,
fechavencimiento datetime not null,
primary key(codigo)
);

insert into medicamentos


values('Sertal','Roche',5.2,1,'2005-02-01');
insert into medicamentos
values('Buscapina','Roche',4.10,3,'2006-03-01');
insert into medicamentos
values('Amoxidal 500','Bayer',15.60,100,'2007-05-01');
insert into medicamentos
values('Paracetamol 500','Bago',1.90,20,'2008-02-01');
insert into medicamentos
values('Bayaspirina','Bayer',2.10,150,'2009-12-01');
insert into medicamentos
values('Amoxidal jarabe','Bayer',5.10,250,'2010-10-01');

select nombre,precio from medicamentos


where laboratorio in ('Bayer','Bago');

select *from medicamentos


where cantidad between 1 and 5;

select *from medicamentos


where cantidad in (1,2,3,4,5);
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":

select *from libros


where autor='Borges';

El operador igual ("=") nos permite comparar cadenas de caracteres, pero al realizar la
comparacin, busca coincidencias de cadenas completas, realiza una bsqueda exacta.

Imaginemos que tenemos registrados estos 2 libros:

"El Aleph", "Borges";


"Antologia poetica", "J.L. Borges";

Si queremos recuperar todos los libros de "Borges" y especificamos la siguiente condicin:

select *from libros


where autor='Borges';

slo aparecer el primer registro, ya que la cadena "Borges" no es igual a la cadena "J.L. Borges".

Esto sucede porque el operador "=" (igual), tambin 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:

select *from libros


where autor like "%Borges%";

El smbolo "%" (porcentaje) reemplaza cualquier cantidad de caracteres (incluyendo ningn


caracter). Es un caracter comodn. "like" y "not like" son operadores de comparacin que sealan
igualdad o diferencia.

Para seleccionar todos los libros que comiencen con "M":

select *from libros


where titulo like 'M%';

Note que el smbolo "%" ya no est al comienzo, con esto indicamos que el ttulo debe tener como
primera letra la "M" y luego, cualquier cantidad de caracteres.

Para seleccionar todos los libros que NO comiencen con "M":


select *from libros
where titulo not like 'M%';

As como "%" reemplaza cualquier cantidad de caracteres, el guin bajo "_" reemplaza un
caracter, es otro caracter comodn. Por ejemplo, queremos ver los libros de "Lewis Carroll" pero
no recordamos si se escribe "Carroll" o "Carrolt", entonces tipeamos esta condicin:

select *from libros


where autor like "%Carrol_";

Otro caracter comodn es [] reemplaza cualquier carcter contenido en el conjunto especificado


dentro de los corchetes.

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:

... like '[a-cf-i]%': busca cadenas que comiencen con a,b,c,f,g,h o i;


... like '[-acfi]%': busca cadenas que comiencen con -,a,c,f o i;
... like 'A[_]9%': busca cadenas que comiencen con 'A_9';
... like 'A[nm]%': busca cadenas que comiencen con 'An' o 'Am'.

El cuarto caracter comodn es [^] reemplaza cualquier caracter NO presente en el conjunto


especificado dentro de los corchetes.

Para seleccionar los libros cuya editorial NO comienza con las letras "P" ni "N" tipeamos:

select titulo,autor,editorial
from libros
where editorial like '[^PN]%';

"like" se emplea con tipos de datos char, nchar, varchar, nvarchar o datetime. Si empleamos
"like" con tipos de datos que no son caracteres, SQL Server convierte (si es posible) el tipo de
dato a caracter. Por ejemplo, queremos buscar todos los libros cuyo precio se encuentre entre
10.00 y 19.99:

select titulo,precio from libros


where precio like '1_.%';

Queremos los libros que NO incluyen centavos en sus precios:

select titulo,precio from libros


where precio like '%.00';

Para bsquedas de caracteres comodines como literales, debe incluirlo dentro de corchetes, por
ejemplo, si busca:

... like '%[%]%': busca cadenas que contengan el signo '%';


... like '%[_]%': busca cadenas que contengan el signo '_';
... like '%[[]%': busca cadenas que contengan el signo '[';

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)
);

3- Ingrese algunos registros:


insert into empleados
values('Juan Perez','22333444','Colon 123','1990-10-08','Gerencia',900.50);
insert into empleados
values('Ana Acosta','23444555','Caseros 987','1995-12-18','Secretaria',590.30);
insert into empleados
values('Lucas Duarte','25666777','Sucre 235','2005-05-15','Sistemas',790);
insert into empleados
values('Pamela Gonzalez','26777888','Sarmiento 873','1999-02-12','Secretaria',550);
insert into empleados
values('Marcos Juarez','30000111','Rivadavia 801','2002-09-22','Contaduria',630.70);
insert into empleados
values('Yolanda Perez','35111222','Colon 180','1990-10-08','Administracion',400);
insert into empleados
values('Rodolfo Perez','35555888','Coronel Olmedo 588','1990-05-
28','Sistemas',800);

4- Muestre todos los empleados con apellido "Perez" empleando el operador "like" (3
registros)

5- Muestre todos los empleados cuyo domicilio comience con "Co" y tengan un "8" (2
registros)

6- Seleccione todos los empleados cuyo documento finalice en 0,2,4,6 u 8 (4 registros)

7- Seleccione todos los empleados cuyo documento NO comience con 1 ni 3 y cuyo


nombre finalice en
"ez" (2 registros)

8- Recupere todos los nombres que tengan una "y" o una "j" en su nombre o apellido
(3 registros)
9- Muestre los nombres y seccin de los empleados que pertenecen a secciones que
comiencen con "S" o
"G" y tengan 8 caracteres (3 registros)

10- Muestre los nombres y seccin 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)

12- Muestre los empleados que hayan ingresado en "1990" (3 registros)

if object_id('empleados') is not null


drop table empleados;

create table empleados(


nombre varchar(30),
documento char(8),
domicilio varchar(30),
fechaingreso datetime,
seccion varchar(20),
sueldo decimal(6,2),
primary key(documento)
);

insert into empleados


values('Juan Perez','22333444','Colon 123','1990-10-08','Gerencia',900.50);
insert into empleados
values('Ana Acosta','23444555','Caseros 987','1995-12-18','Secretaria',590.30);
insert into empleados
values('Lucas Duarte','25666777','Sucre 235','2005-05-15','Sistemas',790);
insert into empleados
values('Pamela Gonzalez','26777888','Sarmiento 873','1999-02-12','Secretaria',550);
insert into empleados
values('Marcos Juarez','30000111','Rivadavia 801','2002-09-22','Contaduria',630.70);
insert into empleados
values('Yolanda Perez','35111222','Colon 180','1990-10-08','Administracion',400);
insert into empleados
values('Rodolfo Perez','35555888','Coronel Olmedo 588','1990-05-
28','Sistemas',800);

select *from empleados


where nombre like '%Perez%';

select *from empleados


where domicilio like 'Co%8%';

select *from empleados


where documento like '%[02468]';
select *from empleados
where documento like '[^13]%' and
nombre like '%ez';

select nombre from empleados


where nombre like '%[yj]%';

select nombre,seccion from empleados


where seccion like '[SG]_______';

select nombre,seccion from empleados


where seccion not like '[SG]%';

select nombre,sueldo from empleados


where sueldo not like '%.00';

select *from empleados


where fechaingreso like '%1990%';

Existen en SQL Server funciones que nos permiten contar registros, calcular sumas, promedios,
obtener valores mximos y mnimos. Estas funciones se denominan funciones de agregado y
operan sobre un conjunto de valores (registros), no con datos individuales y devuelven un nico
valor.

Imaginemos que nuestra tabla "libros" contiene muchos registros. Para averiguar la cantidad sin
necesidad de contarlos manualmente usamos la funcin "count()":

select count(*)
from libros;

La funcin "count()" cuenta la cantidad de registros de una tabla, incluyendo los que tienen valor
nulo.

Tambin podemos utilizar esta funcin junto con la clusula "where" para una consulta ms
especfica. 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 funcin "count()" y en los parntesis 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.
Trabaje con la tabla llamada "medicamentos" de una farmacia.
1- Elimine la tabla, si existe:
if object_id('medicamentos') is not null
drop table medicamentos;

2- Cree la tabla con la siguiente estructura:


create table medicamentos(
codigo int identity,
nombre varchar(20),
laboratorio varchar(20),
precio decimal(6,2),
cantidad tinyint,
fechavencimiento datetime not null,
numerolote int default null,
primary key(codigo)
);

3- Ingrese algunos registros:


insert into medicamentos
values('Sertal','Roche',5.2,1,'2005-02-01',null);
insert into medicamentos
values('Buscapina','Roche',4.10,3,'2006-03-01',null);
insert into medicamentos
values('Amoxidal 500','Bayer',15.60,100,'2007-05-01',null);
insert into medicamentos
values('Paracetamol 500','Bago',1.90,20,'2008-02-01',null);
insert into medicamentos
values('Bayaspirina',null,2.10,null,'2009-12-01',null);
insert into medicamentos
values('Amoxidal jarabe','Bayer',null,250,'2009-12-15',null);

4- Muestre la cantidad de registros empleando la funcin "count(*)" (6 registros)

5- Cuente la cantidad de medicamentos que tienen laboratorio conocido (5 registros)

6- Cuente la cantidad de medicamentos que tienen precio distinto a "null" y que tienen
cantidad
distinto a "null", disponer alias para las columnas.

7- Cuente la cantidad de remedios con precio conocido, cuyo laboratorio comience con
"B" (2
registros)

8- Cuente la cantidad de medicamentos con nmero de lote distitno de "null" (0


registros)

if object_id('medicamentos') is not null


drop table medicamentos;

create table medicamentos(


codigo int identity,
nombre varchar(20),
laboratorio varchar(20),
precio decimal(6,2),
cantidad tinyint,
fechavencimiento datetime not null,
numerolote int default null,
primary key(codigo)
);

insert into medicamentos


values('Sertal','Roche',5.2,1,'2005-02-01',null);
insert into medicamentos
values('Buscapina','Roche',4.10,3,'2006-03-01',null);
insert into medicamentos
values('Amoxidal 500','Bayer',15.60,100,'2007-05-01',null);
insert into medicamentos
values('Paracetamol 500','Bago',1.90,20,'2008-02-01',null);
insert into medicamentos
values('Bayaspirina',null,2.10,null,'2009-12-01',null);
insert into medicamentos
values('Amoxidal jarabe','Bayer',null,250,'2009-12-15',null);

select count(*)
from medicamentos;

select count(laboratorio)
from medicamentos;

select count(precio) as 'Con precio',


count(cantidad) as 'Con cantidad'
from medicamentos;

select count(precio)
from medicamentos
where laboratorio like 'B%';

select count(numerolote) from medicamentos;

Retorna la cantidad de registros. Es similar a la funcin "count(*)", la diferencia es que


"count_big" retorna un valor "bigint" y "count", un "int".

"count_big(*)" cuenta la cantidad de registros de una tabla, incluyendo los valores nulos y
duplicados.

"count_big(CAMPO)" retorna la cantidad de registros cuyo valor en el campo especificado entre


parntesis no es nulo.

"count_big(distinct CAMPO)" retorna la cantidad de registros cuyo valor en el campo especificado


no es nulo, sin considerar los repetidos.
Averiguemos la cantidad de libros usando la funcin "count_big()":

select count_big(*)
from libros;

Note que incluye todos los libros aunque tengan valor nulo en algn campo.

Contamos los libros de editorial "Planeta":

select count_big(*)
from libros
where editorial='Planeta';

Contamos los registros que tienen precio (sin tener en cuenta los que tienen valor nulo):

select count_big(precio)
from libros;

Contamos las editoriales (sin repetir):

select count_big(distinct editorial)


from libros;

Primer problema:

Trabaje con la tabla llamada "medicamentos" de una farmacia.


1- Elimine la tabla, si existe:
if object_id('medicamentos') is not null
drop table medicamentos;

2- Cree la tabla con la siguiente estructura:


create table medicamentos(
codigo int identity,
nombre varchar(20),
laboratorio varchar(20),
precio decimal(6,2),
cantidad tinyint,
fechavencimiento datetime not null,
numerolote int default null,
primary key(codigo)
);

3- Ingrese algunos registros:


insert into medicamentos
values('Sertal','Roche',5.2,1,'2005-02-01',null);
insert into medicamentos
values('Buscapina','Roche',4.10,3,'2006-03-01',null);
insert into medicamentos
values('Amoxidal 500','Bayer',15.60,100,'2007-05-01',null);
insert into medicamentos
values('Paracetamol 500','Bago',1.90,20,'2008-02-01',null);
insert into medicamentos
values('Bayaspirina',null,2.10,null,'2009-12-01',null);
insert into medicamentos
values('Amoxidal jarabe','Bayer',null,250,'2009-12-15',null);

4- Muestre la cantidad de registros empleando la funcin "count_big(*)" (6 registros)

5- Cuente la cantidad de laboratorios distintos (3 registros)

6- Cuente la cantidad de medicamentos que tienen precio y cantidad distinto de "null"


(5 y 5)

if object_id('medicamentos') is not null


drop table medicamentos;

create table medicamentos(


codigo int identity,
nombre varchar(20),
laboratorio varchar(20),
precio decimal(6,2),
cantidad tinyint,
fechavencimiento datetime not null,
numerolote int default null,
primary key(codigo)
);

insert into medicamentos


values('Sertal','Roche',5.2,1,'2005-02-01',null);
insert into medicamentos
values('Buscapina','Roche',4.10,3,'2006-03-01',null);
insert into medicamentos
values('Amoxidal 500','Bayer',15.60,100,'2007-05-01',null);
insert into medicamentos
values('Paracetamol 500','Bago',1.90,20,'2008-02-01',null);
insert into medicamentos
values('Bayaspirina',null,2.10,null,'2009-12-01',null);
insert into medicamentos
values('Amoxidal jarabe','Bayer',null,250,'2009-12-15',null);

select count_big(*)
from medicamentos;

select count_big(distinct laboratorio)


from medicamentos;

select count_big(precio) as 'Con precio',


count_big(cantidad) as 'Con cantidad'
from medicamentos;

Hemos visto que SQL Server tiene funciones que nos permiten contar registros, calcular sumas,
promedios, obtener valores mximos y mnimos, las funciones de agregado.
Ya hemos aprendido una de ellas, "count()", veamos otras.

Se pueden usar en una instruccin "select" y combinarlas con la clusula "group by".

Todas estas funciones retornan "null" si ningn registro cumple con la condicin del "where",
excepto "count" que en tal caso retorna cero.

El tipo de dato del campo determina las funciones que se pueden emplear con ellas.

Las relaciones entre las funciones de agrupamiento y los tipos de datos es la siguiente:

- count: se puede emplear con cualquier tipo de dato.

- min y max: con cualquier tipo de dato.

- sum y avg: slo en campos de tipo numrico.

La funcin "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 mximo o mnimo de un campo usamos las funciones "max()" y "min()"
respectivamente.
Queremos saber cul es el mayor precio de todos los libros:

select max(precio)
from libros;

Entonces, dentro del parntesis de la funcin colocamos el nombre del campo del cul queremos
el mximo valor.

La funcin "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%';

Ahora podemos entender porque estas funciones se denominan "funciones de agrupamiento",


porque operan sobre conjuntos de registros, no con datos individuales.

Tratamiento de los valores nulos:

Si realiza una consulta con la funcin "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".
Primer 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,
primary key(documento)
);

3- Ingrese algunos registros:


insert into empleados
values('Juan Perez','22333444','Colon 123','Gerencia',5000,2);
insert into empleados
values('Ana Acosta','23444555','Caseros 987','Secretaria',2000,0);
insert into empleados
values('Lucas Duarte','25666777','Sucre 235','Sistemas',4000,1);
insert into empleados
values('Pamela Gonzalez','26777888','Sarmiento 873','Secretaria',2200,3);
insert into empleados
values('Marcos Juarez','30000111','Rivadavia 801','Contaduria',3000,0);
insert into empleados
values('Yolanda Perez','35111222','Colon 180','Administracion',3200,1);
insert into empleados
values('Rodolfo Perez','35555888','Coronel Olmedo 588','Sistemas',4000,3);
insert into empleados
values('Martina Rodriguez','30141414','Sarmiento 1234','Administracion',3800,4);
insert into empleados
values('Andres Costa','28444555',default,'Secretaria',null,null);

4- Muestre la cantidad de empleados usando "count" (9 empleados)

5- Muestre la cantidad de empleados con sueldo no nulo de la seccin "Secretaria" (2


empleados)

6- Muestre el sueldo ms alto y el ms bajo colocando un alias (5000 y 2000)

7- Muestre el valor mayor de "cantidadhijos" de los empleados "Perez" (3 hijos)

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 seccin "Secretara" (2100)

10- Muestre el promedio de hijos de todos los empleados de "Sistemas" (2)

if object_id('empleados') is not null


drop table empleados;

create table empleados(


nombre varchar(30),
documento char(8),
domicilio varchar(30),
seccion varchar(20),
sueldo decimal(6,2),
cantidadhijos tinyint,
primary key(documento)
);

insert into empleados


values('Juan Perez','22333444','Colon 123','Gerencia',5000,2);
insert into empleados
values('Ana Acosta','23444555','Caseros 987','Secretaria',2000,0);
insert into empleados
values('Lucas Duarte','25666777','Sucre 235','Sistemas',4000,1);
insert into empleados
values('Pamela Gonzalez','26777888','Sarmiento 873','Secretaria',2200,3);
insert into empleados
values('Marcos Juarez','30000111','Rivadavia 801','Contaduria',3000,0);
insert into empleados
values('Yolanda Perez','35111222','Colon 180','Administracion',3200,1);
insert into empleados
values('Rodolfo Perez','35555888','Coronel Olmedo 588','Sistemas',4000,3);
insert into empleados
values('Martina Rodriguez','30141414','Sarmiento 1234','Administracion',3800,4);
insert into empleados
values('Andres Costa','28444555',default,'Secretaria',null,null);

select count(*)
from empleados;

select count(sueldo)
from empleados
where seccion='Secretaria';

select max(sueldo) as 'Mayor sueldo',


min(sueldo) as 'Menor sueldo'
from empleados;

select max(cantidadhijos)
from empleados
where nombre like '%Perez%';

select avg(sueldo)
from empleados;

select avg(sueldo)
from empleados
where seccion='Secretaria';

select avg(cantidadhijos)
from empleados
where seccion='Sistemas';

As como la clusula "where" permite seleccionar (o rechazar) registros individuales; la clusula


"having" permite seleccionar (o rechazar) un grupo de registros.

Si queremos saber la cantidad de libros agrupados por editorial usamos la siguiente instruccin ya
aprendida:

select editorial, count(*)


from libros
group by editorial;

Si queremos saber la cantidad de libros agrupados por editorial pero considerando slo algunos
grupos, por ejemplo, los que devuelvan un valor mayor a 2, usamos la siguiente instruccin:

select editorial, count(*) from libros


group by editorial
having count(*)>2;

Se utiliza "having", seguido de la condicin de bsqueda, para seleccionar ciertas filas retornadas
por la clusula "group by".

Veamos otros ejemplos. Queremos el promedio de los precios de los libros agrupados por
editorial, pero solamente de aquellos grupos cuyo promedio supere los 25 pesos:

select editorial, avg(precio) from libros


group by editorial
having avg(precio)>25;

En algunos casos es posible confundir las clusulas "where" y "having". Queremos contar los
registros agrupados por editorial sin tener en cuenta a la editorial "Planeta".
Analicemos las siguientes sentencias:

select editorial, count(*) from libros


where editorial<>'Planeta'
group by editorial;
select editorial, count(*) from libros
group by editorial
having editorial<>'Planeta';

Ambas devuelven el mismo resultado, pero son diferentes. La primera, selecciona todos 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".

No debemos confundir la clusula "where" con la clusula "having"; la primera establece


condiciones para la seleccin de registros de un "select"; la segunda establece condiciones para la
seleccin de registros de una salida "group by".

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":

select editorial, count(*) from libros


where precio is not null
group by editorial
having editorial<>'Planeta';

Aqu, selecciona los registros rechazando los que no cumplan con la condicin dada en "where",
luego los agrupa por "editorial" y finalmente rechaza los grupos que no cumplan con la condicin
dada en el "having".

Se emplea la clusula "having" con funciones de agrupamiento, esto no puede hacerlo la clusula
"where". Por ejemplo queremos el promedio de los precios agrupados por editorial, de aquellas
editoriales que tienen ms de 2 libros:

select editorial, avg(precio) from libros


group by editorial
having count(*) > 2;

En una clusula "having" puede haber hasta 128 condiciones. Cuando utilice varias condiciones,
tiene que combinarlas con operadores lgicos (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:

select editorial, max(precio) as 'mayor'


from libros
group by editorial
having min(precio)<100 and
min(precio)>30
order by editorial;

Entonces, usamos la clasula "having" para restringir las filas que devuelve una salida "group by".
Va siempre despus de la clusula "group by" y antes de la clusula "order by" si la hubiere.

Primer problema:

Una empresa tiene registrados sus clientes en una tabla llamada "clientes".
1- Elimine la tabla "clientes", si existe:
if object_id('clientes') is not null
drop table clientes;
2- Crela con la siguiente estructura:
create table clientes (
codigo int identity,
nombre varchar(30) not null,
domicilio varchar(30),
ciudad varchar(20),
provincia varchar (20),
telefono varchar(11),
primary key(codigo)
);

3- Ingrese algunos registros:


insert into clientes
values ('Lopez Marcos','Colon 111','Cordoba','Cordoba','null');
insert into clientes
values ('Perez Ana','San Martin 222','Cruz del Eje','Cordoba','4578585');
insert into clientes
values ('Garcia Juan','Rivadavia 333','Villa del Rosario','Cordoba','4578445');
insert into clientes
values ('Perez Luis','Sarmiento 444','Rosario','Santa Fe',null);
insert into clientes
values ('Pereyra Lucas','San Martin 555','Cruz del Eje','Cordoba','4253685');
insert into clientes
values ('Gomez Ines','San Martin 666','Santa Fe','Santa Fe','0345252525');
insert into clientes
values ('Torres Fabiola','Alem 777','Villa del Rosario','Cordoba','4554455');
insert into clientes
values ('Lopez Carlos',null,'Cruz del Eje','Cordoba',null);
insert into clientes
values ('Ramos Betina','San Martin 999','Cordoba','Cordoba','4223366');
insert into clientes
values ('Lopez Lucas','San Martin 1010','Posadas','Misiones','0457858745');

4- Obtenga el total de los registros agrupados por ciudad y provincia (6 filas)

5- Obtenga el total de los registros agrupados por ciudad y provincia sin considerar los
que tienen
menos de 2 clientes (3 filas)

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)

if object_id('clientes') is not null


drop table clientes;
create table clientes (
codigo int identity,
nombre varchar(30) not null,
domicilio varchar(30),
ciudad varchar(20),
provincia varchar (20),
telefono varchar(11),
primary key(codigo)
);

insert into clientes


values ('Lopez Marcos','Colon 111','Cordoba','Cordoba','null');
insert into clientes
values ('Perez Ana','San Martin 222','Cruz del Eje','Cordoba','4578585');
insert into clientes
values ('Garcia Juan','Rivadavia 333','Villa del Rosario','Cordoba','4578445');
insert into clientes
values ('Perez Luis','Sarmiento 444','Rosario','Santa Fe',null);
insert into clientes
values ('Pereyra Lucas','San Martin 555','Cruz del Eje','Cordoba','4253685');
insert into clientes
values ('Gomez Ines','San Martin 666','Santa Fe','Santa Fe','0345252525');
insert into clientes
values ('Torres Fabiola','Alem 777','Villa del Rosario','Cordoba','4554455');
insert into clientes
values ('Lopez Carlos',null,'Cruz del Eje','Cordoba',null);
insert into clientes
values ('Ramos Betina','San Martin 999','Cordoba','Cordoba','4223366');
insert into clientes
values ('Lopez Lucas','San Martin 1010','Posadas','Misiones','0457858745');

select ciudad, provincia,


count(*) as cantidad
from clientes
group by ciudad,provincia;

select ciudad, provincia,


count(*) as cantidad
from clientes
group by ciudad,provincia
having count(*)>1;

select ciudad, count(*)


from clientes
where domicilio like '%San Martin%'
group by all ciudad
having count(*)<2 and
ciudad <> 'Cordoba';

Podemos combinar "group by" con los operadores "rollup" y "cube" para generar valores de
resumen a la salida.
El operador "rollup" resume valores de grupos. representan los valores de resumen de la
precedente.

Tenemos la tabla "visitantes" con los siguientes campos: nombre, edad, sexo, domicilio, ciudad,
telefono, montocompra.

Si necesitamos la cantidad de visitantes por ciudad empleamos la siguiente sentencia:

select ciudad,count(*) as cantidad


from visitantes
group by ciudad;

Esta consulta muestra el total de visitantes agrupados por ciudad; pero si queremos adems la
cantidad total de visitantes, debemos realizar otra consulta:

select count(*) as total


from visitantes;

Para obtener ambos resultados en una sola consulta podemos usar "with rollup" que nos devolver
ambas salidas en una sola consulta:

select ciudad,count(*) as cantidad


from visitantes
group by ciudad with rollup;

La consulta anterior retorna los registros agrupados por ciudad y una fila extra en la que la
primera columna contiene "null" y la columna con la cantidad muestra la cantidad total.

La clusula "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":

select ciudad,sexo,count(*) as cantidad


from visitantes
group by ciudad,sexo
with rollup;

La salida muestra los totales por ciudad y sexo y produce tantas filas extras como valores 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 agrupacin,
aparece una fila extra con el/ los campos que no se consideran, seteados a "null".

Con "rollup" se puede agrupar hasta por 10 campos.

Es posible incluir varias funciones de agrupamiento, por ejemplo, queremos la cantidad de


visitantes y la suma de sus compras agrupados por ciudad y sexo:

select ciudad,sexo,
count(*) as cantidad,
sum(montocompra) as total
from visitantes
group by ciudad,sexo
with rollup;

Entonces, "rollup" es un modificador para "group by" que agrega filas extras mostrando 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".

Primer problema:

Una empresa tiene registrados sus clientes en una tabla llamada "clientes".
1- Elimine la tabla "clientes", si existe:
if object_id('clientes') is not null
drop table clientes;

2- Crela con la siguiente estructura:


create table clientes (
codigo int identity,
nombre varchar(30) not null,
domicilio varchar(30),
ciudad varchar(20),
estado varchar (20),
pais varchar(20),
primary key(codigo)
);

3- Ingrese algunos registros:


insert into clientes
values ('Lopez Marcos','Colon 111', 'Cordoba','Cordoba','Argentina');
insert into clientes
values ('Perez Ana','San Martin 222', 'Carlos Paz','Cordoba','Argentina');
insert into clientes
values ('Garcia Juan','Rivadavia 333', 'Carlos Paz','Cordoba','Argentina');
insert into clientes
values ('Perez Luis','Sarmiento 444', 'Rosario','Santa Fe','Argentina');
insert into clientes
values ('Gomez Ines','San Martin 987', 'Santa Fe','Santa Fe','Argentina');
insert into clientes
values ('Gomez Ines','San Martin 666', 'Santa Fe','Santa Fe','Argentina');
insert into clientes
values ('Lopez Carlos','Irigoyen 888', 'Cordoba','Cordoba','Argentina');
insert into clientes
values ('Ramos Betina','San Martin 999', 'Cordoba','Cordoba','Argentina');
insert into clientes
values ('Fernando Salas','Mariano Osorio 1234', 'Santiago','Region
metropolitana','Chile');
insert into clientes
values ('German Rojas','Allende 345', 'Valparaiso','Region V','Chile');
insert into clientes
values ('Ricardo Jara','Pablo Neruda 146', 'Santiago','Region metropolitana','Chile');
insert into clientes
values ('Joaquin Robles','Diego Rivera 147', 'Guadalajara','Jalisco','Mexico');

4- Necesitamos la cantidad de clientes por pas y la cantidad total de clientes en una


sola consulta
(4 filas)
Note que la consulta retorna los registros agrupados por pais y una fila extra en la que
la columna
"pais" contiene "null" y la columna con la cantidad muestra la cantidad total.

5- Necesitamos la cantidad de clientes agrupados por pais y estado, incluyendo


resultados paciales
(9 filas)
Note que la salida muestra los totales por pais y estado y produce 4 filas extras: 3
muestran los
totales para cada pais, con la columna "estado" conteniendo "null" y 1 muestra el total
de todos los
clientes, con las columnas "pais" y "estado" conteniendo "null".

6- Necesitamos la cantidad de clientes agrupados por pais, estado y ciudad,


empleando "rollup" (16
filas)
El resultado muestra los totales por pais, estado y ciudad y genera 9 filas extras: 5
muestran los
totales para cada estado, con la columna correspondiente a "ciudad" conteniendo
"null", 3 muestran
los totales para cada pais, con las columnas "ciudad" y "estado" conteniendo "null" y 1
muestra el
total de todos los clientes, con las columnas "pais", "estado" y "ciudad" conteniendo
"null".

Primer problema:

Una empresa tiene registrados sus clientes en una tabla llamada "clientes".
1- Elimine la tabla "clientes", si existe:
if object_id('clientes') is not null
drop table clientes;

2- Crela con la siguiente estructura:


create table clientes (
codigo int identity,
nombre varchar(30) not null,
domicilio varchar(30),
ciudad varchar(20),
estado varchar (20),
pais varchar(20),
primary key(codigo)
);

3- Ingrese algunos registros:


insert into clientes
values ('Lopez Marcos','Colon 111', 'Cordoba','Cordoba','Argentina');
insert into clientes
values ('Perez Ana','San Martin 222', 'Carlos Paz','Cordoba','Argentina');
insert into clientes
values ('Garcia Juan','Rivadavia 333', 'Carlos Paz','Cordoba','Argentina');
insert into clientes
values ('Perez Luis','Sarmiento 444', 'Rosario','Santa Fe','Argentina');
insert into clientes
values ('Gomez Ines','San Martin 987', 'Santa Fe','Santa Fe','Argentina');
insert into clientes
values ('Gomez Ines','San Martin 666', 'Santa Fe','Santa Fe','Argentina');
insert into clientes
values ('Lopez Carlos','Irigoyen 888', 'Cordoba','Cordoba','Argentina');
insert into clientes
values ('Ramos Betina','San Martin 999', 'Cordoba','Cordoba','Argentina');
insert into clientes
values ('Fernando Salas','Mariano Osorio 1234', 'Santiago','Region
metropolitana','Chile');
insert into clientes
values ('German Rojas','Allende 345', 'Valparaiso','Region V','Chile');
insert into clientes
values ('Ricardo Jara','Pablo Neruda 146', 'Santiago','Region metropolitana','Chile');
insert into clientes
values ('Joaquin Robles','Diego Rivera 147', 'Guadalajara','Jalisco','Mexico');

4- Necesitamos la cantidad de clientes por pas y la cantidad total de clientes en una


sola consulta
(4 filas)
Note que la consulta retorna los registros agrupados por pais y una fila extra en la que
la columna
"pais" contiene "null" y la columna con la cantidad muestra la cantidad total.

5- Necesitamos la cantidad de clientes agrupados por pais y estado, incluyendo


resultados paciales
(9 filas)
Note que la salida muestra los totales por pais y estado y produce 4 filas extras: 3
muestran los
totales para cada pais, con la columna "estado" conteniendo "null" y 1 muestra el total
de todos los
clientes, con las columnas "pais" y "estado" conteniendo "null".

6- Necesitamos la cantidad de clientes agrupados por pais, estado y ciudad,


empleando "rollup" (16
filas)
El resultado muestra los totales por pais, estado y ciudad y genera 9 filas extras: 5
muestran los
totales para cada estado, con la columna correspondiente a "ciudad" conteniendo
"null", 3 muestran
los totales para cada pais, con las columnas "ciudad" y "estado" conteniendo "null" y 1
muestra el
total de todos los clientes, con las columnas "pais", "estado" y "ciudad" conteniendo
"null".
if object_id('clientes') is not null
drop table clientes;

create table clientes (


codigo int identity,
nombre varchar(30) not null,
domicilio varchar(30),
ciudad varchar(20),
estado varchar (20),
pais varchar(20),
primary key(codigo)
);

insert into clientes


values ('Lopez Marcos','Colon 111', 'Cordoba','Cordoba','Argentina');
insert into clientes
values ('Perez Ana','San Martin 222', 'Carlos Paz','Cordoba','Argentina');
insert into clientes
values ('Garcia Juan','Rivadavia 333', 'Carlos Paz','Cordoba','Argentina');
insert into clientes
values ('Perez Luis','Sarmiento 444', 'Rosario','Santa Fe','Argentina');
insert into clientes
values ('Gomez Ines','San Martin 987', 'Santa Fe','Santa Fe','Argentina');
insert into clientes
values ('Gomez Ines','San Martin 666', 'Santa Fe','Santa Fe','Argentina');
insert into clientes
values ('Lopez Carlos','Irigoyen 888', 'Cordoba','Cordoba','Argentina');
insert into clientes
values ('Ramos Betina','San Martin 999', 'Cordoba','Cordoba','Argentina');
insert into clientes
values ('Fernando Salas','Mariano Osorio 1234', 'Santiago','Region
metropolitana','Chile');
insert into clientes
values ('German Rojas','Allende 345', 'Valparaiso','Region V','Chile');
insert into clientes
values ('Ricardo Jara','Pablo Neruda 146', 'Santiago','Region metropolitana','Chile');
insert into clientes
values ('Joaquin Robles','Diego Rivera 147', 'Guadalajara','Jalisco','Mexico');

select pais,count(*) as cantidad


from clientes
group by pais with rollup;

select pais,estado,
count(*) as cantidad
from clientes
group by pais,estado with rollup;

select pais,estado,ciudad,
count(*) as cantidad
from clientes
group by pais,estado,ciudad
with rollup;

Hemos aprendido el modificador "rollup", que agrega filas extras mostrando resultados de
resumen por cada grupo y subgrupo.

Por ejemplo, tenemos una tabla llamada "empleados" que contiene, entre otros, los campos
"sexo", "estadocivil" y "seccion".

Si se agrupa por esos tres campos (en ese orden) y se emplea "rollup":

select sexo,estadocivil,seccion,
count(*) from empleados
group by sexo,estadocivil,seccion
with rollup;

SQL Server genera varias filas extras con informacin de resumen para los siguientes subgrupos:

- sexo y estadocivil (seccion seteado a "null"),


- sexo (estadocivil y seccion seteados a "null") y
- total (todos los campos seteados a "null").

Si se emplea "cube":

select sexo,estadocivil,seccion,
count(*) from empleados
group by sexo,estadocivil,seccion
with cube;

retorna ms filas extras adems de las anteriores:

- sexo y seccion (estadocivil seteado a "null"),


- estadocivil y seccion (sexo seteado a "null"),
- seccion (sexo y estadocivil seteados a "null") y
- estadocivil (sexo y seccion seteados a "null"),

Es decir, "cube" genera filas de resumen de subgrupos para todas las combinaciones posibles de
los valores de los campos por los que agrupamos.

Se pueden colocar hasta 10 campos en el "group by".

Con "cube" se puede emplear "where" y "having", pero no es compatible con "all".

Primer problema:

Un comercio guarda la informacin de sus ventas en una tabla llamada "ventas" en la


que se registra
diariamente, el nmero de venta, el monto total de la compra, el tipo de pago
(c=contado, t=tarjeta)
y el nombre del vendedor.
1- Elimine la tabla si existe:
if object_id('ventas') is not null
drop table ventas;

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)
);

3- Ingrese algunos registros:


insert into ventas
values(100.50,'c','Marisa Perez');
insert into ventas
values(200,'c','Marisa Perez');
insert into ventas
values(50,'t','Juan Lopez');
insert into ventas
values(220,'c','Juan Lopez');
insert into ventas
values(150,'t','Marisa Perez');
insert into ventas
values(550.80,'c','Marisa Perez');
insert into ventas
values(300,'t','Juan Lopez');
insert into ventas
values(25,'c','Marisa Perez');

4- Agrupe por "tipopago" y "vendedor" y cuente la cantidad empleando "rollup".


Las agrupaciones de resumen son las siguientes:
- vendedor (tipopago seteado a "null"), 2 filas y
- total (todos los campos seteados a "null"), 1 fila

5- Agrupe por "tipopago" y "vendedor" y cuente la cantidad empleando "cube".


Las agrupaciones de resumen son las siguientes:
- vendedor (tipopago seteado a "null"), 2 filas,
- total (todos los campos seteados a "null"), 1 fila y
- tipopago (vendedor seteado a "null"), 2 filas.

if object_id('ventas') is not null


drop table ventas;

create table ventas(


numero int identity,
montocompra decimal(6,2),
tipopago char(1),--c=contado, t=tarjeta
vendedor varchar(30),
primary key (numero)
);

insert into ventas


values(100.50,'c','Marisa Perez');
insert into ventas
values(200,'c','Marisa Perez');
insert into ventas
values(50,'t','Juan Lopez');
insert into ventas
values(220,'c','Juan Lopez');
insert into ventas
values(150,'t','Marisa Perez');
insert into ventas
values(550.80,'c','Marisa Perez');
insert into ventas
values(300,'t','Juan Lopez');
insert into ventas
values(25,'c','Marisa Perez');

select vendedor,tipopago,
count(*) as cantidad
from ventas
group by vendedor,tipopago
with rollup;

select vendedor,tipopago,
count(*) as cantidad
from ventas
group by vendedor,tipopago
with cube;

La funcin "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 funcin 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.

Slo se puede emplear la funcin "grouping" en los campos que aparecen en la clusula "group
by".

Si tenemos una tabla "visitantes" con los siguientes registros almacenados:

Nombre sexo ciudad


-------------------------------
Susana Molina f Cordoba
Marcela Mercado f Cordoba
Roberto Perez f null
Alberto Garcia m Cordoba
Teresa Garcia f Alta Gracia

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;

aparece la siguiente salida:

ciudad cantidad
-------------------------
NULL 1
Alta Gracia 1
Cordoba 3
NULL 5

La ltima fila es la de resumen generada por "rollup", pero no es posible distinguirla de la primera
fila, en la cual "null" es un valor del campo. Para diferenciarla empleamos "grouping":

select ciudad,
count(*) as cantidad,
grouping(ciudad) as resumen
from visitantes
group by ciudad
with rollup;

aparece la siguiente salida:

ciudad cantidad resumen


---------------------------------------
NULL 1 0
Alta Gracia 1 0
Cordoba 3 0
NULL 5 1

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 funcin "grouping" para distinguir los valores de detalle y de resumen en
el resultado.

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;

2- Crela con la siguiente estructura:


create table empleados (
documento varchar(8) not null,
nombre varchar(30),
sexo char(1),
estadocivil char(1),--c=casado, s=soltero,v=viudo
seccion varchar(20),
primary key (documento)
);

3- Ingrese algunos registros:


insert into empleados
values ('22222222','Alberto Lopez','m','c','Sistemas');
insert into empleados
values ('23333333','Beatriz Garcia','f','c','Administracion');
insert into empleados
values ('24444444','Carlos Fuentes','m','s','Administracion');
insert into empleados
values ('25555555','Daniel Garcia','m','s','Sistemas');
insert into empleados
values ('26666666','Ester Juarez',null,'c','Sistemas');
insert into empleados
values ('27777777','Fabian Torres',null,'s','Sistemas');
insert into empleados
values ('28888888','Gabriela Lopez','f',null,'Sistemas');
insert into empleados
values ('29999999','Hector Garcia','m',null,'Administracion');

4- Cuente la cantidad de empleados agrupados por sexo y estado civil, empleando


"rollup".
Es dificil distinguir los valores de detalle y resumen.

5- Realice la misma consulta anterior pero emplee la funcin "grouping" para los dos
campos por los
que se agrupa para distinguir los valores de resumen y de detalle.
Note que las columnas de resumen contienen 1 y las de detalle 0.

6- Realice la misma consulta anterior pero con "cube" en lugar de "rollup",


distinguiendo los
valores de resumen y de detalle.
Note que las columnas de resumen contienen 1 y las de detalle 0.

if object_id('empleados') is not null


drop table empleados;

create table empleados (


documento varchar(8) not null,
nombre varchar(30),
sexo char(1),
estadocivil char(1),--c=casado, s=soltero,v=viudo
seccion varchar(20),
primary key (documento)
);

insert into empleados


values ('22222222','Alberto Lopez','m','c','Sistemas');
insert into empleados
values ('23333333','Beatriz Garcia','f','c','Administracion');
insert into empleados
values ('24444444','Carlos Fuentes','m','s','Administracion');
insert into empleados
values ('25555555','Daniel Garcia','m','s','Sistemas');
insert into empleados
values ('26666666','Ester Juarez',null,'c','Sistemas');
insert into empleados
values ('27777777','Fabian Torres',null,'s','Sistemas');
insert into empleados
values ('28888888','Gabriela Lopez','f',null,'Sistemas');
insert into empleados
values ('29999999','Hector Garcia','m',null,'Administracion');

select sexo,estadocivil,
count(*) as cantidad
from empleados
group by sexo,estadocivil
with rollup;

select sexo,estadocivil,
count(*) as cantidad,
grouping(sexo) as 'resumen sexo',
grouping(estadocivil) as 'resumen estado civil'
from empleados
group by sexo,estadocivil
with rollup;

select sexo,estadocivil,
count(*) as cantidad,
grouping(sexo) as 'resumen sexo',
grouping(estadocivil) as 'resumen estado civil'
from empleados
group by sexo,estadocivil
with cube;

Las clusulas "compute" y "compute by" generan totales que aparecen en columnas extras al final
del resultado.

Produce filas de detalle y un valor nico para una columna.

Se usa con las funciones de agrupamiento: avg(), count(), max(), min(), sum().
La sintaxis bsica y general es la siguiente:

select CAMPOS
from TABLA
compute FUNCION(CAMPO);

El campo que se coloque en la clusula "compute" debe estar incluida en la lista de campos del
"select".

Para ver todos los datos de los visitantes y el promedio del monto de compra de nuestra tabla
"visitantes":

select *from visitantes


compute avg(montocompra);

Produce la misma salida que las siguientes 2 sentencias:

select *from visitantes;


select avg(montocompra) from visitantes;

En una misma instruccin se pueden colocar varias clusulas "compute":

select edad,ciudad,montocompra
from visitantes
compute avg(edad),sum(montocompra);

"Compute by" genera cortes de control y subtotales. Se generan filas de detalle y varios valores
de resumen cuando cambian los valores del campo.

Con "compute by" se DEBE usar tambin la clusula "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 funcin 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 clusula "compute by" DEBEN ser idnticos a un subconjunto
de los campos que aparecen despus de "order by" y estar en el mismo orden. Si la clusula "order
by" tiene los siguientes campos:

... order by a,b,c...

la clusula "compute by" puede incluir los siguientes subconjuntos de campos:


... compute ...
by a...
o
... compute ...
by a,b...
o
... compute ...
by a,b,c...

En una misma instruccin se pueden colocar varias clusulas "compute" combinadas con varias
clusulas "compute by":

select *from visitantes


order by provincia,ciudad
compute avg(edad), sum(montocompra)
compute avg(montocompra),count(provincia)
by provincia,ciudad;

El resultado de la consulta anterior muestra el promedio de la compra y la cantidad al final de


cada subgrupo de provincia y ciudad (compute by) y el promedio de las edades y el total del
monto de compras de todos (compute).

Los tipos de datos ntext, text e image no se pueden incluir en una clusula "compute" o "compute
by".

Primer 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;

2- Crela con la siguiente estructura:


create table inmuebles (
documento varchar(8) not null,
nombre varchar(30),
domicilio varchar(20),
barrio varchar(20),
ciudad varchar(20),
tipo char(1),--b=baldio, e: edificado
superficie decimal (8,2),
monto decimal (8,2)
);

3- Ingrese algunos registros:


insert into inmuebles
values ('11111111','Alberto Acosta','Avellaneda 800','Centro','Cordoba','e',100,1200);
insert into inmuebles
values ('11111111','Alberto Acosta','Sarmiento 245','Gral.
Paz','Cordoba','e',200,2500);
insert into inmuebles
values ('22222222','Beatriz Barrios','San Martin 202','Centro','Cordoba','e',250,1900);
insert into inmuebles
values ('33333333','Carlos Caseres','Paso 1234','Alberdi','Cordoba','b',200,1000);
insert into inmuebles
values ('33333333','Carlos Caseres','Guemes 876','Alberdi','Cordoba','b',300,1500);
insert into inmuebles
values ('44444444','Diana Dominguez','Calderon
456','Matienzo','Cordoba','b',200,800);
insert into inmuebles
values ('55555555','Estela Fuentes','San Martin 321','Flores','Carlos
Paz','e',500,4500);
insert into inmuebles
values ('55555555','Estela Fuentes','Lopez y Planes
853','Alberdi','Cordoba','e',350,2200);

4- Muestre todos los datos y el promedio del monto empleando "compute" (1 resultado
parcial)

5- Empleando clusulas "compute" consulte el promedio de las superficies y el total de


los montos (2
columnas extras)

6- Realice la misma consulta anterior pero empleando "compute by" para obtener
resultados parciales
por documento,barrio y ciudad.

7- Realice la misma consulta anterior pero con resultados parciales por documento y
barrio (6
resultados parciales dobles)

8- Realice la misma consulta anterior pero con resultados parciales por documento (4
resultados
parciales dobles)

9- Intente realizar la misma consulta anterior pero con resultados parciales por
documento y ciudad.
Aparece un mensaje de error indicando que el subgrupo de campos listados luego del
"by" no es
correcto.

10- Combine clusulas "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)

if object_id('inmuebles') is not null


drop table inmuebles;

create table inmuebles (


documento varchar(8) not null,
nombre varchar(30),
domicilio varchar(20),
barrio varchar(20),
ciudad varchar(20),
tipo char(1),--b=baldio, e: edificado
superficie decimal (8,2),
monto decimal (8,2)
);

insert into inmuebles


values ('11111111','Alberto Acosta','Avellaneda 800','Centro','Cordoba','e',100,1200);
insert into inmuebles
values ('11111111','Alberto Acosta','Sarmiento 245','Gral.
Paz','Cordoba','e',200,2500);
insert into inmuebles
values ('22222222','Beatriz Barrios','San Martin 202','Centro','Cordoba','e',250,1900);
insert into inmuebles
values ('33333333','Carlos Caseres','Paso 1234','Alberdi','Cordoba','b',200,1000);
insert into inmuebles
values ('33333333','Carlos Caseres','Guemes 876','Alberdi','Cordoba','b',300,1500);
insert into inmuebles
values ('44444444','Diana Dominguez','Calderon
456','Matienzo','Cordoba','b',200,800);
insert into inmuebles
values ('55555555','Estela Fuentes','San Martin 321','Flores','Carlos
Paz','e',500,4500);
insert into inmuebles
values ('55555555','Estela Fuentes','Lopez y Planes
853','Alberdi','Cordoba','e',350,2200);

select *from inmuebles


compute avg(monto);

select *from inmuebles


compute avg(superficie),sum(monto);

select *from inmuebles


order by documento,barrio,ciudad
compute avg(superficie),sum(monto)
by documento,barrio,ciudad;

select *from inmuebles


order by documento,barrio,ciudad
compute avg(superficie),sum(monto)
by documento,barrio;

select *from inmuebles


order by documento,barrio,ciudad
compute avg(superficie),sum(monto)
by documento;

select *from inmuebles


order by documento,barrio,ciudad
compute avg(superficie),sum(monto)
by documento,ciudad;

select *from inmuebles


order by documento
compute sum(monto)
compute avg(monto)
by documento;

Con la clusula "distinct" se especifica que los registros con ciertos datos duplicados sean
obviadas en el resultado. Por ejemplo, queremos conocer todos los autores de los cuales tenemos
libros, si utilizamos esta sentencia:

select autor from libros;

Aparecen repetidos. Para obtener la lista de autores sin repeticin usamos:

select distinct autor from libros;

Tambin podemos tipear:

select autor from libros


group by autor;

Note que en los tres casos anteriores aparece "null" como un valor para "autor" Si slo queremos
la lista de autores conocidos, es decir, no queremos incluir "null" en la lista, podemos utilizar la
sentencia siguiente:

select distinct autor from libros


where autor is not null;

Para contar los distintos autores, sin considerar el valor "null" usamos:

select count(distinct autor)


from libros;

Note que si contamos los autores sin "distinct", no incluir los valores "null" pero si los repetidos:

select count(autor)
from libros;

Esta sentencia cuenta los registros que tienen autor.

Podemos combinarla con "where". Por ejemplo, queremos conocer los distintos autores de la
editorial "Planeta":

select distinct autor from libros


where editorial='Planeta';

Tambin puede utilizarse con "group by" para contar los diferentes autores por editorial:
select editorial, count(distinct autor)
from libros
group by editorial;

La clusula "distinct" afecta a todos los campos presentados. Para mostrar los ttulos y editoriales
de los libros sin repetir ttulos ni editoriales, usamos:

select distinct titulo,editorial


from libros
order by titulo;

Note que los registros no estn duplicados, aparecen ttulos iguales pero con editorial diferente,
cada registro es diferente.

La palabra clave "distinct" no est permitida con las clusulas "compute" y "compute by".

Entonces, "distinct" elimina registros duplicados.

Primer problema:

Una empresa tiene registrados sus clientes en una tabla llamada "clientes".
1- Elimine la tabla "clientes", si existe:
if object_id('clientes') is not null
drop table clientes;

2- Crela con la siguiente estructura:


create table clientes (
codigo int identity,
nombre varchar(30) not null,
domicilio varchar(30),
ciudad varchar(20),
provincia varchar (20),
primary key(codigo)
);

3- Ingrese algunos registros:


insert into clientes
values ('Lopez Marcos','Colon 111','Cordoba','Cordoba');
insert into clientes
values ('Perez Ana','San Martin 222','Cruz del Eje','Cordoba');
insert into clientes
values ('Garcia Juan','Rivadavia 333','Villa del Rosario','Cordoba');
insert into clientes
values ('Perez Luis','Sarmiento 444','Rosario','Santa Fe');
insert into clientes
values ('Pereyra Lucas','San Martin 555','Cruz del Eje','Cordoba');
insert into clientes
values ('Gomez Ines','San Martin 666','Santa Fe','Santa Fe');
insert into clientes
values ('Torres Fabiola','Alem 777','Villa del Rosario','Cordoba');
insert into clientes
values ('Lopez Carlos',null,'Cruz del Eje','Cordoba');
insert into clientes
values ('Ramos Betina','San Martin 999','Cordoba','Cordoba');
insert into clientes
values ('Lopez Lucas','San Martin 1010','Posadas','Misiones');

4- Obtenga las provincias sin repetir (3 registros)

5- Cuente las distintas provincias.

6- Se necesitan los nombres de las ciudades sin repetir (6 registros)

7- Obtenga la cantidad de ciudades distintas.

8- Combine con "where" para obtener las distintas ciudades de la provincia de Cordoba
(3 registros)

9- Contamos las distintas ciudades de cada provincia empleando "group by" (3


registros)

if object_id('clientes') is not null


drop table clientes;

create table clientes (


codigo int identity,
nombre varchar(30) not null,
domicilio varchar(30),
ciudad varchar(20),
provincia varchar (20),
primary key(codigo)
);

insert into clientes


values ('Lopez Marcos','Colon 111','Cordoba','Cordoba');
insert into clientes
values ('Perez Ana','San Martin 222','Cruz del Eje','Cordoba');
insert into clientes
values ('Garcia Juan','Rivadavia 333','Villa del Rosario','Cordoba');
insert into clientes
values ('Perez Luis','Sarmiento 444','Rosario','Santa Fe');
insert into clientes
values ('Pereyra Lucas','San Martin 555','Cruz del Eje','Cordoba');
insert into clientes
values ('Gomez Ines','San Martin 666','Santa Fe','Santa Fe');
insert into clientes
values ('Torres Fabiola','Alem 777','Villa del Rosario','Cordoba');
insert into clientes
values ('Lopez Carlos',null,'Cruz del Eje','Cordoba');
insert into clientes
values ('Ramos Betina','San Martin 999','Cordoba','Cordoba');
insert into clientes
values ('Lopez Lucas','San Martin 1010','Posadas','Misiones');
select distinct provincia from clientes;

select count(distinct provincia) as cantidad


from clientes;

select distinct ciudad from clientes;

select count(distinct ciudad) from clientes;

select distinct ciudad from clientes


where provincia='Cordoba';

select provincia,count(distinct ciudad)


from clientes
group by provincia;

La palabra clave "top" se emplea para obtener slo 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:

select top 2 *from libros;

Es decir, luego del "select" se coloca "top" seguido de un nmero entero positivo y luego se
contina con la consulta.

Se puede combinar con "order by":

select top 3 titulo,autor


from libros
order by autor;

En la consulta anterior solicitamos los ttulos y autores de los 3 primeros libros, ordenados por
autor.

Cuando se combina con "order by" es posible emplear tambin la clusula "with ties". Esta
clusula 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
nmero 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 nmero 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 seleccin.

Veamos un ejemplo:

select top 3 with ties


*from libros
order by autor;
Esta consulta solicita el retorno de los primeros 3 registros; en caso que el registro nmero 4 (y
los posteriores), tengan el mismo valor en "autor" que el ltimo registro retornado (nmero 3),
tambin aparecern en la seleccin.

Si colocamos un valor para "top" que supera la cantidad de registros de la tabla, SQL Server
muestra todos los registros.

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;

2- Crela con la siguiente estructura:


create table empleados (
documento varchar(8) not null,
nombre varchar(30),
estadocivil char(1),--c=casado, s=soltero,v=viudo
seccion varchar(20)
);

3- Ingrese algunos registros:


insert into empleados
values ('22222222','Alberto Lopez','c','Sistemas');
insert into empleados
values ('23333333','Beatriz Garcia','c','Administracion');
insert into empleados
values ('24444444','Carlos Fuentes','s','Administracion');
insert into empleados
values ('25555555','Daniel Garcia','s','Sistemas');
insert into empleados
values ('26666666','Ester Juarez','c','Sistemas');
insert into empleados
values ('27777777','Fabian Torres','s','Sistemas');
insert into empleados
values ('28888888','Gabriela Lopez',null,'Sistemas');
insert into empleados
values ('29999999','Hector Garcia',null,'Administracion');

4- Muestre los 5 primeros registros (5 registros)

5- Muestre nombre y seccion de los 4 primeros registros ordenados por seccin (4


registros)

6- Realice la misma consulta anterior pero incluya todos los registros que tengan el
mismo valor en
"seccion" que el ltimo (8 registros)
7- Muestre nombre, estado civil y seccion de los primeros 4 empleados ordenados por
estado civil y
seccin (4 registros)

8- Realice la misma consulta anterior pero incluya todos los valores iguales al ltimo
registro
retornado (5 registros)

if object_id('empleados') is not null


drop table empleados;

create table empleados (


documento varchar(8) not null,
nombre varchar(30),
estadocivil char(1),--c=casado, s=soltero,v=viudo
seccion varchar(20)
);

insert into empleados


values ('22222222','Alberto Lopez','c','Sistemas');
insert into empleados
values ('23333333','Beatriz Garcia','c','Administracion');
insert into empleados
values ('24444444','Carlos Fuentes','s','Administracion');
insert into empleados
values ('25555555','Daniel Garcia','s','Sistemas');
insert into empleados
values ('26666666','Ester Juarez','c','Sistemas');
insert into empleados
values ('27777777','Fabian Torres','s','Sistemas');
insert into empleados
values ('28888888','Gabriela Lopez',null,'Sistemas');
insert into empleados
values ('29999999','Hector Garcia',null,'Administracion');

select top 5 *from empleados;

select top 4 nombre,seccion


from empleados
order by seccion;

select top 4 with ties nombre,seccion


from empleados
order by seccion;

select top 4 nombre,estadocivil,seccion


from empleados
order by estadocivil,seccion;

select top 4 with ties nombre,estadocivil,seccion


from empleados
order by estadocivil,seccion;

Las claves primarias pueden ser simples, formadas por un solo campo o compuestas, ms 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 da los datos de los vehculos que
ingresan en la tabla llamada "vehiculos" con los siguientes campos:

- patente char(6) not null,


- tipo char (1), 'a'= auto, 'm'=moto,
- horallegada datetime,
- horasalida datetime,

Necesitamos definir una clave primaria para una tabla con los datos descriptos arriba. No
podemos usar solamente la patente porque un mismo auto puede ingresar ms de una vez en el
da 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 ningn campo, por si slo cumple con la condicin para ser clave, es decir, debe identificar
un solo registro, el valor no puede repetirse, debemos usar 2 campos.

Definimos una clave compuesta cuando ningn campo por si solo cumple con la condicin para ser
clave.

En este ejemplo, un auto puede ingresar varias veces en un da a la playa, pero siempre ser a
distinta hora.

Usamos 2 campos como clave, la patente junto con la hora de llegada, as identificamos
unvocamente cada registro.

Para establecer ms de un campo como clave primaria usamos la siguiente sintaxis:

create table vehiculos(


patente char(6) not null,
tipo char(1),--'a'=auto, 'm'=moto
horallegada datetime,
horasalida datetime,
primary key(patente,horallegada)
);

Nombramos los campos que formarn parte de la clave separados por comas.

Al ingresar los registros, SQL Server controla que los valores para los campos establecidos como
clave primaria no estn repetidos en la tabla; si estuviesen repetidos, muestra un mensaje y la
insercin no se realiza. Lo mismo sucede si realizamos una actualizacin.
Entonces, si un solo campo no identifica unvocamente un registro podemos definir una clave
primaria compuesta, es decir formada por ms de un campo.

Primer problema:

Un consultorio mdico en el cual trabajan 3 mdicos registra las consultas de los


pacientes en una
tabla llamada "consultas".
1- Elimine la tabla si existe:
if object_id('consultas') is not null
drop table consultas;

2- La tabla contiene los siguientes datos:


- fechayhora: datetime not null, fecha y hora de la consulta,
- medico: varchar(30), not null, nombre del mdico (Perez,Lopez,Duarte),
- documento: char(8) not null, documento del paciente,
- paciente: varchar(30), nombre del paciente,
- obrasocial: varchar(30), nombre de la obra social (IPAM,PAMI, etc.).
);

3- Un mdico slo puede atender a un paciente en una fecha y hora determianada. En


una fecha y hora
determinada, varios mdicos atienden a distintos pacientes. Cree la tabla definiendo
una clave
primaria compuesta:
create table consultas(
fechayhora datetime not null,
medico varchar(30) not null,
documento char(8) not null,
paciente varchar(30),
obrasocial varchar(30),
primary key(fechayhora,medico)
);

4- Ingrese varias consultas para un mismo mdico en distintas horas el mismo da.

5- Ingrese varias consultas para diferentes mdicos en la misma fecha y hora.

6- Intente ingresar una consulta para un mismo mdico en la misma hora el mismo
da.

if object_id('consultas') is not null


drop table consultas;

create table consultas(


fechayhora datetime not null,
medico varchar(30) not null,
documento char(8) not null,
paciente varchar(30),
obrasocial varchar(30),
primary key(fechayhora,medico)
);

insert into consultas


values ('2006/11/05 8:00','Lopez','12222222','Acosta Betina','PAMI');
insert into consultas
values ('2006/11/05 8:30','Lopez','23333333','Fuentes Carlos','PAMI');

insert into consultas


values ('2006/11/05 8:00','Perez','34444444','Garcia Marisa','IPAM');
insert into consultas
values ('2006/11/05 8:00','Duarte','45555555','Pereyra Luis','PAMI');

insert into consultas


values ('2006/11/05 8:00','Perez','23333333','Fuentes Carlos','PAMI');

Es importante, al disear una base de datos y las tablas que contiene, tener en cuenta la
integridad de los datos, esto significa que la informacin almacenada en las tablas debe ser
vlida, coherente y exacta.

Hasta el momento, hemos controlado y restringido la entrada de valores a un campo mediante el


tipo de dato que le definimos (cadena, numricos, etc.), la aceptacin o no de valores nulos, el
valor por defecto. Tambin hemos asegurado que cada registro de una tabla sea nico definiendo
una clave primaria y empleando la propiedad identity.

SQL Server ofrece ms alternativas, adems de las aprendidas, para restringir y validar los datos,
las veremos ordenadamente y al finalizar haremos un resumen de las mismas.

Comenzamos por las restricciones.

Las restricciones (constraints) son un mtodo para mantener la integridad de los datos,
asegurando que los valores ingresados sean vlidos y que las relaciones entre las tablas se
mantenga. Se establecen a los campos y las tablas.

Pueden definirse al crear la tabla ("create table") o agregarse a una tabla existente (empleando
"alter table") y se pueden aplicar a un campo o a varios. Se aconseja crear las tablas y luego
agregar las restricciones.

Se pueden crear, modificar y eliminar las restricciones sin eliminar la tabla y volver a crearla.

El procedimiento almacenado del sistema "sp_helpconstraint" junto al nombre de la tabla, nos


muestra informacin acerca de las restricciones de dicha tabla.

Cuando se agrega una restriccin a una tabla, SQL Server comprueba los datos existentes.
Hay varios tipos de restricciones.

La restriccin "default" especifica un valor por defecto para un campo cuando no se inserta
explcitamente en un comando "insert".
Anteriormente, para establecer un valor por defecto para un campo emplebamos la clusula
"default" al crear la tabla, por ejemplo:

create table libros(


...
autor varchar(30) default 'Desconocido',
...
);

Cada vez que establecamos un valor por defecto para un campo de una tabla, SQL Server creaba
automticamente una restriccin "default" para ese campo de esa tabla.

Dicha restriccin, a la cual no le dbamos un nombre, reciba un nombre dado por SQL Server que
consiste "DF" (por default), seguido del nombre de la tabla, el nombre del campo y letras y
nmeros aleatorios.

Podemos agregar una restriccin "default" a una tabla existente con la sintaxis bsica siguiente:

alter table NOMBRETABLA


add constraint NOMBRECONSTRAINT
default VALORPORDEFECTO
for CAMPO;

En la sentencia siguiente agregamos una restriccin "default" al campo autor de la tabla existente
"libros", que almacena el valor "Desconocido" en dicho campo si no ingresamos un valor en un
"insert":

alter table libros


add constraint DF_libros_autor
default 'Desconocido'
for autor;

Por convencin, 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 restriccin "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 restriccin "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 informacin referente a las restriciones de una tabla con el procedimiento
almacenado "sp_helpcontraint":

sp_helpconstraint libros;

aparecen varias columnas con la siguiente informacin:

- constraint_type: el tipo de restriccin y sobre qu campo est


establecida
(DEFAULT on column autor),
- constraint_name: el nombre de la restriccin (DF_libros_autor),
- delete_action y update_action: no tienen valores para este tipo de
restriccin.
- status_enabled y status_for_replication: no tienen valores para este
tipo
de restriccin.
- constraint_keys: el valor por defecto (Desconocido).

Entonces, la restriccin "default" especifica un valor por defecto para un campo cuando no se
inserta explcitamente en un "insert", se puede establecer uno por campo y no se puede emplear
junto con la propiedad "identity".

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;

2- Cree la tabla con la siguiente estructura:


create table visitantes(
numero int identity,
nombre varchar(30),
edad tinyint,
domicilio varchar(30),
ciudad varchar(20),
montocompra decimal (6,2) not null
);

3- Defina una restriccin "default" para el campo "ciudad" que almacene el valor
"Cordoba" en caso
de no ingresar valor para dicho campo:
alter table visitantes
add constraint DF_visitantes_ciudad
default 'Cordoba'
for ciudad;

4- Defina una restriccin "default" para el campo "montocompra" que almacene el


valor "0" en caso de
no ingresar valor para dicho campo:
alter table visitantes
add constraint DF_visitantes_montocompra
default 0
for montocompra;

5- Ingrese algunos registros sin valor para los campos con restriccin "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);

6- Vea cmo se almacenaron los registros:


select *from visitantes;

7- Vea las restricciones creadas anteriormente.


aparecen dos filas, una por cada restriccin.

8- Intente agregar otra restriccin "default" al campo "ciudad".


Aparece un mensaje de error indicando que el campo ya tiene una restriccin "default"
y sabemos
que no puede establecerse ms de una restriccin "default" por campo.

9- Intente establecer una restriccin "default" al campo "identity".


No se permite.

if object_id('visitantes') is not null


drop table visitantes;

create table visitantes(


numero int identity,
nombre varchar(30),
edad tinyint,
domicilio varchar(30),
ciudad varchar(20),
montocompra decimal (6,2) not null
);

alter table visitantes


add constraint DF_visitantes_ciudad
default 'Cordoba'
for ciudad;

alter table visitantes


add constraint DF_visitantes_montocompra
default 0
for montocompra;

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);

select *from visitantes;

sp_helpconstraint visitantes;

alter table visitantes


add constraint DF_visitantes_ciudad
default 'Cordoba'
for ciudad;

alter table visitantes


add constraint DF_visitantes_numero
default 0
for numero;

La restriccin "check" especifica los valores que acepta un campo, evitando que se ingresen
valores inapropiados.

La sintaxis bsica es la siguiente:

alter table NOMBRETABLA


add constraint NOMBRECONSTRAINT
check CONDICION;

Trabajamos con la tabla "libros" de una librera 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).

Los campos correspondientes a los precios (minorista y mayorista) se definen de tipo


decimal(5,2), es decir, aceptan valores entre -999.99 y 999.99. Podemos controlar que no se
ingresen valores negativos para dichos campos agregando una restriccin "check":

alter table libros


add constraint CK_libros_precio_positivo
check (preciomin>=0 and preciomay>=0);

Este tipo de restriccin verifica los datos cada vez que se ejecuta una sentencia "insert" o
"update", es decir, acta en inserciones y actualizaciones.

Si la tabla contiene registros que no cumplen con la restriccin que se va a establecer, la


restriccin no se puede establecer, hasta que todos los registros cumplan con dicha restriccin.

La condicin puede hacer referencia a otros campos de la misma tabla. Por ejemplo, podemos
controlar que el precio mayorista no sea mayor al precio minorista:

alter table libros


add constraint CK_libros_preciominmay
check (preciomay<=preciomin);

Por convencin, cuando demos el nombre a las restricciones "check" seguiremos la misma
estructura: comenzamos con "CK", seguido del nombre de la tabla, del campo y alguna palabra
con la cual podamos identificar fcilmente de qu se trata la restriccin, por si tenemos varias
restricciones "check" para el mismo campo.

Un campo puede tener varias restricciones restricciones "check" y una restriccin "check" puede
incluir varios campos.
Las condiciones para restricciones "check" tambin pueden pueden incluir un patrn o una lista de
valores. Por ejemplo establecer que cierto campo conste de 4 caracteres, 2 letras y 2 dgitos:

...
check (CAMPO like '[A-Z][A-Z][0-9][0-9]');

O establecer que cierto campo asuma slo los valores que se listan:

...
check (CAMPO in ('lunes','miercoles','viernes'));

No se puede aplicar esta restriccin junto con la propiedad "identity".

Si un campo permite valores nulos, "null" es un valor aceptado aunque no est incluido en la
condicin de restriccin.

Si intentamos establecer una restriccin "check" para un campo que entra en conflicto con otra
restriccin "check" establecida al mismo campo, SQL Server no lo permite.

Pero si establecemos una restriccin "check" para un campo que entra en conflicto con una
restriccin "default" establecida para el mismo campo, SQL Server lo permite; pero al intentar
ingresar un registro, aparece un mensaje de error.

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;

2- Crela con la siguiente estructura:


create table empleados (
documento varchar(8),
nombre varchar(30),
fechanacimiento datetime,
cantidadhijos tinyint,
seccion varchar(20),
sueldo decimal(6,2)
);

3- Agregue una restriccin "check" para asegurarse que no se ingresen valores


negativos para el
sueldo:
alter table empleados
add constraint CK_empelados_sueldo_positivo
check (sueldo>0);

4- Ingrese algunos registros vlidos:


insert into empleados values ('22222222','Alberto
Lopez','1965/10/05',1,'Sistemas',1000);
insert into empleados values ('33333333','Beatriz
Garcia','1972/08/15',2,'Administracion',3000);
insert into empleados values ('34444444','Carlos
Caseres','1980/10/05',0,'Contadura',6000);
5- Intente agregar otra restriccin "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 restriccin.

6- Elimine el registro infractor y vuelva a crear la restriccin:


delete from empleados where sueldo=6000;

alter table empleados


add constraint CK_empleados_sueldo_maximo
check (sueldo<=5000);

7- Establezca una restriccin para controlar que la fecha de nacimiento que se ingresa
no supere la
fecha actual:
alter table empleados
add constraint CK_fechanacimiento_actual
check (fechanacimiento

if object_id('empleados') is not null

drop table empleados;

create table empleados (

documento varchar(8),

nombre varchar(30),

fechanacimiento datetime,

cantidadhijos tinyint,

seccion varchar(20),

sueldo decimal(6,2)

);

alter table empleados

add constraint CK_empleados_sueldovalores


check (sueldo>=0);

insert into empleados values ('22222222','Alberto Lopez','1965/10/05',1,'Sistemas',1000);

insert into empleados values ('33333333','Beatriz Garcia','1972/08/15',2,'Administracion',3000);

insert into empleados values ('34444444','Carlos Caseres','1980/10/05',0,'Contadura',6000);

delete from empleados where sueldo=6000;

alter table empleados

add constraint CK_empleados_sueldonomayor

check (sueldo <= 5000);

alter table empleados

add constraint CK_empleados_fechanacimientonoactual

check (fechanacimiento <> getdate());

Sabemos que si agregamos una restriccin a una tabla que contiene datos, SQL Server los controla
para asegurarse que cumplen con la condicin de la restriccin, si algn registro no la cumple, la
restriccin no se establecece.

Es posible deshabilitar esta comprobacin en caso de restricciones "check".

Podemos hacerlo cuando agregamos la restriccin "check" a una tabla para que SQL Server acepte
los valores ya almacenados que infringen la restriccin. Para ello debemos incluir la opcin "with
nocheck" en la instruccin "alter table":

alter table libros


with nocheck
add constraint CK_libros_precio
check (precio>=0);

La restriccin no se aplica en los datos existentes, pero si intentamos ingresar un nuevo valor que
no cumpla la restriccin, SQL Server no lo permite.

Entonces, para evitar la comprobacin de datos existentes al crear la restriccin, la sintaxis


bsica es la siguiente:

alter table TABLA


with nocheck
add constraint NOMBRERESTRICCION
check (CONDICION);

Por defecto, si no especificamos, la opcin es "with check".

Tambin podemos deshabilitar las restricciones para agregar o actualizar datos sin comprobarla:

alter table libros


nocheck constraint CK_libros_precio;

En el ejemplo anterior deshabilitamos la restriccin "CK_libros_precio" para poder ingresar un


valor negativo para "precio".

Para habilitar una restriccin deshabilitada se ejecuta la misma instruccin pero con la clusula
"check" o "check all":

alter table libros


check constraint CK_libros_precio;

Si se emplea "check constraint all" no se coloca nombre de restricciones, habilita todas las
restricciones que tiene la tabla nombrada.

Para habilitar o deshabilitar restricciones la comprobacin de datos en inserciones o


actualizaciones, la sintaxis bsica es:

alter table NOMBRETABLA


OPCIONdeRESTRICCION constraint NOMBRERESTRICCION;

Para saber si una restriccin est habilitada o no, podemos ejecutar el procedimiento
almacenado "sp_helpconstraint" y fijarnos lo que informa la columna "status_enabled".

Entonces, las clusulas "check" y "nocheck" permiten habilitar o deshabilitar restricciones "check"
(tambin las restricciones "foreign key" que veremos ms adelante), a las dems se las debe
eliminar ("default" y las que veremos posteriormente).

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;
2- Crela con la siguiente estructura e ingrese los registros siguientes:
create table empleados (
documento varchar(8),
nombre varchar(30),
seccion varchar(20),
sueldo decimal(6,2)
);

insert into empleados


values ('22222222','Alberto Acosta','Sistemas',-10);
insert into empleados
values ('33333333','Beatriz Benitez','Recursos',3000);
insert into empleados
values ('34444444','Carlos Caseres','Contaduria',4000);

3- Intente agregar una restriccin "check" para asegurarse que no se ingresen valores
negativos para
el sueldo:
alter table empleados
add constraint CK_empleados_sueldo_positivo
check (sueldo>=0);
No se permite porque hay un valor negativo almacenado.

5- Vuelva a intentarlo agregando la opcin "with nocheck":


alter table empleados
with nocheck
add constraint CK_empleados_sueldo_positivo
check (sueldo>=0);

6- Intente ingresar un valor negativo para sueldo:


insert into empleados
values ('35555555','Daniel Duarte','Administracion',-2000);
No es posible a causa de la restriccin.

7- Deshabilite la restriccin e ingrese el registro anterior:


alter table empleados
nocheck constraint CK_empleados_sueldo_positivo;
insert into empleados
values ('35555555','Daniel Duarte','Administracion',2000);

8- Establezca una restriccin "check" para "seccion" que permita solamente los valores
"Sistemas",
"Administracion" y "Contadura":
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.

9- Establezca la restriccin anterior evitando que se controlen los datos existentes.

10- Vea si las restricciones de la tabla estn o no habilitadas:


sp_helpconstraint empleados;
Muestra 2 filas, una por cada restriccin.

11- Habilite la restriccin deshabilitada.

12- Intente modificar la seccin del empleado "Carlos Caseres" a "Recursos".


No lo permite.

13- Deshabilite la restriccin para poder realizar la actualizacin del punto precedente.

if object_id('empleados') is not null


drop table empleados;

create table empleados (


documento varchar(8),
nombre varchar(30),
seccion varchar(20),
sueldo decimal(6,2)
);

insert into empleados


values ('22222222','Alberto Acosta','Sistemas',-10);
insert into empleados
values ('33333333','Beatriz Benitez','Recursos',3000);
insert into empleados
values ('34444444','Carlos Caseres','Contaduria',4000);

alter table empleados


add constraint CK_empleados_sueldo_positivo
check (sueldo>=0);

alter table empleados


with nocheck
add constraint CK_empleados_sueldo_positivo
check (sueldo>=0);

insert into empleados


values ('35555555','Daniel Duarte','Administracion',-2000);

alter table empleados


nocheck constraint CK_empleados_sueldo_positivo;
insert into empleados
values ('35555555','Daniel Duarte','Administracion',2000);

alter table empleados


add constraint CK_empleados_seccion_lista
check (seccion in ('Sistemas','Administracion','Contaduria'));

alter table empleados


with nocheck
add constraint CK_empleados_seccion_lista
check (seccion in ('Sistemas','Administracion','Contaduria'));
sp_helpconstraint empleados;

alter table empleados


check constraint CK_empleados_sueldo_positivo;

update empleados set seccion='Recursos' where nombre='Carlos Caseres';

alter table empleados


nocheck constraint CK_empleados_seccion_lista;
update empleados set seccion='Recursos' where nombre='Carlos Caseres';

Hemos visto las restricciones que se aplican a los campos, "default" y "check".

Ahora veremos las restricciones que se aplican a las tablas, que aseguran valores nicos para cada
registro.

Hay 2 tipos: 1) primary key y 2) unique.

Anteriormente, para establecer una clave primaria para una tabla emplebamos la siguiente
sintaxis al crear la tabla, por ejemplo:

create table libros(


codigo int not null,
titulo varchar(30),
autor varchar(30),
editorial varchar(20),
primary key(codigo)
);

Cada vez que establecamos la clave primaria para la tabla, SQL Server creaba automticamente
una restriccin "primary key" para dicha tabla. Dicha restriccin, a la cual no le dbamos un
nombre, reciba 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 nmeros aleatorios.

Podemos agregar una restriccin "primary key" a una tabla existente con la sintaxis bsica
siguiente:

alter table NOMBRETABLA


add constraint NOMBRECONSTRAINT
primary key (CAMPO,...);

En el siguiente ejemplo definimos una restriccin "primary key" para nuestra tabla "libros" para
asegurarnos que cada libro tendr un cdigo diferente y nico:

alter table libros


add constraint PK_libros_codigo
primary key(codigo);

Con esta restriccin, 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 convencin, cuando demos el nombre a las restricciones "primary key" seguiremos el formato
"PK_NOMBRETABLA_NOMBRECAMPO".

Sabemos que cuando agregamos una restriccin a una tabla que contiene informacin, SQL Server
controla los datos existentes para confirmar que cumplen las exigencias de la restriccin, si no
los cumple, la restriccin no se aplica y aparece un mensaje de error. Por ejemplo, si intentamos
definir la restriccin "primary key" para "libros" y hay registros con cdigos repetidos o con un
valor "null", la restriccin no se establece.

Cuando establecamos una clave primaria al definir la tabla, automticamente SQL Server
redefina el campo como "not null"; pero al agregar una restriccin "primary key", los campos que
son clave primaria DEBEN haber sido definidos "not null" (o ser implcitamente "not null" si se
definen identity).

SQL Server permite definir solamente una restriccin "primary key" por tabla, que asegura la
unicidad de cada registro de una tabla.

Si ejecutamos el procedimiento almacenado "sp_helpconstraint" junto al nombre de la tabla,


podemos ver las restricciones "primary key" (y todos los tipos de restricciones) de dicha tabla.

Un campo con una restriccin "primary key" puede tener una restriccin "check".

Un campo "primary key" tambin acepta una restriccin "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.

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;

2- Crela con la siguiente estructura:


create table empleados (
documento varchar(8) not null,
nombre varchar(30),
seccion varchar(20)
);

3- Ingrese algunos registros, dos de ellos con el mismo nmero de documento:


insert into empleados
values ('22222222','Alberto Lopez','Sistemas');
insert into empleados
values ('23333333','Beatriz Garcia','Administracion');
insert into empleados
values ('23333333','Carlos Fuentes','Administracion');

4- Intente establecer una restriccin "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 restriccin,
debemos eliminar (o
modificar) el registro que tiene documento duplicado:
delete from empleados
where nombre='Carlos Fuentes';

5- Establezca la restriccin "primary key" del punto 4.

6- Intente actualizar un documento para que se repita.


No lo permite porque va contra la restriccin.

7-Intente establecer otra restriccin "primary key" con el campo "nombre".


No lo permite, slo puede haber una restriccin "primary key" por tabla.

8- Intente ingresar un registro con valor nulo para el documento.


No lo permite porque la restriccin no admite valores nulos.

9- Establezca una restriccin "default" para que almacene "00000000" en el


documento en caso de
omitirlo en un "insert".

10- Ingrese un registro sin valor para el documento.

11- Vea el registro:


select *from empleados;

12- Intente ingresar otro empleado sin documento explcito.


No lo permite porque se duplicara la clave.

13- Vea las restricciones de la tabla empleados (2 filas):


sp_helpconstraint empleados;

if object_id('empleados') is not null


drop table empleados;

create table empleados (


documento varchar(8) not null,
nombre varchar(30),
seccion varchar(20)
);

insert into empleados


values ('22222222','Alberto Lopez','Sistemas');
insert into empleados
values ('23333333','Beatriz Garcia','Administracion');
insert into empleados
values ('23333333','Carlos Fuentes','Administracion');

alter table empleados


add constraint PK_empleados_documento
primary key(documento);
delete from empleados
where nombre='Carlos Fuentes';

alter table empleados


add constraint PK_empleados_documento
primary key(documento);

update empleados set documento='22222222'


where documento='23333333';

alter table empleados


add constraint PK_empleados_nombre
primary key(nombre);

insert into empleados values(null,'Marcelo Juarez','Sistemas');

alter table empleados


add constraint DF_empleados_documento
default '00000000'
for documento;

insert into empleados (nombre,seccion) values('Luis Luque','Sistemas');

select *from empleados;

insert into empleados (nombre,seccion) values('Ana Fuentes','Sistemas');

sp_helpconstraint empleados;

Hemos visto que las restricciones aplicadas a tablas aseguran valores nicos para cada registro.
Anteriormente aprendimos la restriccin "primary key", otra restriccin para las tablas es
"unique".

La restriccin "unique" impide la duplicacin de claves alternas (no primarias), es decir,


especifica que dos registros no puedan tener el mismo valor en un campo. Se permiten valores
nulos. Se pueden aplicar varias restricciones de este tipo a una misma tabla, y pueden aplicarse a
uno o varios campos que no sean clave primaria.

Se emplea cuando ya se estableci una clave primaria (como un nmero de legajo) pero se
necesita asegurar que otros datos tambin sean nicos y no se repitan (como nmero de
documento).

La sintaxis general es la siguiente:

alter table NOMBRETABLA


add constraint NOMBRERESTRICCION
unique (CAMPO);

Ejemplo:
alter table alumnos
add constraint UQ_alumnos_documento
unique (documento);

En el ejemplo anterior se agrega una restriccin "unique" sobre el campo "documento" de la tabla
"alumnos", esto asegura que no se pueda ingresar un documento si ya existe. Esta restriccin
permite valores nulos, asi que si se ingresa el valor "null" para el campo "documento", se acepta.

Por convencin, 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 restriccin a una tabla que contiene informacin, SQL
Server controla los datos existentes para confirmar que cumplen la condicin de la restriccin, si
no los cumple, la restriccin no se aplica y aparece un mensaje de error. En el caso del ejemplo
anterior, si la tabla contiene nmeros de documento duplicados, la restriccin no podr
establecerse; si podr establecerse si tiene valores nulos.

SQL Server controla la entrada de datos en inserciones y actualizaciones evitando que se ingresen
valores duplicados.

Primer problema:

Una empresa de remises tiene registrada la informacin de sus vehculos en una tabla
llamada
"remis".
1- Elimine la tabla si existe:
if object_id('remis') is not null
drop table remis;

2- Cree la tabla con la siguiente estructura:


create table remis(
numero tinyint identity,
patente char(6),
marca varchar(15),
modelo char(4)
);

3- Ingrese algunos registros, 2 de ellos con patente repetida y alguno con patente
nula:
insert into remis values('ABC123','Renault clio','1990');
insert into remis values('DEF456','Peugeot 504','1995');
insert into remis values('DEF456','Fiat Duna','1998');
insert into remis values('GHI789','Fiat Duna','1995');
insert into remis values(null,'Fiat Duna','1995');

4- Intente agregar una restriccin "unique" para asegurarse que la patente del remis
no tomar
valores repetidos.
No se puede porque hay valores duplicados.

5- Elimine el registro con patente duplicada y establezca la restriccin.


Note que hay 1 registro con valor nulo en "patente".

6- Intente ingresar un registro con patente repetida (no lo permite)

7- Intente ingresar un registro con valor nulo para el campo "patente".


No lo permite porque la clave estara duplicada.

8- Muestre la informacin de las restricciones:


sp_helpconstraint remis;

if object_id('remis') is not null


drop table remis;

create table remis(


numero tinyint identity,
patente char(6),
marca varchar(15),
modelo char(4)
);

insert into remis values('ABC123','Renault clio','1990');


insert into remis values('DEF456','Peugeot 504','1995');
insert into remis values('DEF456','Fiat Duna','1998');
insert into remis values('GHI789','Fiat Duna','1995');
insert into remis values(null,'Fiat Duna','1995');

alter table remis


add constraint UQ_remis_patente
unique(patente);

delete from remis where numero=3;


alter table remis
add constraint UQ_remis_patente
unique(patente);

insert into remis values('ABC123','Renault 11','1995');

insert into remis values(null,'Renault 11','1995');

sp_helpconstraint remis;

El procedimiento almacenado "sp_helpconstraint" seguido del nombre de una tabla muestra la


informacin referente a todas las restricciones establecidas en dicha tabla, devuelve las
siguientes columnas:

- constraint_type: tipo de restriccin. Si es una restriccin de campo (default o check) indica


sobre qu campo fue establecida. Si es de tabla (primary key o unique) indica el tipo de ndice
creado (tema que veremos posteriormente).

- constraint_name: nombre de la restriccin.


- delete_action: solamente es aplicable para restricciones de tipo "foreign key" (la veremos
posteriormente).

- update_action: slo es aplicable para restricciones de tipo "foreign key" (la veremos
posteriormente).

- status_enabled: solamente es aplicable para restricciones de tipo "check" y "foreign key". Indica
si est habilitada (Enabled) o no (Disabled). Indica "n/a" en cualquier restriccin para la que no se
aplique.

- status_for_replication: solamente es aplicable para restricciones de tipo "check" y "foreign key".


Indica "n/a" en cualquier restriccin para la que no se aplique.

- constraint_keys: Si es una restriccin "check" muestra la condicin de chequeo; si es una


restriccin "default", el valor por defecto; si es una "primary key" o "unique" muestra el/ los
campos a los que se aplicaron la restriccin.

Para eliminar una restriccin, la sintaxis bsica es la siguiente:

alter table NOMBRETABLA


drop NOMBRERESTRICCION;

Para eliminar la restriccin "DF_libros_autor" de la tabla libros tipeamos:

alter table libros


drop DF_libros_autor;

Pueden eliminarse varias restricciones con una sola instruccin separndolas por comas.

Cuando eliminamos una tabla, todas las restricciones que fueron establecidas en ella, se eliminan
tambin.

Primer problema:

Una playa de estacionamiento almacena cada da los datos de los vehculos 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 not null,
horasalida datetime
);

3- Establezca una restriccin "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'));

4- Establezca una restriccin "default" para el campo "tipo" que almacene el valor "a"
en caso de no
ingresarse valor para dicho campo:
alter table vehiculos
add constraint DF_vehiculos_tipo
default 'a'
for tipo;

5- Establezca una restriccin "check" para el campo "patente" para que acepte 3 letras
seguidas de 3
dgitos:
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 restriccin "primary key" que incluya los campos "patente" y
"horallegada":
alter table vehiculos
add constraint PK_vehiculos_patentellegada
primary key(patente,horallegada);

7- Ingrese un vehculo:
insert into vehiculos values('SDR456','a','2005/10/10 10:10',null);

8- Intente ingresar un registro repitiendo la clave primaria:


insert into vehiculos values('SDR456','m','2005/10/10 10:10',null);
No se permite.

9- Ingrese un registro repitiendo la patente pero no la hora de llegada:


insert into vehiculos values('SDR456','m','2005/10/10 12:10',null);

10- Ingrese un registro repitiendo la hora de llegada pero no la patente:


insert into vehiculos values('SDR111','m','2005/10/10 10:10',null);

11- Vea todas las restricciones para la tabla "vehiculos":


sp_helpconstraint vehiculos;
aparecen 4 filas, 2 correspondientes a restricciones "check", 1 a "default" y 1 a
"primary key".

12- Elimine la restriccin "default" del campo "tipo".

13- Vea si se ha eliminado:


sp_helpconstraint vehiculos;
14- Elimine la restriccin "primary key" y "check".

15- Vea si se han eliminado:


sp_helpconstraint vehiculos;

if object_id('vehiculos') is not null


drop table vehiculos;

create table vehiculos(


patente char(6) not null,
tipo char(1),--'a'=auto, 'm'=moto
horallegada datetime not null,
horasalida datetime
);

alter table vehiculos


add constraint CK_vehiculos_tipo
check (tipo in ('a','m'));

alter table vehiculos


add constraint DF_vehiculos_tipo
default 'a'
for tipo;

alter table vehiculos


add constraint CK_vehiculos_patente_patron
check (patente like '[A-Z][A-Z][A-Z][0-9][0-9][0-9]');

alter table vehiculos


add constraint PK_vehiculos_patentellegada
primary key(patente,horallegada);

insert into vehiculos values('SDR456','a','2005/10/10 10:10',null);

insert into vehiculos values('SDR456','m','2005/10/10 10:10',null);

insert into vehiculos values('SDR456','m','2005/10/10 12:10',null);

insert into vehiculos values('SDR111','m','2005/10/10 10:10',null);

sp_helpconstraint vehiculos;

alter table vehiculos


drop DF_vehiculos_tipo;

sp_helpconstraint vehiculos;

alter table vehiculos


drop PK_vehiculos_patentellegada, CK_vehiculos_tipo;
sp_helpconstraint vehiculos;

Vimos que SQL Server ofrece varias alternativas para asegurar la integridad de datos, mediante el
uso de:

1. RESTRICCIONES (constraints), que se establecen en tablas y campos y son controlados


automticamente por SQL Server. Hay 3 tipos:

I) DE LOS CAMPOS (hace referencia a los valores vlidos para un campo determinado).
Pueden ser:

a) DEFAULT: especifica un valor por defecto para un campo cuando no se inserta


explcitamente en un comando "insert".

b) CHECK: especifica un rango de valores que acepta un campo, se emplea en inserciones


y actualizaciones ("insert" y "update").

II) DE LA TABLA (asegura un identificador nico para cada registro de una tabla). Hay 2
tipos:

a) PRIMARY KEY: identifica unvocamente cada uno de los registros; asegura que no haya
valores duplicados ni valores nulos. Se crea un ndice automticamente.

b) UNIQUE: impide la duplicacin de claves alternas (no primarias). Se permiten valores


nulos. Se crea un ndice automticamente.

III) REFERENCIAL: lo veremos ms adelante.

2. REGLAS (rules) y
3. VALORES PREDETERMINADOS (defaults).

Veamos las reglas.

Las reglas especifican los valores que se pueden ingresar en un campo, asegurando que los datos
se encuentren en un intervalo de valores especfico, coincidan con una lista de valores o sigan un
patrn.

Una regla se asocia a un campo de una tabla (o a un tipo de dato definido por el usuario, tema
que veremos posteriormente).

Un campo puede tener solamente UNA regla asociado a l.

Sintaxis bsica es la siguiente:


create rule NOMBREREGLA
as @VARIABLE CONDICION

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 condicin.

Por convencin, nombraremos las reglas comenzando con "RG", el nombre del campo al que se
asocia y alguna palabra que haga referencia a la condicin.

La variable puede tener cualquier nombre, pero debe estar precedido por el signo arroba (@),
dicha variable ser reemplazada por el valor del campo cuando se asocie.

La condicin se refiere a los valores permitidos para inserciones y actualizaciones y puede


contener cualquier expresin vlida para una clusula "where"; no puede hacer referencia a los
campos de una tabla.

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:

create rule RG_sueldo_intervalo


as @sueldo between 100 and 1000

Luego de crear la regla, debemos asociarla a un campo ejecutando un procedimiento almacenado


del sistema empleando la siguiente sintaxis bsica:

exec sp_bindrule NOMBREREGLA, 'TABLA.CAMPO';

Asociamos la regla creada anteriormente al campo "sueldo" de la tabla "empleados":

exec sp_bindrule RG_sueldo_intervalo, 'empleados.sueldo';

Si intentamos agregar (o actualizar) un registro con valor para el campo "sueldo" que no est en
el intervalo de valores especificado en la regla, aparece un mensaje de error indicando que hay
conflicto con la regla y la insercin (o actualizacin) 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
instruccin "insert" o "update" muestra un mensaje de error, es decir, acta 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 instruccin "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 asociacin anterior; pero la primera regla no desaparece, solamente se deshace la asociacin.

La sentencia "create rule" no puede combinarse con otras sentencias en un lote.


La funcin que cumple una regla es bsicamente la misma que una restriccin "check", las
siguientes caractersticas explican algunas diferencias entre ellas:

- podemos definir varias restricciones "check" sobre un campo, un campo solamente puede tener
una regla asociada a l;

- una restriccin "check" se almacena con la tabla, cuando sta se elimina, las restricciones
tambin 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 restriccin "check" puede incluir varios campos; una regla puede asociarse a distintos
campos (incluso de distintas tablas);

- una restriccin "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".

Primer problema:

Una playa de estacionamiento almacena cada da los datos de los vehculos que
ingresan en la tabla
llamada "vehiculos".
1- Elimine la tabla, si existe:
if object_id('vehiculos') is not null
drop table vehiculos;

2- Elimine las siguientes reglas:


if object_id ('RG_patente_patron') is not null
drop rule RG_patente_patron;
if object_id ('RG_horallegada') is not null
drop rule RG_horallegada;
if object_id ('RG_vehiculos_tipo') is not null
drop rule RG_vehiculos_tipo;
if object_id ('RG_vehiculos_tipo2') is not null
drop rule RG_vehiculos_tipo2;
if object_id ('RG_menor_fechaactual') is not null
drop rule RG_menor_fechaactual;

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- Ingrese algunos registros:


insert into vehiculos values ('AAA111','a','1990-02-01 08:10',null);
insert into vehiculos values ('BCD222','m','1990-02-01 08:10','1990-02-01 10:10');
insert into vehiculos values ('BCD222','m','1990-02-01 12:00',null);
insert into vehiculos values ('CC1234','a','1990-02-01 12:00',null);

5- Cree una regla para restringir los valores que se pueden ingresar en un campo
"patente" (3 letras
seguidas de 3 dgitos):
create rule RG_patente_patron
as @patente like '[A-Z][A-Z][A-Z][0-9][0-9][0-9]'

6- Ejecute el procedimiento almacenado del sistema "sp_help" para ver que la regla
creada
anteriormente existe:
sp_help;

7- Ejecute el procedimiento almacenado del sistema "sp_helpconstraint" para ver que


la regla creada
anteriormente no est asociada an a ningn campo de la tabla "vehiculos".

8- Asocie la regla al campo "patente":


Note que hay una patente que no cumple la regla, SQL Server NO controla los datos
existentes, pero
si controla las inserciones y actualizaciones:
select *from empleados;

9- Intente ingresar un registro con valor para el campo "patente" que no cumpla con la
regla.
aparece un mensaje de error indicando que hay conflicto con la regla y la insercin no
se realiza.

10- Cree otra regla que controle los valores para el campo "tipo" para que solamente
puedan
ingresarse los caracteres "a" y "m".

11- Asocie la regla al campo "tipo".

12- Intente actualizar un registro cambiando el valor de "tipo" a un valor que no


cumpla con la
regla anterior.
No lo permite.

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".

14- Si la asociamos a un campo que ya tiene asociada otra regla, la nueva regla
reeemplaza la
asociacin anterior. Asocie la regla creada en el punto anterior al campo "tipo".

15- Actualice el registro que no pudo actualizar en el punto 12:


update vehiculos set tipo='c' where patente='AAA111';

16- Cree una regla que permita fechas menores o iguales a la actual.

17- Asocie la regla anterior a los campos "horallegada" y "horasalida":


exec sp_bindrule RG_menor_fechaactual, 'vehiculos.horallegada';
exec sp_bindrule RG_menor_fechaactual, 'vehiculos.horasalida';

18- Ingrese un registro en el cual la hora de entrada sea posterior a la hora de salida:
insert into vehiculos values ('NOP555','a','1990-02-01 10:10','1990-02-01 08:30');

19- Intente establecer una restriccin "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 restriccin.

20- Elimine dicho registro:


delete from vehiculos where patente='NOP555';

21- Establezca la restriccin "check" que no pudo establecer en el punto 19:


alter table vehiculos
add constraint CK_vehiculos_llegada_salida
check(horallegada<=horasalida);

22- Cree una restriccin "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 restriccin 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".

24- Vea las reglas asociadas a "empleados" y las restricciones aplicadas a la misma
tabla ejecutando
"sp_helpconstraint".
Muestra 1 restriccin "check", 1 restriccin "default" y 4 reglas asociadas.
if object_id('vehiculos') is not null
drop table vehiculos;

if object_id ('RG_patente_patron') is not null


drop rule RG_patente_patron;
if object_id ('RG_horallegada') is not null
drop rule RG_horallegada;
if object_id ('RG_vehiculos_tipo') is not null
drop rule RG_vehiculos_tipo;
if object_id ('RG_vehiculos_tipo2') is not null
drop rule RG_vehiculos_tipo2;
if object_id ('RG_menor_fechaactual') is not null
drop rule RG_menor_fechaactual;

create table vehiculos(


patente char(6) not null,
tipo char(1),--'a'=auto, 'm'=moto
horallegada datetime not null,
horasalida datetime
);

insert into vehiculos values ('AAA111','a','1990-02-01 08:10',null);


insert into vehiculos values ('BCD222','m','1990-02-01 08:10','1990-02-01 10:10');
insert into vehiculos values ('BCD222','m','1990-02-01 12:00',null);
insert into vehiculos values ('CC1234','a','1990-02-01 12:00',null);

create rule RG_patente_patron


as @patente like '[A-Z][A-Z][A-Z][0-9][0-9][0-9]';

sp_help;

sp_helpconstraint vehiculos;

sp_bindrule RG_patente_patron,'vehiculos.patente';

select *from empleados;

insert into vehiculos values ('FGHIJK','a','1990-02-01 18:00',null);

create rule RG_vehiculos_tipo


as @tipo in ('a','m');

sp_bindrule RG_vehiculos_tipo, 'vehiculos.tipo';

update vehiculos set tipo='c' where patente='AAA111';

create rule RG_vehiculos_tipo2


as @tipo in ('a','c','m');

sp_bindrule RG_vehiculos_tipo2, 'vehiculos.tipo';

update vehiculos set tipo='c' where patente='AAA111';


create rule RG_menor_fechaactual
as @fecha <= getdate();

exec sp_bindrule RG_menor_fechaactual, 'vehiculos.horallegada';


exec sp_bindrule RG_menor_fechaactual, 'vehiculos.horasalida';

insert into vehiculos values ('NOP555','a','1990-02-01 10:10','1990-02-01 08:30');

alter table vehiculos


add constraint CK_vehiculos_llegada_salida
check(horallegada<=horasalida);

delete from vehiculos where patente='NOP555';

alter table vehiculos


add constraint CK_vehiculos_llegada_salida
check(horallegada<=horasalida);

alter table vehiculos


add constraint DF_vehiculos_tipo
default 'b'
for tipo;

insert into vehiculos values ('STU456',default,'1990-02-01 10:10','1990-02-01


15:30');

sp_helpconstraint vehiculos;

Para eliminar una regla, primero se debe deshacer la asociacin, ejecutando el procedimiento
almacenado del sistema "sp_unbindrule":

exec sp_unbindrule 'TABLA.CAMPO';

No es posible eliminar una regla si est asociada a un campo. Si intentamos hacerlo, aparece un
mensaje de error y la eliminacin no se realiza.

Con la instruccin "drop rule" eliminamos la regla:

drop rule NOMBREREGLA;

Quitamos la asociacin de la regla "RG_sueldo_intervalo" con el campo "sueldo" de la tabla


"empleados" tipeando:

exec sp_unbindrule 'empleados.sueldo';

Luego de quitar la asociacin la eliminamos:

drop rule RG_sueldo_100a1000;


Si eliminamos una tabla, las asociaciones de reglas de sus campos desaparecen, pero las reglas
siguen existiendo.

Primer problema:

Una playa de estacionamiento almacena cada da los datos de los vehculos que
ingresan en la tabla
llamada "vehiculos".
1- Elimine la tabla, si existe:
if object_id('vehiculos') is not null
drop table vehiculos;

2- Elimine las siguientes reglas, si existen:


if object_id ('RG_patente_patron') is not null
drop rule RG_patente_patron;
if object_id ('RG_vehiculos_tipo') is not null
drop rule RG_vehiculos_tipo;
if object_id ('RG_vehiculos_tipo2') is not null
drop rule RG_vehiculos_tipo2;

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 dgitos):
create rule RG_patente_patron
as @patente like '[A-Z][A-Z][A-Z][0-9][0-9][0-9]';

5-Asocie la regla al campo "patente":


sp_bindrule RG_patente_patron,'vehiculos.patente';

6- Intente ingresar un registro con valor para el campo "patente" que no cumpla con la
regla:
insert into vehiculos values ('FGHIJK','a','1990-02-01 18:00',null);
aparece un mensaje de error indicando que hay conflicto con la regla y la insercin no
se realiza.

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')

8- Asocie la regla al campo "tipo":


sp_bindrule RG_vehiculos_tipo, 'vehiculos.tipo';

9- Intente ingresar un registro con el valor 'c' para "tipo":


insert into vehiculos values('AAA111','c','2001-10-10 10:10',NULL);
No lo permite.

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');

11- Si la asociamos a un campo que ya tiene asociada otra regla, la nueva regla
reeemplaza la
asociacin anterior. Asocie la regla creada en el punto anterior al campo "tipo".

12- Ingrese el registro que no pudo ingresar en el punto 9.

13- Intente eliminar la regla "RG_vehiculos_tipo2".


No es posible porque est asociada a un campo de "vehiculos".

14- Elimine la regla "RG_vehiculos_tipo".


Es posible porque no est asociada a ningn campo.

15- Intente eliminar la regla "RG_patente_patron".


No es posible porque est asociada.

16- Quite la asociacin de la regla con el campo "patente" de "vehiculos".

17- Vea si la regla "RG_patente_patron" est asociada a algn campo de "vehiculos".


No lo est.

18- Verifique que la regla an existe en la base de datos activa:


sp_help;
aparece la regla.

19- Elimine la regla que no pudo eliminar en el punto 15.

20- Verifique que la regla ya no existe en la base de datos activa.


No aparece la regla "RG_patente_patron".

if object_id('vehiculos') is not null


drop table vehiculos;

if object_id ('RG_patente_patron') is not null


drop rule RG_patente_patron;
if object_id ('RG_vehiculos_tipo') is not null
drop rule RG_vehiculos_tipo;
if object_id ('RG_vehiculos_tipo2') is not null
drop rule RG_vehiculos_tipo2;

create table vehiculos(


patente char(6) not null,
tipo char(1),--'a'=auto, 'm'=moto
horallegada datetime not null,
horasalida datetime
);

create rule RG_patente_patron


as @patente like '[A-Z][A-Z][A-Z][0-9][0-9][0-9]';

sp_bindrule RG_patente_patron,'vehiculos.patente';

insert into vehiculos values ('FGHIJK','a','1990-02-01 18:00',null);

create rule RG_vehiculos_tipo


as @tipo in ('a','m');

sp_bindrule RG_vehiculos_tipo, 'vehiculos.tipo';

insert into vehiculos values('AAA111','c','2001-10-10 10:10',NULL);

create rule RG_vehiculos_tipo2


as @tipo in ('a','c','m');

sp_bindrule RG_vehiculos_tipo2, 'vehiculos.tipo';

insert into vehiculos values('AAA111','c','2001-10-10 10:10',NULL);

drop rule RG_vehiculos_tipo2;

drop rule RG_vehiculos_tipo;

drop rule RG_patente_patron;

exec sp_unbindrule 'vehiculos.patente';

sp_helpconstraint vehiculos;

sp_help;

drop rule RG_patente_patron;

sp_help;

Podemos utilizar el procedimiento almacenado "sp_help" con el nombre del objeto del cual
queremos informacin, en este caso el nombre de una regla:

sp_help NOMBREREGLA;

muestra nombre, propietario, tipo y fecha de creacin.

Con "sp_help", no sabemos si las reglas existentes estn o no asociadas a algn 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;

muestra la siguiente informacin:

- constraint_type: indica que es una regla con "RULE", nombrando el campo al que est
asociada.

- constraint_name: nombre de la regla.

- constraint_keys: muestra el texto de la regla.

Para ver el texto de una regla empleamos el procedimiento almacenado "sp_helptext"


seguido del nombre de la regla:

sp_helptext NOMBREREGLA;

Tambin 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":

select *from sysobjects;

Si queremos ver todas las reglas creadas por nosotros, podemos tipear:

select *from sysobjects


where xtype='R' and-- tipo regla
name like 'RG%';--bsqueda con comodn

Hemos visto que para mantener la integridad declarativa se emplean restricciones, reglas (que
hemos estudiado en secciones anteriores) y valores predeterminados.

Veamos los valores predeterminados.

Los valores predeterminados se asocian con uno o varios campos (o tipos de datos definidos por 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 bsica:

create default NOMBREVALORPREDETERMINADO


as VALORPREDETERMINADO;

"VALORPREDETERMINADO" no puede hacer referencia a campos de una tabla (u otros objetos) y


debe ser compatible con el tipo de datos y longitud del campo al cual se asocia; si esto no
sucede, SQL Server no lo informa al crear el valor predeterminado ni al asociarlo, pero al
ejecutar una instruccin "insert" muestra un mensaje de error.

En el siguiente ejemplo creamos un valor predeterminado llamado "VP_datodesconocido' con el


valor "Desconocido":

create default VP_datodesconocido


as 'Desconocido'

Luego de crear un valor predeterminado, debemos asociarlo a un campo (o a un tipo de datos


definido por el usuario) ejecutando el procedimiento almacenado del sistema "sp_bindefault":

exec sp_bindefault NOMBRE, 'NOMBRETABLA.CAMPO';

La siguiente sentencia asocia el valor predeterminado creado anteriormente al campo "domicilio"


de la tabla "empleados":

exec sp_bindefault VP_datodesconocido, 'empleados.domicilio';

Podemos asociar un valor predeterminado a varios campos. Asociamos el valor predeterminado


"VP_datodesconocido" al campo "barrio" de la tabla "empleados":

exec sp_bindefault VP_datodesconocido, 'empleados.barrio';

La funcin que cumple un valor predeterminado es bsicamente la misma que una restriccin
"default", las siguientes caractersticas explican algunas semejanzas y diferencias entre ellas:

- un campo solamente puede tener definida UNA restriccin "default", un campo solamente puede
tener UN valor predeterminado asociado a l,

- una restriccin "default" se almacena con la tabla, cuando sta se elimina, las restricciones
tambin. 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 restriccin "default" se establece para un solo campo; un valor predeterminado puede
asociarse a distintos campos (inclusive, de diferentes tablas).

- una restriccin "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 restriccin "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 asociacin reemplaza a la anterior.

Veamos otros ejemplos.


Creamos un valor predeterminado que inserta el valor "0" en un campo de tipo numrico:

create default VP_cero


as 0;

En el siguiente creamos un valor predeterminado que inserta ceros con el formato vlido para un
nmero de telfono:

create default VP_telefono


as '(0000)0-000000';

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".

Una empresa registra los datos de sus clientes en una tabla llamada "clientes".
1- Elimine la tabla si existe:
if object_id ('clientes') is not null
drop table clientes;

2- Recuerde que si elimina una tabla, las asociaciones de reglas y valores


predeterminados de sus
campos desaparecen, pero las reglas y valores predeterminados siguen existiendo. Si
intenta crear
una regla o un valor predeterminado con igual nombre que uno existente, aparecer
un mensaje
indicndolo, por ello, debe eliminarlos (si existen) para poder crearlos nuevamente:
if object_id ('VP_legajo_patron') is not null
drop default VP_legajo_patron;
if object_id ('RG_legajo_patron') is not null
drop rule RG_legajo_patron;
if object_id ('RG_legajo') is not null
drop rule RG_legajo;
if object_id ('VP_datodesconocido') is not null
drop default VP_datodesconocido;
if object_id ('VP_fechaactual') is not null
drop default VP_fechaactual;

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 patrn para los valores que se ingresen en el
campo "legajo" (2
letras seguido de 2 cifras) llamada "RG_legajo_patron":

5- Asocie la regla al campo "legajo".

6- Cree un valor predeterminado para el campo "legajo" ('AA00') llamado


"VP_legajo_patron".

7- Ascielo al campo "legajo".


Recuerde que un campo puede tener un valor predeterminado y reglas asociados.

8- Cree un valor predeterminado con la cadena "??" llamado "VP_datodesconocido".

9- Ascielo al campo "domicilio".

10- Ascielo al campo "ciudad".


Recuerde que un valor predeterminado puede asociarse a varios campos.

11- Ingrese un registro con valores por defecto para los campos "domicilio" y "ciudad"
y vea qu
almacenaron.

12- Intente asociar el valor predeterminado "VP_datodesconocido" al campo


"provincia".
No se puede porque dicho campo tiene una restriccin "default".

13- Cree un valor predeterminado con la fecha actual llamado "VP_fechaactual".

14- Ascielo al campo "fechaingreso".

15- Ingrese algunos registros para ver cmo se almacenan los valores para los cuales
no se insertan
datos.

16- Asocie el valor predeterminado "VP_datodesconocido" al campo "fechaingreso".


Note que se asoci un valor predeterminado de tipo caracter a un campo de tipo
"datetime"; SQL
Server lo permite, pero al intentar ingresar el valor aparece un mensaje de error.

17- Ingrese un registro con valores por defecto.


No lo permite porque son de distintos tipos.

18- Cree una regla que entre en conflicto con el valor predeterminado
"VP_legajo_patron".

19- Asocie la regla al campo "legajo".


Note que la regla especifica que el campo "legajo" debe comenzar con la letra "B",
pero el valor
predeterminado tiene el valor "AA00"; SQL Server realiza la asociacin, pero al
intentar ingresar el
valor predeterminado, no puede hacerlo y muestra un mensaje de error.

20- Intente ingresar un registro con el valor "default" para el campo "legajo".
No lo permite porque al intentar ingresar el valor por defecto establecido con el valor
predeterminado entra en conflicto con la regla "RG_legajo".

if object_id ('clientes') is not null


drop table clientes;

if object_id ('VP_legajo_patron') is not null


drop default VP_legajo_patron;
if object_id ('RG_legajo_patron') is not null
drop rule RG_legajo_patron;
if object_id ('RG_legajo') is not null
drop rule RG_legajo;
if object_id ('VP_datodesconocido') is not null
drop default VP_datodesconocido;
if object_id ('VP_fechaactual') is not null
drop default VP_fechaactual;

create table clientes(


legajo char(4),
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(15),
provincia varchar(20) default 'Cordoba',
fechaingreso datetime
);

create rule RG_legajo_patron


as @valor like '[A-Z][A-Z][0-9][0-9]';

exec sp_bindrule RG_legajo_patron,'clientes.legajo';

create default VP_legajo_patron


as 'AA00';

exec sp_bindefault VP_legajo_patron,'clientes.legajo';

create default VP_datodesconocido


as '??';

exec sp_bindefault VP_datodesconocido,'clientes.domicilio';

exec sp_bindefault VP_datodesconocido,'clientes.ciudad';

insert into clientes values('GF12','Ana Perez',default,default,'Cordoba','2001-10-10');


select *from clientes;

exec sp_bindefault VP_datodesconocido,'clientes.provincia';

create default VP_fechaactual


as getdate();

exec sp_bindefault VP_fechaactual,'clientes.fechaingreso';

insert into clientes default values;


select *from clientes;

exec sp_bindefault VP_datodesconocido,'clientes.fechaingreso';

insert into clientes default values;

create rule RG_legajo


as @valor like 'B%';

exec sp_bindrule RG_legajo,'clientes.legajo';

insert into clientes values (default,'Luis Garcia','Colon 876','Cordoba','Cordoba','2001-


10-10');

Un valor predeterminado no puede eliminarse si no se ha desasociado previamente.

Para deshacer una asociacin empleamos el procedimiento almacenado "sp_unbindefault" seguido


de la tabla y campo al que est asociado:

sp_unbindefault 'TABLA.CAMPO';

Quitamos la asociacin al campo "sueldo" de la tabla "empleados":

sp_unbindefault 'empleados.sueldo';

Con la instruccin "drop default" podemos eliminar un valor predeterminado:

drop default NOMBREVALORPREDETERMINADO;

Eliminamos el valor predeterminado llamado "VP_cero":

drop default VP_cero;

Si eliminamos una tabla, las asociaciones de valores predeterminados de sus campos


desaparecen, pero los valores predeterminados siguen existiendo.

Primer problema:
Una librera almacena los datos de sus libros en una tabla llamada "libros".
1- Elimine la tabla si existe:
if object_id ('libros') is not null
drop table libros;

2- Recuerde que si elimina una tabla, las asociaciones de reglas y valores


predeterminados de sus
campos desaparecen, pero las reglas y valores predeterminados siguen existiendo. Si
intenta crear
una regla o un valor predeterminado con igual nombre que uno existente, aparecer
un mensaje
indicndolo, por ello, debe eliminarlos (si existen) para poder crearlos nuevamente:
if object_id ('VP_cero') is not null
drop default VP_cero;
if object_id ('VP_desconocido') is not null
drop default VP_desconocido;
if object_id ('RG_positivo') is not null
drop rule RG_positivo;

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".

5- Asocie la regla al campo "precio".

6- Asocie la regla al campo "cantidad".

7- Cree un valor predeterminado para que almacene el valor cero, llamado "VP_cero".

8- Ascielo al campo "precio".

9- Ascielo al campo "cantidad".

10- Cree un valor predeterminado con la cadena "Desconocido" llamado


"VP_desconocido".

11- Ascielo al campo "autor".

12- Ascielo al campo "editorial".

13- Vea las reglas y valores predeterminados con "sp_help":


sp_help;

14- Vea las reglas y valores predeterminados asociados a "libros".


Aparecen 6 filas, 2 corresponden a la regla "RG_positivo" asociadas a los campos
"precio" y
"cantidad"; 2 al valor predeterminado "VP_cero" asociados a los campos "precio" y
"cantidad" y 2 al
valor predeterminado "VP_desconocido" asociados a los campos "editorial" y "autor".

15- Ingrese un registro con valores por defecto para todos los campos, excepto "titulo"
y vea qu se
almacen.

15- Quite la asociacin del valor predeterminado "VP_cero" al campo "precio".

16- Ingrese otro registro con valor predeterminado para el campo "precio" y vea cmo
se almacen.

17- Vea las reglas y valores predeterminados asociados a "libros".


5 filas; el valor predeterminado "VP_cero" ya no est asociado al campo "precio".

18- Verifique que el valor predeterminado "VP_cero" existe an en la base de datos.

19- Intente eliminar el valor predeterminado "VP_cero".


No se puede porque est asociado al campo "cantidad".

20- Quite la asociacin del valor predeterminado "VP_cero" al campo "cantidad".

21- Verifique que ya no existe asociacin de este valor predeterminado con la tabla
"libros".
4 filas.

22- Verifique que el valor predeterminado "VP_cero" aun existe en la base de datos.

23- Elimine el valor predeterminado "VP_cero".

24- Verifique que ya no existe en la base de datos.

if object_id ('libros') is not null


drop table libros;

if object_id ('VP_cero') is not null


drop default VP_cero;
if object_id ('VP_desconocido') is not null
drop default VP_desconocido;
if object_id ('RG_positivo') is not null
drop rule RG_positivo;

create table libros(


codigo int identity,
titulo varchar(40) not null,
autor varchar(30),
editorial varchar(20),
precio decimal(5,2),
cantidad smallint
);

create rule RG_positivo


as @valor >=0;

exec sp_bindrule RG_positivo,'libros.precio';

exec sp_bindrule RG_positivo,'libros.cantidad';

create default VP_cero


as 0;

exec sp_bindefault VP_cero,'libros.precio';

exec sp_bindefault VP_cero,'libros.cantidad';

create default VP_desconocido


as 'Desconocido';

exec sp_bindefault VP_desconocido,'libros.autor';

exec sp_bindefault VP_desconocido,'libros.editorial';

-- sp_help;

sp_helpconstraint libros;

insert into libros (titulo) values('Aprenda PHP');


select *from libros;

exec sp_unbindefault 'libros.precio';

insert into libros (titulo) values('Matematica estas ahi');


select *from libros;

sp_helpconstraint libros;

sp_help VP_cero;

drop default VP_cero;

exec sp_unbindefault 'libros.cantidad';

sp_helpconstraint libros;

sp_help VP_cero;

drop default VP_cero;


sp_help VP_cero;

Para obtener informacin 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".

Si al procedimiento almacenado "sp_help" le agregamos el nombre de un valor predeterminado,


nos muestra el nombre, propietario, tipo y fecha de creacin:

sp_help NOMBREVALORPREDETERMINADO;

Con "sp_help", no sabemos si los valores predeterminados existentes estn o no asociadas a algn
campo.

"sp_helpconstraint" retorna una lista de todas las restricciones que tiene una tabla. Tambin los
valores predeterminados asociados; muestra la siguiente informacin:

- constraint_type: indica que es un valor predeterminado con "DEFAULT", nombrando el campo al


que est asociado.

- constraint_name: nombre del valor predeterminado.

- constraint_keys: muestra el texto del valor predeterminado.

Con "sp_helptext" seguido del nombre de un valor predeterminado podemos ver el texto de
cualquier valor predeterminado:

sp_helptext NOMBREVALORPREDETERMINADO;

Tambin 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":

select *from sysobjects;

Si queremos ver todos los valores predeterminados creados por nosotros, podemos tipear:

select *from sysobjects


where xtype='D' and-- tipo valor predeterminado
name like 'VP%';--bsqueda con comodn

SQL Server accede a los datos de dos maneras:


1. recorriendo las tablas; comenzando el principio y extrayendo los registros que cumplen
las condiciones de la consulta.
2. empleando ndices; recorriendo la estructura de rbol del ndice para localizar los
registros y extrayendo los que cumplen las condiciones de la consulta.

Los ndices se emplean para facilitar la obtencin de informacin de una tabla. El indice de una
tabla desempea la misma funcin que el ndice de un libro: permite encontrar datos
rpidamente; en el caso de las tablas, localiza registros.

Una tabla se indexa por un campo (o varios).

Un ndice posibilita el acceso directo y rpido haciendo ms eficiente las bsquedas. Sin ndice,
SQL Server debe recorrer secuencialmente toda la tabla para encontrar un registro.

El objetivo de un indice es acelerar la recuperacin de informacin. La indexacin es una tcnica


que optimiza el acceso a los datos, mejora el rendimiento acelerando las consultas y otras
operaciones. Es til cuando la tabla contiene miles de registros, cuando se realizan operaciones
de ordenamiento y agrupamiento y cuando se combinan varias tablas (tema que veremos ms
adelante).

La desventaja es que consume espacio en el disco en disco y genera costo de mantenimiento


(tiempo y recursos).

Los ndices ms adecuados son aquellos creados con campos que contienen valores nicos.

Es importante identificar el o los campos por los que sera til crear un ndice, aquellos campos
por los cuales se realizan bsqueda 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.

SQL Server permite crear dos tipos de ndices: 1) agrupados y 2) no agrupados.

Dijimos que SQL Server permite crear dos tipos de ndices: 1) agrupados (clustered) y 2) no
agrupados (nonclustered).

1) Un INDICE AGRUPADO es similar a una gua telefnica, 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 slo puede tener UN ndice agrupado.
El tamao medio de un ndice agrupado es aproximadamente el 5% del tamao de la tabla.

2) Un INDICE NO AGRUPADO es como el ndice de un libro, los datos se almacenan en un lugar


diferente al del ndice, los punteros indican el lugar de almacenamiento de los elementos
indizados en la tabla.
Un ndice no agrupado se emplea cuando se realizan distintos tipos de busquedas
frecuentemente, con campos en los que los datos son nicos.
Una tabla puede tener hasta 249 ndices no agrupados.
Si no se especifica un tipo de ndice, de modo predeterminado ser no agrupado.

Los campos de tipo text, ntext e image no se pueden indizar.

Es recomendable crear los ndices agrupados antes que los no agrupados, porque los primeros
modifican el orden fsico de los registros, ordenndolos secuencialmente.

La diferencia bsica entre ndices agrupados y no agrupados es que los registros de un ndice
agrupado estn ordenados y almacenados de forma secuencial en funcin de su clave.

SQL Server crea automaticamente ndices cuando se crea una restriccin "primary key" o "unique"
en una tabla.
Es posible crear ndices en las vistas.

Resumiendo, los ndices facilitan la recuperacin de datos, permitiendo el acceso directo y


acelerando las bsquedas, consultas y otras operaciones que optimizan el rendimiento general.

Para crear ndices empleamos la instruccin "create index".

La sintaxis bsica es la siguiente:

create TIPODEINDICE index NOMBREINDICE


on TABLA(CAMPO);

"TIPODEINDICE" indica si es agrupado (clustered) o no agrupado (nonclustered). Si no


especificamos crea uno No agrupado. Independientemente de si es agrupado o no, tambin se
puede especificar que sea "unique", es decir, no haya valores repetidos. Si se intenta crear un
ndice unique para un campo que tiene valores duplicados, SQL Server no lo permite.

En este ejemplo se crea un ndice agrupado nico para el campo "codigo" de la tabla "libros":

create unique clustered index I_libros_codigo


on libros(codigo);

Para identificar los ndices fcilmente, 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":

create nonclustered index I_libros_titulo


on libros(titulo);

Un ndice puede tener ms 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).

Creamos un ndice compuesto para el campo "autor" y "editorial":

create index I_libros_autoreditorial


on libros(autor,editorial);
SQL Server crea automticamente ndices cuando se establece una restriccin "primary key" o
"unique" en una tabla. Al crear una restriccin "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
restriccin "unique", si no se especifica, el ndice ser no agrupado (non-clustered).

Ahora podemos entender el resultado del procedimiento almacenado "sp_helpconstraint" cuando


en la columna "constraint_type" mostraba el tipo de ndice seguido de las palabras "clustered" o
"non_clustered".

Puede especificarse que un ndice sea agrupado o no agrupado al agregar estas restricciones.
Agregamos una restriccin "primary key" al campo "codigo" de la tabla "libros" especificando que
cree un ndice NO agrupado:

alter table libros


add constraint PK_libros_codigo
primary key nonclustered (codigo);

Para ver los indices de una tabla:

sp_helpindex libros;

Muestra el nombre del ndice, si es agrupado (o no), primary (o unique) y el campo por el cual se
indexa.

Todos los ndices de la base de datos activa se almacenan en la tabla del sistema "sysindexes",
podemos consultar dicha tabla tipeando:

select name from sysindexes;

Para ver todos los ndices de la base de datos activa creados por nosotros podemos tipear la
siguiente consulta:

select name from sysindexes


where name like 'I_%';

Primer problema:

Un profesor guarda algunos datos de sus alumnos en una tabla llamada "alumnos".
1- Elimine la tabla si existe y crela 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)
);

2- Ingresamos algunos registros:


insert into alumnos values ('A123','22222222','Perez','Patricia',5.50);
insert into alumnos values ('A234','23333333','Lopez','Ana',9);
insert into alumnos values ('A345','24444444','Garcia','Carlos',8.5);
insert into alumnos values ('A348','25555555','Perez','Daniela',7.85);
insert into alumnos values ('A457','26666666','Perez','Fabian',3.2);
insert into alumnos values ('A589','27777777','Gomez','Gaston',6.90);

3- Intente crear un ndice agrupado nico para el campo "apellido".


No lo permite porque hay valores duplicados.

4- Cree un ndice agrupado, no nico, para el campo "apellido".

5- Intente establecer una restriccin "primary key" al campo "legajo" especificando


que cree un
ndice agrupado.
No lo permite porque ya existe un ndice agrupado y solamente puede haber uno por
tabla.

6- Establezca la restriccin "primary key" al campo "legajo" especificando que cree un


ndice NO
agrupado.

7- Vea los ndices de "alumnos":


sp_helpindex alumnos;
2 ndices: uno "I_alumnos_apellido", agrupado, con "apellido" y otro
"PK_alumnos_legajo", no
agrupado, unique, con "legajo" que se cre automticamente al crear la restriccin
"primary key".

8- Analice la informacin que muestra "sp_helpconstraint":


sp_helpconstraint libros;
En la columna "constraint_type" aparece "PRIMARY KEY" y entre parntesis, el tipo de
ndice creado.

9- Cree un ndice unique no agrupado para el campo "documento".

10- Intente ingresar un alumno con documento duplicado.


No lo permite.

11- Veamos los indices de "alumnos".


Aparecen 3 filas, uno por cada ndice.

12- Cree un ndice compuesto para el campo "apellido" y "nombre".


Se crear uno no agrupado porque no especificamos el tipo, adems, ya existe uno
agrupado y
solamente puede haber uno por tabla.

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.

14- Cree una restriccin unique para el campo "documento".


15- Vea la informacin de "sp_helpconstraint".

16- Vea los ndices de "alumnos".


Aparecen 5 filas, uno por cada ndice.

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 automticamente al agregarse
una restriccin
"primary" o "unique" no comienzan con "I_".

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)
);

insert into alumnos values ('A123','22222222','Perez','Patricia',5.50);


insert into alumnos values ('A234','23333333','Lopez','Ana',9);
insert into alumnos values ('A345','24444444','Garcia','Carlos',8.5);
insert into alumnos values ('A348','25555555','Perez','Daniela',7.85);
insert into alumnos values ('A457','26666666','Perez','Fabian',3.2);
insert into alumnos values ('A589','27777777','Gomez','Gaston',6.90);

create unique clustered index I_alumnos_apellido


on alumnos(apellido);

create clustered index I_alumnos_apellido


on alumnos(apellido);

alter table alumnos


add constraint PK_alumnos_legajo
primary key clustered (legajo);

alter table alumnos


add constraint PK_alumnos_legajo
primary key nonclustered (legajo);
sp_helpindex alumnos;

sp_helpconstraint libros;

create unique nonclustered index I_alumnos_documento


on alumnos(documento);

insert into alumnos values ('A789','27777777','Morales','Hector',8);

sp_helpindex alumnos;

create index I_alumnos_apellidonombre


on alumnos(apellido,nombre);

select name from sysindexes


where name like '%alumnos%';

alter table alumnos


add constraint UQ_alumnos_documento
unique (documento);

sp_helpconstraint alumnos;

sp_helpindex alumnos;

select name from sysindexes


where name like '%alumnos%';

select name from sysindexes


where name like 'I_%';

Vimos que para crear ndices empleamos la instruccin "create index".

Empleando la opcin "drop_existing" junto con "create index" permite regenerar un ndice, con
ello evitamos eliminarlo y volver a crearlo. La sintaxis es la siguiente:

create TIPODEINDICE index NOMBREINDICE


on TABLA(CAMPO)
with drop_existing;

Tambin podemos modificar alguna de las caractersticas de un ndice con esta opcin, a saber:

- tipo: cambindolo 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 algn
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":

create nonclustered index I_libros


on libros(titulo);

Regeneramos el ndice "I_libros" y lo convertimos a agrupado:

create clustered index I_libros


on libros(titulo)
with drop_existing;

Agregamos un campo al ndice "I_libros":

create clustered index I_libros


on libros(titulo,editorial)
with drop_existing;

Esta opcin no puede emplearse con ndices creados a partir de una restriccin "primary key" o
"unique".

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)
);

create nonclustered index I_alumnos_apellido


on alumnos(apellido);

sp_helpindex alumnos;

create nonclustered index I_alumnos_apellido


on alumnos(apellido,nombre)
with drop_existing;

exec sp_helpindex alumnos;

alter table alumnos


add constraint UQ_alumnos_documento
unique nonclustered (documento);

sp_helpindex alumnos;

create clustered index UQ_alumnos_documento


on alumnos(documento)
with drop_existing;

create nonclustered index I_alumnos_legajo


on alumnos(legajo);

sp_helpindex alumnos;

create clustered index I_alumnos_legajo


on alumnos(legajo)
with drop_existing;

exec sp_helpindex alumnos;

create nonclustered index I_alumnos_legajo


on alumnos(legajo)
with drop_existing;

create nonclustered index I_alumnos_apellido


on alumnos(apellido)
with drop_existing;

create clustered index I_alumnos_apellido


on alumnos(apellido)
with drop_existing;

create unique clustered index I_alumnos_legajo


on alumnos(legajo)
with drop_existing;

sp_helpindex alumnos;

create clustered index I_alumnos_legajo


on alumnos(legajo)
with drop_existing;

sp_helpindex alumnos;

Los ndices creados con "create index" se eliminan con "drop index"; la siguiente es la sintaxis
bsica:

drop index NOMBRETABLA.NOMBREINDICE;

Eliminamos el ndice "I_libros_titulo":

drop index libros.I_libros_titulo;

Los ndices que SQL Server crea automticamente al establecer una restriccin "primary key" o
"unique" no pueden eliminarse con "drop index", se eliminan automticamente cuando quitamos
la restriccin.
Podemos averiguar si existe un ndice para eliminarlo, consultando la tabla del sistema
"sysindexes":

if exists (select name from sysindexes


where name = 'NOMBREINDICE')
drop index NOMBRETABLA.NOMBREINDICE;

Eliminamos el ndice "I_libros_titulo" si existe:

if exists (select *from sysindexes


where name = 'I_libros_titulo')
drop index libros.I_libros_titulo;

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)
);

create nonclustered index I_alumnos_apellido


on alumnos(apellido);

alter table alumnos


add constraint PK_alumnos_legajo
primary key clustered (legajo);

sp_helpindex alumnos;

drop index PK_alumnos_legajo;

drop index I_alumnos_apellido;

drop index alumnos.I_alumnos_apellido;

sp_helpindex alumnos;

if exists (select name from sysindexes


where name = 'I_alumnos_apellido')
drop index alumnos.I_alumnos_apellido;

alter table alumnos


drop PK_alumnos_legajo;

sp_helpindex alumnos;
Hasta el momento hemos trabajado con una sola tabla, pero generalmente, se trabaja con ms
de una.

Para evitar la repeticin de datos y ocupar menos espacio, se separa la informacin en varias
tablas. Cada tabla almacena parte de la informacin que necesitamos registrar.

Por ejemplo, los datos de nuestra tabla "libros" podran separarse en 2 tablas, una llamada
"libros" y otra "editoriales" que guardar la informacin de las editoriales.
En nuestra tabla "libros" haremos referencia a la editorial colocando un cdigo que la identifique.

Veamos:

create table libros(


codigo int identity,
titulo varchar(40) not null,
autor varchar(30) not null default 'Desconocido',
codigoeditorial tinyint not null,
precio decimal(5,2),
primary key (codigo)
);

create table editoriales(


codigo tinyint identity,
nombre varchar(20) not null,
primary key(codigo)
);

De esta manera, evitamos almacenar tantas veces los nombres de las editoriales en la tabla
"libros" y guardamos el nombre en la tabla "editoriales"; para indicar la editorial de cada libro
agregamos un campo que hace referencia al cdigo de la editorial en la tabla "libros" y en
"editoriales".

Al recuperar los datos de los libros con la siguiente instruccin:

select* from libros;

vemos que en el campo "editorial" aparece el cdigo, 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 informacin de las dos.

Cuando obtenemos informacin de ms de una tabla decimos que hacemos un "join"


(combinacin).

Veamos un ejemplo:

select *from libros


join editoriales
on libros.codigoeditorial=editoriales.codigo;
Resumiendo: si distribuimos la informacin en varias tablas evitamos la redundancia de datos y
ocupamos menos espacio fsico en el disco. Un join es una operacin que relaciona dos o ms
tablas para obtener un resultado que incluya datos (campos y registros) de ambas; las tablas
participantes se combinan segn los campos comunes a ambas tablas.

Hay hay tres tipos de combinaciones. En los siguientes captulos explicamos cada una de ellas.

Un join es una operacin que relaciona dos o ms tablas para obtener un resultado que incluya
datos (campos y registros) de ambas; las tablas participantes se combinan segn los campos
comunes a ambas tablas.

Hay tres tipos de combinaciones:

1. combinaciones internas (inner join o join),


2. combinaciones externas y
3. combinaciones cruzadas.

Tambin es posible emplear varias combinaciones en una consulta "select", incluso puede
combinarse una tabla consigo misma.

La combinacin interna emplea "join", que es la forma abreviada de "inner join". Se emplea para
obtener informacin de dos tablas y combinar dicha informacin en una salida.

La sintaxis bsica es la siguiente:

select CAMPOS
from TABLA1
join TABLA2
on CONDICIONdeCOMBINACION;

Ejemplo:

select *from libros


join editoriales
on codigoeditorial=editoriales.codigo;

Analicemos la consulta anterior.

- especificamos los campos que aparecern en el resultado en la lista de seleccin;

- indicamos el nombre de la tabla luego del "from" ("libros");

- combinamos esa tabla con "join" y el nombre de la otra tabla ("editoriales"); se especifica qu
tablas se van a combinar y cmo;

- cuando se combina informacin 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 condicin
para enlazarlas, es decir, el campo por el cual se combinarn, que tienen en comn.
"on" hace coincidir registros de ambas tablas basndose en el valor de tal campo, en el ejemplo,
el campo "codigoeditorial" de "libros" y el campo "codigo" de "editoriales" son los que enlazarn
ambas tablas. Se emplean campos comunes, que deben tener tipos de datos iguales o similares.
La condicion de combinacin, es decir, el o los campos por los que se van a combinar (parte
"on"), se especifica segn las claves primarias y externas.

Note que en la consulta, al nombrar el campo usamos el nombre de la tabla tambin. 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 clusula "on"
se debe hacer referencia a la clave completa, es decir, la condicin referenciar a todos los
campos clave que identifican al registro.

Se puede incluir en la consulta join la clusula "where" para restringir los registros que retorna el
resultado; tambin "order by", "distinct", etc..

Se emplea este tipo de combinacin para encontrar registros de la primera tabla que se
correspondan con los registros de la otra, es decir, que cumplan la condicin del "on". Si un valor
de la primera tabla no se encuentra en la segunda tabla, el registro no aparece.

Para simplificar la sentencia podemos usar un alias para cada tabla:

select l.codigo,titulo,autor,nombre
from libros as l
join editoriales as e
on l.codigoeditorial=e.codigo;

En algunos casos (como en este ejemplo) el uso de alias es para fines de simplificacin y hace
ms legible la consulta si es larga y compleja, pero en algunas consultas es absolutamente
necesario.

Primer problema:

Una empresa tiene registrados sus clientes en una tabla llamada "clientes", tambin
tiene una tabla
"provincias" donde registra los nombres de las provincias.
1- Elimine las tablas "clientes" y "provincias", si existen:
if (object_id('clientes')) is not null
drop table clientes;
if (object_id('provincias')) is not null
drop table provincias;

2- Crelas con las siguientes estructuras:


create table clientes (
codigo int identity,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia tinyint not null,
primary key(codigo)
);

create table provincias(


codigo tinyint identity,
nombre varchar(20),
primary key (codigo)
);

3- Ingrese algunos registros para ambas tablas:


insert into provincias (nombre) values('Cordoba');
insert into provincias (nombre) values('Santa Fe');
insert into provincias (nombre) values('Corrientes');

insert into clientes values ('Lopez Marcos','Colon 111','Crdoba',1);


insert into clientes values ('Perez Ana','San Martin 222','Cruz del Eje',1);
insert into clientes values ('Garcia Juan','Rivadavia 333','Villa Maria',1);
insert into clientes values ('Perez Luis','Sarmiento 444','Rosario',2);
insert into clientes values ('Pereyra Lucas','San Martin 555','Cruz del Eje',1);
insert into clientes values ('Gomez Ines','San Martin 666','Santa Fe',2);
insert into clientes values ('Torres Fabiola','Alem 777','Ibera',3);

4- Obtenga los datos de ambas tablas, usando alias:


select c.nombre,domicilio,ciudad,p.nombre
from clientes as c
join provincias as p
on c.codigoprovincia=p.codigo;

5- Obtenga la misma informacin anterior pero ordenada por nombre de provincia.

6- Recupere los clientes de la provincia "Santa Fe" (2 registros devueltos)

if (object_id('clientes')) is not null


drop table clientes;
if (object_id('provincias')) is not null
drop table provincias;

create table clientes (


codigo int identity,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia tinyint not null,
primary key(codigo)
);

create table provincias(


codigo tinyint identity,
nombre varchar(20),
primary key (codigo)
);

insert into provincias (nombre) values('Cordoba');


insert into provincias (nombre) values('Santa Fe');
insert into provincias (nombre) values('Corrientes');

insert into clientes values ('Lopez Marcos','Colon 111','Crdoba',1);


insert into clientes values ('Perez Ana','San Martin 222','Cruz del Eje',1);
insert into clientes values ('Garcia Juan','Rivadavia 333','Villa Maria',1);
insert into clientes values ('Perez Luis','Sarmiento 444','Rosario',2);
insert into clientes values ('Pereyra Lucas','San Martin 555','Cruz del Eje',1);
insert into clientes values ('Gomez Ines','San Martin 666','Santa Fe',2);
insert into clientes values ('Torres Fabiola','Alem 777','Ibera',3);

select c.nombre,domicilio,ciudad,p.nombre
from clientes as c
join provincias as p
on c.codigoprovincia=p.codigo;

select c.nombre,domicilio,ciudad,p.nombre
from clientes as c
join provincias as p
on c.codigoprovincia=p.codigo
order by p.nombre;

select c.nombre,domicilio,ciudad
from clientes as c
join provincias as p
on c.codigoprovincia=p.codigo
where p.nombre='Santa Fe';

Vimos que una combinacin interna (join) encuentra registros de la primera tabla que se
correspondan con los registros de la segunda, es decir, que cumplan la condicin del "on" y si un
valor de la primera tabla no se encuentra en la segunda tabla, el registro no aparece.

Si queremos saber qu registros de una tabla NO encuentran correspondencia en la otra, es decir,


no existe valor coincidente en la segunda, necesitamos otro tipo de combinacin, "outer join"
(combinacin externa).

Las combinaciones externas combinan registros de dos tablas que cumplen la condicin, ms los
registros de la segunda tabla que no la cumplen; es decir, muestran todos los registros de las
tablas relacionadas, an cuando no haya valores coincidentes entre ellas.

Este tipo de combinacin se emplea cuando se necesita una lista completa de los datos de una de
las tablas y la informacin que cumple con la condicin. 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.

Vamos a estudiar las primeras.


Se emplea una combinacin 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".

En el siguiente ejemplo solicitamos el ttulo y nombre de la editorial de los libros:

select titulo,nombre
from editoriales as e
left join libros as l
on codigoeditorial = e.codigo;

El resultado mostrar el ttulo y nombre de la editorial; las editoriales de las cuales no hay libros,
es decir, cuyo cdigo de editorial no est presente en "libros" aparece en el resultado, pero con
el valor "null" en el campo "titulo".

Es importante la posicin 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 bsica es la siguiente:

select CAMPOS
from TABLAIZQUIERDA
left join TABLADERECHA
on CONDICION;

En el siguiente ejemplo solicitamos el ttulo y el nombre la editorial, la sentencia es similar a la


anterior, la diferencia est en el orden de las tablas:

select titulo,nombre
from libros as l
left join editoriales as e
on codigoeditorial = e.codigo;

El resultado mostrar el ttulo del libro y el nombre de la editorial; los ttulos cuyo cdigo 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 cdigo 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;

Tambin podemos mostrar las editoriales que NO estn 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;

if (object_id('clientes')) is not null


drop table clientes;
if (object_id('provincias')) is not null
drop table provincias;

create table clientes (


codigo int identity,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia tinyint not null,
primary key(codigo)
);

create table provincias(


codigo tinyint identity,
nombre varchar(20),
primary key (codigo)
);

insert into provincias (nombre) values('Cordoba');


insert into provincias (nombre) values('Santa Fe');
insert into provincias (nombre) values('Corrientes');

insert into clientes values ('Lopez Marcos','Colon 111','Crdoba',1);


insert into clientes values ('Perez Ana','San Martin 222','Cruz del Eje',1);
insert into clientes values ('Garcia Juan','Rivadavia 333','Villa Maria',1);
insert into clientes values ('Perez Luis','Sarmiento 444','Rosario',2);
insert into clientes values ('Gomez Ines','San Martin 666','Santa Fe',2);
insert into clientes values ('Torres Fabiola','Alem 777','La Plata',4);
insert into clientes values ('Garcia Luis','Sucre 475','Santa Rosa',5);

select c.nombre,domicilio,ciudad, p.nombre


from clientes as c
left join provincias as p
on codigoprovincia = p.codigo;

select c.nombre,domicilio,ciudad, p.nombre


from provincias as p
left join clientes as c
on codigoprovincia = p.codigo;

select c.nombre,domicilio,ciudad, p.nombre


from clientes as c
left join provincias as p
on codigoprovincia = p.codigo
where p.codigo is not null;

select c.nombre,domicilio,ciudad, p.nombre


from clientes as c
left join provincias as p
on codigoprovincia = p.codigo
where p.codigo is null
order by c.nombre;

select c.nombre,domicilio,ciudad, p.nombre


from clientes as c
left join provincias as p
on codigoprovincia = p.codigo
where p.nombre='Cordoba';

Vimos que una combinacin externa izquierda (left join) encuentra registros de la tabla izquierda
que se correspondan con los registros de la tabla derecha y si un valor de la tabla izquierda no se
encuentra en la tabla derecha, el registro muestra los campos correspondientes a la tabla de la
derecha seteados a "null".

Una combinacin externa derecha ("right outer join" o "right join") opera del mismo modo slo
que la tabla derecha es la que localiza los registros en la tabla izquierda.

En el siguiente ejemplo solicitamos el ttulo y nombre de la editorial de los libros empleando un


"right join":

select titulo,nombre
from libros as l
right join editoriales as e
on codigoeditorial = e.codigo;

El resultado mostrar el ttulo y nombre de la editorial; las editoriales de las cuales no hay libros,
es decir, cuyo cdigo 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 posicin 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 bsica es la siguiente:

select CAMPOS
from TABLAIZQUIERDA
right join TABLADERECHA
on CONDICION;

Un "right join" tambin puede tener clusula "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 estn 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;

Vimos que una combinacin externa izquierda (left join) encuentra registros de la tabla izquierda
que se correspondan con los registros de la tabla derecha y si un valor de la tabla izquierda no se
encuentra en la tabla derecha, el registro muestra los campos correspondientes a la tabla de la
derecha seteados a "null".

Una combinacin externa derecha ("right outer join" o "right join") opera del mismo modo slo
que la tabla derecha es la que localiza los registros en la tabla izquierda.

En el siguiente ejemplo solicitamos el ttulo y nombre de la editorial de los libros empleando un


"right join":

select titulo,nombre
from libros as l
right join editoriales as e
on codigoeditorial = e.codigo;

El resultado mostrar el ttulo y nombre de la editorial; las editoriales de las cuales no hay libros,
es decir, cuyo cdigo 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 posicin 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 bsica es la siguiente:

select CAMPOS
from TABLAIZQUIERDA
right join TABLADERECHA
on CONDICION;

Un "right join" tambin puede tener clusula "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 estn 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;

Primer problema:

Una empresa tiene registrados sus clientes en una tabla llamada "clientes", tambin
tiene una
tabla "provincias" donde registra los nombres de las provincias.
1- Elimine las tablas "clientes" y "provincias", si existen y cree las tablas:
if (object_id('clientes')) is not null
drop table clientes;
if (object_id('provincias')) is not null
drop table provincias;

create table clientes (


codigo int identity,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia tinyint not null,
primary key(codigo)
);

create table provincias(


codigo tinyint identity,
nombre varchar(20),
primary key (codigo)
);

2- Ingrese algunos registros para ambas tablas:


insert into provincias (nombre) values('Cordoba');
insert into provincias (nombre) values('Santa Fe');
insert into provincias (nombre) values('Corrientes');

insert into clientes values ('Lopez Marcos','Colon 111','Crdoba',1);


insert into clientes values ('Perez Ana','San Martin 222','Cruz del Eje',1);
insert into clientes values ('Garcia Juan','Rivadavia 333','Villa Maria',1);
insert into clientes values ('Perez Luis','Sarmiento 444','Rosario',2);
insert into clientes values ('Gomez Ines','San Martin 666','Santa Fe',2);
insert into clientes values ('Torres Fabiola','Alem 777','La Plata',4);
insert into clientes values ('Garcia Luis','Sucre 475','Santa Rosa',5);

3- Muestre todos los datos de los clientes, incluido el nombre de la provincia


empleando un "right
join".

4- Obtenga la misma salida que la consulta anterior pero empleando un "left join".

5- Empleando un "right join", muestre solamente los clientes de las provincias que
existen en
"provincias" (5 registros)

6- Muestre todos los clientes cuyo cdigo de provincia NO existe en "provincias"


ordenados por
ciudad (2 registros)

if (object_id('clientes')) is not null


drop table clientes;
if (object_id('provincias')) is not null
drop table provincias;

create table clientes (


codigo int identity,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia tinyint not null,
primary key(codigo)
);

create table provincias(


codigo tinyint identity,
nombre varchar(20),
primary key (codigo)
);

insert into provincias (nombre) values('Cordoba');


insert into provincias (nombre) values('Santa Fe');
insert into provincias (nombre) values('Corrientes');

insert into clientes values ('Lopez Marcos','Colon 111','Crdoba',1);


insert into clientes values ('Perez Ana','San Martin 222','Cruz del Eje',1);
insert into clientes values ('Garcia Juan','Rivadavia 333','Villa Maria',1);
insert into clientes values ('Perez Luis','Sarmiento 444','Rosario',2);
insert into clientes values ('Gomez Ines','San Martin 666','Santa Fe',2);
insert into clientes values ('Torres Fabiola','Alem 777','La Plata',4);
insert into clientes values ('Garcia Luis','Sucre 475','Santa Rosa',5);

select c.nombre,domicilio,ciudad, p.nombre


from provincias as p
right join clientes as c
on codigoprovincia = p.codigo;

select c.nombre,domicilio,ciudad, p.nombre


from clientes as c
left join provincias as p
on codigoprovincia = p.codigo;

select c.nombre,domicilio,ciudad, p.nombre


from provincias as p
right join clientes as c
on codigoprovincia = p.codigo
where p.codigo is not null;

select c.nombre,domicilio,ciudad, p.nombre


from provincias as p
right join clientes as c
on codigoprovincia = p.codigo
where p.codigo is null
order by ciudad;

Vimos que un "left join" encuentra registros de la tabla izquierda que se correspondan con los
registros de la tabla derecha y si un valor de la tabla izquierda no se encuentra en la tabla
derecha, el registro muestra los campos correspondientes a la tabla de la derecha seteados a
"null". Aprendimos tambin que un "right join" opera del mismo modo slo que la tabla derecha es
la que localiza los registros en la tabla izquierda.

Una combinacin 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 cdigo de editorial no existe en la tabla "editoriales" y las editoriales de las cuales no
hay correspondencia en "libros".

Primer problema:

Un club dicta clases de distintos deportes. Almacena la informacin en una tabla


llamada "deportes"
en la cual incluye el nombre del deporte y el nombre del profesor y en otra tabla
llamada
"inscriptos" que incluye el documento del socio que se inscribe, el deporte y si la
matricula est
paga o no.
1- Elimine las tablas si existen y cree las tablas:
if (object_id('deportes')) is not null
drop table deportes;
if (object_id('inscriptos')) is not null
drop table inscriptos;
create table deportes(
codigo tinyint identity,
nombre varchar(30),
profesor varchar(30),
primary key (codigo)
);
create table inscriptos(
documento char(8),
codigodeporte tinyint not null,
matricula char(1) --'s'=paga 'n'=impaga
);

2- Ingrese algunos registros para ambas tablas:


insert into deportes values('tenis','Marcelo Roca');
insert into deportes values('natacion','Marta Torres');
insert into deportes values('basquet','Luis Garcia');
insert into deportes values('futbol','Marcelo Roca');

insert into inscriptos values('22222222',3,'s');


insert into inscriptos values('23333333',3,'s');
insert into inscriptos values('24444444',3,'n');
insert into inscriptos values('22222222',2,'s');
insert into inscriptos values('23333333',2,'s');
insert into inscriptos values('22222222',4,'n');
insert into inscriptos values('22222222',5,'n');

3- Muestre todos la informacin de la tabla "inscriptos", y consulte la tabla "deportes"


para
obtener el nombre de cada deporte (6 registros)

4- Empleando un "left join" con "deportes" obtenga todos los datos de los inscriptos (7
registros)

5- Obtenga la misma salida anterior empleando un "rigth join".

6- Muestre los deportes para los cuales no hay inscriptos, empleando un "left join" (1
registro)

7- Muestre los documentos de los inscriptos a deportes que no existen en la tabla


"deportes" (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)

if (object_id('deportes')) is not null


drop table deportes;
if (object_id('inscriptos')) is not null
drop table inscriptos;
create table deportes(
codigo tinyint identity,
nombre varchar(30),
profesor varchar(30),
primary key (codigo)
);
create table inscriptos(
documento char(8),
codigodeporte tinyint not null,
matricula char(1) --'s'=paga 'n'=impaga
);

insert into deportes values('tenis','Marcelo Roca');


insert into deportes values('natacion','Marta Torres');
insert into deportes values('basquet','Luis Garcia');
insert into deportes values('futbol','Marcelo Roca');

insert into inscriptos values('22222222',3,'s');


insert into inscriptos values('23333333',3,'s');
insert into inscriptos values('24444444',3,'n');
insert into inscriptos values('22222222',2,'s');
insert into inscriptos values('23333333',2,'s');
insert into inscriptos values('22222222',4,'n');
insert into inscriptos values('22222222',5,'n');
select documento,d.nombre,matricula
from inscriptos as i
join deportes as d
on codigodeporte=codigo;

select documento,d.nombre,matricula
from inscriptos as i
left join deportes as d
on codigodeporte=codigo;

select documento,d.nombre,matricula
from deportes as d
right join inscriptos as i
on codigodeporte=codigo;

select nombre
from deportes as d
left join inscriptos as i
on codigodeporte=codigo
where codigodeporte is null;

select documento
from inscriptos as i
left join deportes as d
on codigodeporte=codigo
where codigo is null;

select documento,nombre,profesor,matricula
from inscriptos as i
full join deportes as d
on codigodeporte=codigo;

Vimos que hay tres tipos de combinaciones: 1) combinaciones internas (join), 2) combinaciones
externas (left, right y full join) y 3) combinaciones cruzadas.

Las combinaciones cruzadas (cross join) muestran todas las combinaciones de todos los registros
de las tablas combinadas. Para este tipo de join no se incluye una condicin de enlace. Se genera
el producto cartesiano en el que el nmero de filas del resultado es igual al nmero de registros
de la primera tabla multiplicado por el nmero de registros de la segunda tabla, es decir, si hay 5
registros en una tabla y 6 en la otra, retorna 30 filas.

La sintaxis bsica es sta:

select CAMPOS
from TABLA1
cross join TABLA2;

Veamos un ejemplo. Un pequeo 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":

select c.nombre as 'plato principal', p.nombre as 'postre'


from comidas as c
cross join postres as p;

La salida muestra cada plato combinado con cada uno de los postres.

Como cualquier tipo de "join", puede emplearse una clusula "where" que condicione la salida.

Primer problema:

Una agencia matrimonial almacena la informacin de sus clientes de sexo femenino en


una tabla
llamada "mujeres" y en otra la de sus clientes de sexo masculino llamada "varones".
1- Elimine las tablas si existen y crelas:
if object_id('mujeres') is not null
drop table mujeres;
if object_id('varones') is not null
drop table varones;
create table mujeres(
nombre varchar(30),
domicilio varchar(30),
edad int
);
create table varones(
nombre varchar(30),
domicilio varchar(30),
edad int
);

2- Ingrese los siguientes registros:


insert into mujeres values('Maria Lopez','Colon 123',45);
insert into mujeres values('Liliana Garcia','Sucre 456',35);
insert into mujeres values('Susana Lopez','Avellaneda 98',41);

insert into varones values('Juan Torres','Sarmiento 755',44);


insert into varones values('Marcelo Oliva','San Martin 874',56);
insert into varones values('Federico Pereyra','Colon 234',38);
insert into varones values('Juan Garcia','Peru 333',50);

3- La agencia necesita la combinacin de todas las personas de sexo femenino con las
de sexo
masculino. Use un "cross join" (12 registros)

4- Realice la misma combinacin pero considerando solamente las personas mayores


de 40 aos (6
registros)
5- Forme las parejas pero teniendo en cuenta que no tengan una diferencia superior a
10 aos (8
registros)

if object_id('mujeres') is not null


drop table mujeres;
if object_id('varones') is not null
drop table varones;
create table mujeres(
nombre varchar(30),
domicilio varchar(30),
edad int
);
create table varones(
nombre varchar(30),
domicilio varchar(30),
edad int
);

insert into mujeres values('Maria Lopez','Colon 123',45);


insert into mujeres values('Liliana Garcia','Sucre 456',35);
insert into mujeres values('Susana Lopez','Avellaneda 98',41);

insert into varones values('Juan Torres','Sarmiento 755',44);


insert into varones values('Marcelo Oliva','San Martin 874',56);
insert into varones values('Federico Pereyra','Colon 234',38);
insert into varones values('Juan Garcia','Peru 333',50);

select m.nombre,m.edad,v.nombre,v.edad
from mujeres as m
cross join varones as v;

select m.nombre,m.edad,v.nombre,v.edad
from mujeres as m
cross join varones as v
where m.edad>40 and
v.edad>40;

select m.nombre,m.edad,v.nombre,v.edad
from mujeres as m
cross join varones as v
where m.edad-v.edad between -10 and 10;

Dijimos que es posible combinar una tabla consigo misma.

Un pequeo 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 combinacin de platos empleando un "cross join" con una sola tabla:

select c1.nombre as 'plato principal',


c2.nombre as postre,
c1.precio+c2.precio as total
from comidas as c1
cross join comidas as c2;

En la consulta anterior aparecen filas duplicadas, para evitarlo debemos emplear un "where":

select c1.nombre as 'plato principal',


c2.nombre as postre,
c1.precio+c2.precio as total
from comidas as c1
cross join comidas as c2
where c1.rubro='plato' and
c2.rubro='postre';

En la consulta anterior se emple un "where" que especifica que se combine "plato" con "postre".

En una autocombinacin 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".

Tambin se puede realizar una autocombinacin con "join":

select c1.nombre as 'plato principal',


c2.nombre as postre,
c1.precio+c2.precio as total
from comidas as c1
join comidas as c2
on c1.codigo<>c2.codigo
where c1.rubro='plato' and
c2.rubro='postre';

Para que no aparezcan filas duplicadas se agrega un "where".

Primer problema:

Una agencia matrimonial almacena la informacin de sus clientes en una tabla llamada
"clientes".
1- Elimine la tabla si existe y crela:
if object_id('clientes') is not null
drop table clientes;

create table clientes(


nombre varchar(30),
sexo char(1),--'f'=femenino, 'm'=masculino
edad int,
domicilio varchar(30)
);

2- Ingrese los siguientes registros:


insert into clientes values('Maria Lopez','f',45,'Colon 123');
insert into clientes values('Liliana Garcia','f',35,'Sucre 456');
insert into clientes values('Susana Lopez','f',41,'Avellaneda 98');
insert into clientes values('Juan Torres','m',44,'Sarmiento 755');
insert into clientes values('Marcelo Oliva','m',56,'San Martin 874');
insert into clientes values('Federico Pereyra','m',38,'Colon 234');
insert into clientes values('Juan Garcia','m',50,'Peru 333');

3- La agencia necesita la combinacin de todas las personas de sexo femenino con las
de sexo
masculino. Use un "cross join" (12 registros)

4- Obtenga la misma salida enterior pero realizando un "join".

5- Realice la misma autocombinacin que el punto 3 pero agregue la condicin que las
parejas no
tengan una diferencia superior a 5 aos (5 registros)

if object_id('clientes') is not null


drop table clientes;

create table clientes(


nombre varchar(30),
sexo char(1),--'f'=femenino, 'm'=masculino
edad int,
domicilio varchar(30)
);

insert into clientes values('Maria Lopez','f',45,'Colon 123');


insert into clientes values('Liliana Garcia','f',35,'Sucre 456');
insert into clientes values('Susana Lopez','f',41,'Avellaneda 98');
insert into clientes values('Juan Torres','m',44,'Sarmiento 755');
insert into clientes values('Marcelo Oliva','m',56,'San Martin 874');
insert into clientes values('Federico Pereyra','m',38,'Colon 234');
insert into clientes values('Juan Garcia','m',50,'Peru 333');

select cm.nombre,cm.edad,cv.nombre,cv.edad
from clientes as cm
cross join clientes cv
where cm.sexo='f' and cv.sexo='m';

select cm.nombre,cm.edad,cv.nombre,cv.edad
from clientes as cm
join clientes cv
on cm.nombre<>cv.nombre
where cm.sexo='f' and cv.sexo='m';

select cm.nombre,cm.edad,cv.nombre,cv.edad
from clientes as cm
cross join clientes cv
where cm.sexo='f' and cv.sexo='m' and
cm.edad-cv.edad between -5 and 5;

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:

select nombre as editorial,


count(*) as cantidad
from editoriales as e
join libros as l
on codigoeditorial=e.codigo
group by e.nombre;

Note que las editoriales que no tienen libros no aparecen en la salida porque empleamos un
"join".

Empleamos otra funcin de agrupamiento con "left join". Para conocer el mayor precio de los
libros de cada editorial usamos la funcin "max()", hacemos un "left join" y agrupamos por nombre
de la editorial:

select nombre as editorial,


max(precio) as 'mayor precio'
from editoriales as e
left join libros as l
on codigoeditorial=e.codigo
group by nombre;

En la sentencia anterior, mostrar, para la editorial de la cual no haya libros, el valor "null" en la
columna calculada.

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;

2- Cree las tablas:


create table visitantes(
nombre varchar(30),
edad tinyint,
sexo char(1) default 'f',
domicilio varchar(30),
codigociudad tinyint not null,
mail varchar(30),
montocompra decimal (6,2)
);

create table ciudades(


codigo tinyint identity,
nombre varchar(20)
);

3- Ingrese algunos registros:


insert into ciudades values('Cordoba');
insert into ciudades values('Carlos Paz');
insert into ciudades values('La Falda');
insert into ciudades values('Cruz del Eje');

insert into visitantes values


('Susana Molina', 35,'f','Colon 123', 1, null,59.80);
insert into visitantes values
('Marcos Torres', 29,'m','Sucre 56', 1, 'marcostorres@hotmail.com',150.50);
insert into visitantes values
('Mariana Juarez', 45,'f','San Martin 111',2,null,23.90);
insert into visitantes values
('Fabian Perez',36,'m','Avellaneda 213',3,'fabianperez@xaxamail.com',0);
insert into visitantes values
('Alejandra Garcia',28,'f',null,2,null,280.50);
insert into visitantes values
('Gaston Perez',29,'m',null,5,'gastonperez1@gmail.com',95.40);
insert into visitantes values
('Mariana Juarez',33,'f',null,2,null,90);

4- Cuente la cantidad de visitas por ciudad mostrando el nombre de la ciudad (3 filas)

5- Muestre el promedio de gastos de las visitas agrupados por ciudad y sexo (4 filas)

6- Muestre la cantidad de visitantes con mail, agrupados por ciudad (3 filas)

7- Obtenga el monto de compra ms alto de cada ciudad (3 filas)

if object_id('visitantes') is not null


drop table visitantes;
if object_id('ciudades') is not null
drop table ciudades;
create table visitantes(
nombre varchar(30),
edad tinyint,
sexo char(1) default 'f',
domicilio varchar(30),
codigociudad tinyint not null,
mail varchar(30),
montocompra decimal (6,2)
);

create table ciudades(


codigo tinyint identity,
nombre varchar(20)
);

insert into ciudades values('Cordoba');


insert into ciudades values('Carlos Paz');
insert into ciudades values('La Falda');
insert into ciudades values('Cruz del Eje');

insert into visitantes values


('Susana Molina', 35,'f','Colon 123', 1, null,59.80);
insert into visitantes values
('Marcos Torres', 29,'m','Sucre 56', 1, 'marcostorres@hotmail.com',150.50);
insert into visitantes values
('Mariana Juarez', 45,'f','San Martin 111',2,null,23.90);
insert into visitantes values
('Fabian Perez',36,'m','Avellaneda 213',3,'fabianperez@xaxamail.com',0);
insert into visitantes values
('Alejandra Garcia',28,'f',null,2,null,280.50);
insert into visitantes values
('Gaston Perez',29,'m',null,5,'gastonperez1@gmail.com',95.40);
insert into visitantes values
('Mariana Juarez',33,'f',null,2,null,90);

select c.nombre,
count(*) as cantidad
from ciudades as c
join visitantes as v
on codigociudad=c.codigo
group by c.nombre;

select c.nombre,sexo,
avg(montocompra) as 'promedio de compra'
from ciudades as c
join visitantes as v
on codigociudad=c.codigo
group by c.nombre,sexo;

select c.nombre,
count(mail) as 'tienen mail'
from ciudades as c
join visitantes as v
on codigociudad=c.codigo
group by c.nombre;

select c.nombre,
max(montocompra)
from visitantes as v
join ciudades as c
on codigociudad=c.codigo
group by c.nombre;

Podemos hacer un "join" con ms 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 librera 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
combinarn; luego debemos hacer coincidir los valores para el enlace con la tabla "editoriales"
enlazndolas por los campos correspondientes. Utilizamos alias para una sentencia ms 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 cdigo de autor no se encuentra en "autores" y cuya
editorial no existe en "editoriales", esto es porque realizamos una combinacin interna.

Podemos combinar varios tipos de join en una misma sentencia:

select titulo,a.nombre,e.nombre
from autores as a
right join libros as l
on codigoautor=a.codigo
left join editoriales as e on codigoeditorial=e.codigo;
En la consulta anterior solicitamos el ttulo, 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 informacin 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".

Primer problema:

Un club dicta clases de distintos deportes. En una tabla llamada "socios" guarda los
datos de los
socios, en una tabla llamada "deportes" la informacin referente a los diferentes
deportes que se
dictan y en una tabla denominada "inscriptos", las inscripciones de los socios a los
distintos
deportes.
Un socio puede inscribirse en varios deportes el mismo ao. Un socio no puede
inscribirse en el
mismo deporte el mismo ao. Distintos socios se inscriben en un mismo deporte en el
mismo ao.
1- Elimine las tablas si existen:
if object_id('socios') is not null
drop table socios;
if object_id('deportes') is not null
drop table deportes;
if object_id('inscriptos') is not null
drop table inscriptos;

2- Cree las tablas con las siguientes estructuras:


create table socios(
documento char(8) not null,
nombre varchar(30),
domicilio varchar(30),
primary key(documento)
);
create table deportes(
codigo tinyint identity,
nombre varchar(20),
profesor varchar(15),
primary key(codigo)
);
create table inscriptos(
documento char(8) not null,
codigodeporte tinyint not null,
anio char(4),
matricula char(1),--'s'=paga, 'n'=impaga
primary key(documento,codigodeporte,anio)
);

3- Ingrese algunos registros en "socios":


insert into socios values('22222222','Ana Acosta','Avellaneda 111');
insert into socios values('23333333','Betina Bustos','Bulnes 222');
insert into socios values('24444444','Carlos Castro','Caseros 333');
insert into socios values('25555555','Daniel Duarte','Dinamarca 44');
4- Ingrese algunos registros en "deportes":
insert into deportes values('basquet','Juan Juarez');
insert into deportes values('futbol','Pedro Perez');
insert into deportes values('natacion','Marina Morales');
insert into deportes values('tenis','Marina Morales');

5- Inscriba a varios socios en el mismo deporte en el mismo ao:


insert into inscriptos values ('22222222',3,'2006','s');
insert into inscriptos values ('23333333',3,'2006','s');
insert into inscriptos values ('24444444',3,'2006','n');

6- Inscriba a un mismo socio en el mismo deporte en distintos aos:


insert into inscriptos values ('22222222',3,'2005','s');
insert into inscriptos values ('22222222',3,'2007','n');

7- Inscriba a un mismo socio en distintos deportes el mismo ao:


insert into inscriptos values ('24444444',1,'2006','s');
insert into inscriptos values ('24444444',2,'2006','s');

8- Ingrese una inscripcin con un cdigo de deporte inexistente y un documento de


socio que no
exista en "socios":
insert into inscriptos values ('26666666',0,'2006','s');

9- Muestre el nombre del socio, el nombre del deporte en que se inscribi y el ao


empleando
diferentes tipos de join.

10- Muestre todos los datos de las inscripciones (excepto los cdigos) incluyendo
aquellas
inscripciones cuyo cdigo 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".

if object_id('socios') is not null


drop table socios;
if object_id('deportes') is not null
drop table deportes;
if object_id('inscriptos') is not null
drop table inscriptos;

create table socios(


documento char(8) not null,
nombre varchar(30),
domicilio varchar(30),
primary key(documento)
);
create table deportes(
codigo tinyint identity,
nombre varchar(20),
profesor varchar(15),
primary key(codigo)
);
create table inscriptos(
documento char(8) not null,
codigodeporte tinyint not null,
anio char(4),
matricula char(1),--'s'=paga, 'n'=impaga
primary key(documento,codigodeporte,anio)
);

insert into socios values('22222222','Ana Acosta','Avellaneda 111');


insert into socios values('23333333','Betina Bustos','Bulnes 222');
insert into socios values('24444444','Carlos Castro','Caseros 333');
insert into socios values('25555555','Daniel Duarte','Dinamarca 44');

insert into deportes values('basquet','Juan Juarez');


insert into deportes values('futbol','Pedro Perez');
insert into deportes values('natacion','Marina Morales');
insert into deportes values('tenis','Marina Morales');

insert into inscriptos values ('22222222',3,'2006','s');


insert into inscriptos values ('23333333',3,'2006','s');
insert into inscriptos values ('24444444',3,'2006','n');

insert into inscriptos values ('22222222',3,'2005','s');


insert into inscriptos values ('22222222',3,'2007','n');

insert into inscriptos values ('24444444',1,'2006','s');


insert into inscriptos values ('24444444',2,'2006','s');

insert into inscriptos values ('26666666',0,'2006','s');

select s.nombre,d.nombre,anio
from deportes as d
right join inscriptos as i
on codigodeporte=d.codigo
left join socios as s
on i.documento=s.documento;

select s.nombre,d.nombre,anio,matricula
from deportes as d
full join inscriptos as i
on codigodeporte=d.codigo
full join socios as s
on s.documento=i.documento;

select s.nombre,d.nombre,anio,matricula
from deportes as d
join inscriptos as i
on codigodeporte=d.codigo
join socios as s
on s.documento=i.documento
where s.documento='22222222';

Las combinaciones no slo se utilizan con la sentencia "select", tambin podemos emplearlas con
"update" y "delete".

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":

update libros set precio=precio+(precio*0.1)


from libros
join editoriales as e
on codigoeditorial=e.codigo
where nombre='Planeta';

Eliminamos todos los libros de editorial "Emece":

delete libros
from libros
join editoriales
on codigoeditorial = editoriales.codigo
where editoriales.nombre='Emece';

Problema:

Una librera almacena la informacin de sus libros para la venta en dos tablas, "libros" y
"editoriales".
Eliminamos ambas tablas, si existen:

if object_id('libros') is not null


drop table libros;
if object_id('editoriales') is not null
drop table editoriales;
Creamos las tablas:

create table libros(


codigo int identity,
titulo varchar(40),
autor varchar(30) default 'Desconocido',
codigoeditorial tinyint not null,
precio decimal(5,2)
);
create table editoriales(
codigo tinyint identity,
nombre varchar(20),
primary key (codigo)
);

Ingresamos algunos registros en ambas tablas:

insert into editoriales values('Planeta');


insert into editoriales values('Emece');
insert into editoriales values('Siglo XXI');

insert into libros values('El aleph','Borges',2,20);


insert into libros values('Martin Fierro','Jose Hernandez',1,30);
insert into libros values('Aprenda PHP','Mario Molina',3,50);
insert into libros values('Java en 10 minutos',default,3,45);

Aumentamos en un 10% los precios de los libros de editorial "Planeta":

update libros set precio=precio+(precio*0.1)


from libros
join editoriales as e
on codigoeditorial=e.codigo
where nombre='Planeta';

Veamos el resultado:

select titulo,autor,e.nombre,precio
from libros as l
join editoriales as e
on codigoeditorial=e.codigo;

Eliminamos todos los libros de editorial "Emece":

delete libros
from libros
join editoriales
on codigoeditorial = editoriales.codigo
where editoriales.nombre='Emece';

Veamos si se eliminaron:

select titulo,autor,e.nombre,precio
from libros as l
join editoriales as e
on codigoeditorial=e.codigo;

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 fornea, externa o ajena.

En el ejemplo de la librera en que utilizamos las tablas "libros" y "editoriales" con estos campos:

libros: codigo (clave primaria), titulo, autor, codigoeditorial, precio


y
editoriales: codigo (clave primaria), nombre.

el campo "codigoeditorial" de "libros" es una clave fornea, se emplea para enlazar la tabla
"libros" con "editoriales" y es clave primaria en "editoriales" con el nombre "codigo".

Las claves forneas 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 forneas. Si modificamos el
tipo, longitud o atributos de una clave fornea, sta puede quedar inhabilitada para hacer los
enlaces.

Entonces, una clave fornea 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.

Hemos visto que una de las alternativas que SQL Server ofrece para asegurar la integridad de
datos es el uso de restricciones (constraints). Aprendimos que las restricciones se establecen en
tablas y campos asegurando que los datos sean vlidos y que las relaciones entre las tablas se
mantengan; vimos que existen distintos tipos de restricciones:

1) de los campos: default y check


2) de la tabla: primary key y unique.
3) referencial: foreign key, la analizaremos ahora.

Con la restriccin "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
restriccin "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 cdigo de editorial en la tabla "libros", tal
cdigo exista en la tabla "editoriales".

Tambin 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 cdigo de "editoriales" si existen libros con dicho cdigo.

La siguiente es la sintaxis parcial general para agregar una restriccin "foreign key":

alter table NOMBRETABLA1


add constraint NOMBRERESTRICCION
foreign key (CAMPOCLAVEFORANEA)
references NOMBRETABLA2 (CAMPOCLAVEPRIMARIA);
Analicmosla:

- NOMBRETABLA1 referencia el nombre de la tabla a la cual le aplicamos la restriccin,

- NOMBRERESTRICCION es el nombre que le damos a la misma,

- luego de "foreign key", entre parntesis se coloca el campo de la tabla a la que le aplicamos la
restriccin que ser establecida como clave fornea,

- luego de "references" indicamos el nombre de la tabla referenciada y el campo que es clave


primaria en la misma, a la cual hace referencia la clave fornea. La tabla referenciada debe
tener definida una restriccin "primary key" o "unique"; si no la tiene, aparece un mensaje de
error.

Para agregar una restriccin "foreign key" al campo "codigoeditorial" de "libros", tipeamos:

alter table libros


add constraint FK_libros_codigoeditorial
foreign key (codigoeditorial)
references editoriales(codigo);

En el ejemplo implementamos una restriccin "foreign key" para asegurarnos que el cdigo de la
editorial de la de la tabla "libros" ("codigoeditorial") est asociada con un cdigo vlido en la
tabla "editoriales" ("codigo").

Cuando agregamos cualquier restriccin a una tabla que contiene informacin, SQL Server
controla los datos existentes para confirmar que cumplen con la restriccin, si no los cumple, la
restriccin no se aplica y aparece un mensaje de error. Por ejemplo, si intentamos agregar una
restriccin "foreign key" a la tabla "libros" y existe un libro con un valor de cdigo para editorial
que no existe en la tabla "editoriales", la restriccin no se agrega.

Acta en inserciones. Si intentamos ingresar un registro (un libro) con un valor de clave fornea
(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
fornea (codigoeditorial), almacenar "null", porque esta restriccin permite valores nulos (a
menos que se haya especificado lo contrario al definir el campo).

Acta en eliminaciones y actualizaciones. Si intentamos eliminar un registro o modificar un valor


de clave primaria de una tabla si una clave fornea hace referencia a dicho registro, SQL Server
no lo permite (excepto si se permite la accin 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.

Esta restriccin (a diferencia de "primary key" y "unique") no crea ndice automaticamente.

La cantidad y tipo de datos de los campos especificados luego de "foreign key" DEBEN coincidir
con la cantidad y tipo de datos de los campos de la clusula "references".

Esta restriccin se puede definir dentro de la misma tabla (lo veremos ms adelante) o entre
distintas tablas.

Una tabla puede tener varias restricciones "foreign key".


No se puede eliminar una tabla referenciada en una restriccin "foreign key", aparece un mensaje
de error.

Una restriccion "foreign key" no puede modificarse, debe eliminarse y volverse a crear.

Para ver informacin acerca de esta restriccin podemos ejecutar el procedimiento almacenado
"sp_helpconstraint" junto al nombre de la tabla. Nos muestra el tipo, nombre, la opcin para
eliminaciones y actualizaciones, el estado (temas que veremos ms adelante), el nombre del
campo y la tabla y campo que referencia.

Tambin informa si la tabla es referenciada por una clave fornea.

Primer problema:

Una empresa tiene registrados sus clientes en una tabla llamada "clientes", tambin
tiene una tabla
"provincias" donde registra los nombres de las provincias.
1- Elimine las tablas "clientes" y "provincias", si existen y crelas:
if object_id('clientes') is not null
drop table clientes;
if object_id('provincias') is not null
drop table provincias;

create table clientes (


codigo int identity,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia tinyint
);

create table provincias(


codigo tinyint not null,
nombre varchar(20)
);

En este ejemplo, el campo "codigoprovincia" de "clientes" es una clave fornea, se


emplea para
enlazar la tabla "clientes" con "provincias".

2- Intente agregar una restriccin "foreign key" a la tabla "clientes" que haga
referencia al campo
"codigo" de "provincias":
alter table clientes
add constraint FK_clientes_codigoprovincia
foreign key (codigoprovincia)
references provincias(codigo);
No se puede porque "provincias" no tiene restriccin "primary key" ni "unique".

3- Establezca una restriccin "primary key" al campo "codigo" de "provincias":


alter table provincias
add constraint PK_provincias_codigo
primary key (codigo);

4- Ingrese algunos registros para ambas tablas:


insert into provincias values(1,'Cordoba');
insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Misiones');
insert into provincias values(4,'Rio Negro');

insert into clientes values('Perez Juan','San Martin 123','Carlos Paz',1);


insert into clientes values('Moreno Marcos','Colon 234','Rosario',2);
insert into clientes values('Acosta Ana','Avellaneda 333','Posadas',3);
insert into clientes values('Luisa Lopez','Juarez 555','La Plata',6);

5- Intente agregar la restriccin "foreign key" del punto 2 a la tabla "clientes":


alter table clientes
add constraint FK_clientes_codigoprovincia
foreign key (codigoprovincia)
references provincias(codigo);
No se puede porque hay un registro en "clientes" cuyo valor de "codigoprovincia" no
existe en
"provincias".
6- Elimine el registro de "clientes" que no cumple con la restriccin y establezca la
restriccin
nuevamente:
delete from clientes where codigoprovincia=6;
alter table clientes
add constraint FK_clientes_codigoprovincia
foreign key (codigoprovincia)
references provincias(codigo);

7- Intente agregar un cliente con un cdigo de provincia inexistente en "provincias".


No se puede.

8- Intente eliminar el registro con cdigo 3, de "provincias".


No se puede porque hay registros en "clientes" al cual hace referencia.

9- Elimine el registro con cdigo "4" de "provincias".


Se permite porque en "clientes" ningn registro hace referencia a l.

10- Intente modificar el registro con cdigo 1, de "provincias".


No se puede porque hay registros en "clientes" al cual hace referencia.

11- Vea las restricciones de "clientes".


aparece la restriccin "foreign key".

12- Vea las restricciones de "provincias".


aparece la restriccin "primary key" y nos informa que la tabla es rerenciada por una
"foreign key"
de la tabla "clientes" llamada "FK_clientes_codigoprovincia".
if object_id('clientes') is not null
drop table clientes;
if object_id('provincias') is not null
drop table provincias;

create table clientes (


codigo int identity,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia tinyint
);

create table provincias(


codigo tinyint not null,
nombre varchar(20)
);

alter table clientes


add constraint FK_clientes_codigoprovincia
foreign key (codigoprovincia)
references provincias(codigo);

alter table provincias


add constraint PK_provincias_codigo
primary key (codigo);

insert into provincias values(1,'Cordoba');


insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Misiones');
insert into provincias values(4,'Rio Negro');

insert into clientes values('Perez Juan','San Martin 123','Carlos Paz',1);


insert into clientes values('Moreno Marcos','Colon 234','Rosario',2);
insert into clientes values('Acosta Ana','Avellaneda 333','Posadas',3);
insert into clientes values('Luisa Lopez','Juarez 555','La Plata',6);

alter table clientes


add constraint FK_clientes_codigoprovincia
foreign key (codigoprovincia)
references provincias(codigo);

delete from clientes where codigoprovincia=6;


alter table clientes
add constraint FK_clientes_codigoprovincia
foreign key (codigoprovincia)
references provincias(codigo);

insert into clientes values('Garcia Marcos','Colon 877','Lules',9);

delete from provincias where codigo=3;

delete from provincias where codigo=4;


update provincias set codigo=7 where codigo=1;

sp_helpconstraint clientes;

sp_helpconstraint provincias;

La restriccin "foreign key", que define una referencia a un campo con una restriccin "primary
key" o "unique" se puede definir entre distintas tablas (como hemos aprendido) o dentro de la
misma tabla.

Veamos un ejemplo en el cual definimos esta restriccin dentro de la misma tabla.

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.

La estructura de la tabla es la siguiente:

create table afiliados(


numero int identity not null,
documento char(8) not null,
nombre varchar(30),
afiliadotitular int,
primary key (documento),
unique (numero)
);

En caso que un afiliado no haya sido incorporado a la mutual por otro afiliado, el campo
"afiliadotitular" almacenar "null".

Establecemos una restriccin "foreign key" para asegurarnos que el nmero de afiliado que se
ingrese en el campo "afiliadotitular" exista en la tabla "afiliados":

alter table afiliados


add constraint FK_afiliados_afiliadotitular
foreign key (afiliadotitular)
references afiliados (numero);

La sintaxis es la misma, excepto que la tabla se autoreferencia.

Luego de aplicar esta restriccin, cada vez que se ingrese un valor en el campo "afiliadotitular",
SQL Server controlar que dicho nmero 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 accin en cascada (prximo tema).

Primer problema:
Una empresa registra los datos de sus clientes en una tabla llamada "clientes". Dicha
tabla contiene
un campo que hace referencia al cliente que lo recomend denominado
"referenciadopor". Si un cliente
no ha sido referenciado por ningn otro cliente, tal campo almacena "null".
1- Elimine la tabla si existe y crela:
if object_id('clientes') is not null
drop table clientes;
create table clientes(
codigo int not null,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
referenciadopor int,
primary key(codigo)
);

2- Ingresamos algunos registros:


insert into clientes values (50,'Juan Perez','Sucre 123','Cordoba',null);
insert into clientes values(90,'Marta Juarez','Colon 345','Carlos Paz',null);
insert into clientes values(110,'Fabian Torres','San Martin 987','Cordoba',50);
insert into clientes values(125,'Susana Garcia','Colon 122','Carlos Paz',90);
insert into clientes values(140,'Ana Herrero','Colon 890','Carlos Paz',9);

3- Intente agregar una restriccin "foreign key" para evitar que en el campo
"referenciadopor" se
ingrese un valor de cdigo de cliente que no exista.
No se permite porque existe un registro que no cumple con la restriccin que se
intenta establecer.

4- Cambie el valor invlido de "referenciadopor" del registro que viola la restriccin por
uno
vlido.

5- Agregue la restriccin "foreign key" que intent agregar en el punto 3.

6- Vea la informacin referente a las restricciones de la tabla "clientes".

7- Intente agregar un registro que infrinja la restriccin.


No lo permite.

8- Intente modificar el cdigo de un cliente que est referenciado en "referenciadopor".


No se puede.

9- Intente eliminar un cliente que sea referenciado por otro en "referenciadopor".


No se puede.

10- Cambie el valor de cdigo de un cliente que no referenci a nadie.

11- Elimine un cliente que no haya referenciado a otros.

if object_id('clientes') is not null


drop table clientes;

create table clientes(


codigo int not null,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
referenciadopor int,
primary key(codigo)
);

insert into clientes values (50,'Juan Perez','Sucre 123','Cordoba',null);


insert into clientes values(90,'Marta Juarez','Colon 345','Carlos Paz',null);
insert into clientes values(110,'Fabian Torres','San Martin 987','Cordoba',50);
insert into clientes values(125,'Susana Garcia','Colon 122','Carlos Paz',90);
insert into clientes values(140,'Ana Herrero','Colon 890','Carlos Paz',9);

alter table clientes


add constraint FK_clientes_referenciadopor
foreign key (referenciadopor)
references clientes (codigo);

update clientes set referenciadopor=90 where referenciadopor=9;

alter table clientes


add constraint FK_clientes_referenciadopor
foreign key (referenciadopor)
references clientes (codigo);

sp_helpconstraint clientes;

insert into clientes values(150,'Karina Gomez','Caseros 444','Cruz del Eje',8);

update clientes set codigo=180 where codigo=90;

delete from clientes where nombre='Marta Juarez';

update clientes set codigo=180 where codigo=125;

delete from clientes where codigo=110;

Continuamos con la restriccin "foreign key".

Si intentamos eliminar un registro de la tabla referenciada por una restriccin "foreign key" cuyo
valor de clave primaria existe referenciada en la tabla que tiene dicha restriccin, la accin no se
ejecuta y aparece un mensaje de error. Esto sucede porque, por defecto, para eliminaciones, la
opcin de la restriccin "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 restriccin "foreign key" tiene las clusulas "on delete" y "on update" que son opcionales.
Estas clusulas especifican cmo debe actuar SQL Server frente a eliminaciones y modificaciones
de las tablas referenciadas en la restriccin.
Las opciones para estas clusulas 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 accin no se realice; es la opcin predeterminada.

- "cascade": indica que si eliminamos o actualizamos un valor de la clave primaria en la tabla


referenciada (TABLA2), los registros coincidentes en la tabla principal (TABLA1), tambin se
eliminen o modifiquen; es decir, si eliminamos o modificamos un valor de campo definido con una
restriccin "primary key" o "unique", dicho cambio se extiende al valor de clave externa de la otra
tabla (integridad referencial en cascada).

La sintaxis completa para agregar esta restriccin a una tabla es la siguiente:

alter table TABLA1


add constraint NOMBRERESTRICCION
foreign key (CAMPOCLAVEFORANEA)
references TABLA2(CAMPOCLAVEPRIMARIA)
on delete OPCION
on update OPCION;

Sintetizando, si al agregar una restriccin foreign key:

- no se especifica accin para eliminaciones (o se especifica "no_action"), y se intenta eliminar un


registro de la tabla referenciada (editoriales) cuyo valor de clave primaria (codigo) existe en la
tabla principal (libros), la accin no se realiza.

- se especifica "cascade" para eliminaciones ("on delete cascade") y elimina un registro de la tabla
referenciada (editoriales) cuyo valor de clave primaria (codigo) existe en la tabla
principal(libros), la eliminacin de la tabla referenciada (editoriales) se realiza y se eliminan de
la tabla principal (libros) todos los registros cuyo valor coincide con el registro eliminado de la
tabla referenciada (editoriales).

- no se especifica accin para actualizaciones (o se especifica "no_action"), y se intenta modificar


un valor de clave primaria (codigo) de la tabla referenciada (editoriales) que existe en el campo
clave fornea (codigoeditorial) de la tabla principal (libros), la accin no se realiza.

- se especifica "cascade" para actualizaciones ("on update cascade") y se modifica un valor de


clave primaria (codigo) de la tabla referenciada (editoriales) que existe en la tabla principal
(libros), SQL Server actualiza el registro de la tabla referenciada (editoriales) y todos los registros
coincidentes en la tabla principal (libros).

Veamos un ejemplo. Definimos una restriccin "foreign key" a la tabla "libros" estableciendo el
campo "codigoeditorial" como clave fornea que referencia al campo "codigo" de la tabla
"editoriales". La tabla "editoriales" tiene como clave primaria el campo "codigo". Especificamos la
accin en cascada para las actualizaciones y eliminaciones:

alter table libros


add constraint FK_libros_codigoeditorial
foreign key (codigoeditorial)
references editoriales(codigo)
on update cascade
on delete cascade;

Si luego de establecer la restriccin anterior, eliminamos una editorial de "editoriales" de las


cuales hay libros, se elimina dicha editorial y todos los libros de tal editorial. Y si modificamos el
valor de cdigo de una editorial de "editoriales", se modifica en "editoriales" y todos los valores
iguales de "codigoeditorial" de libros tambin se modifican.

Primer problema:

Una empresa tiene registrados sus clientes en una tabla llamada "clientes", tambin
tiene una tabla
"provincias" donde registra los nombres de las provincias.
1- Elimine las tablas "clientes" y "provincias", si existen:
if object_id('clientes') is not null
drop table clientes;
if object_id('provincias') is not null
drop table provincias;

2- Crelas con las siguientes estructuras:


create table clientes (
codigo int identity,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia tinyint,
primary key(codigo)
);

create table provincias(


codigo tinyint,
nombre varchar(20),
primary key (codigo)
);

3- Ingrese algunos registros para ambas tablas:


insert into provincias values(1,'Cordoba');
insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Misiones');
insert into provincias values(4,'Rio Negro');

insert into clientes values('Perez Juan','San Martin 123','Carlos Paz',1);


insert into clientes values('Moreno Marcos','Colon 234','Rosario',2);
insert into clientes values('Acosta Ana','Avellaneda 333','Posadas',3);

4- Establezca una restriccin "foreign key" especificando la accin "en cascade" para
actualizaciones y "no_action" para eliminaciones.

5- Intente eliminar el registro con cdigo 3, de "provincias".


No se puede porque hay registros en "clientes" al cual hace referencia y la opcin para
eliminaciones se estableci como "no action".
6- Modifique el registro con cdigo 3, de "provincias".

7- Verifique que el cambio se realiz en cascada, es decir, que se modific en la tabla


"provincias"
y en "clientes":
select *from provincias;
select *from clientes;

8- Intente modificar la restriccin "foreign key" para que permita eliminacin en


cascada.
Mensaje de error, no se pueden modificar las restricciones.

9- Intente eliminar la tabla "provincias".


No se puede eliminar porque una restriccin "foreign key" hace referencia a ella.

if object_id('clientes') is not null


drop table clientes;
if object_id('provincias') is not null
drop table provincias;

create table clientes (


codigo int identity,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia tinyint,
primary key(codigo)
);

create table provincias(


codigo tinyint,
nombre varchar(20),
primary key (codigo)
);

insert into provincias values(1,'Cordoba');


insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Misiones');
insert into provincias values(4,'Rio Negro');

insert into clientes values('Perez Juan','San Martin 123','Carlos Paz',1);


insert into clientes values('Moreno Marcos','Colon 234','Rosario',2);
insert into clientes values('Acosta Ana','Avellaneda 333','Posadas',3);

alter table clientes


add constraint FK_clientes_codigoprovincia
foreign key (codigoprovincia)
references provincias(codigo)
on update cascade
on delete no action;

delete from provincias where codigo=3;


update provincias set codigo=9 where codigo=3;

select *from provincias;


select *from clientes;

alter table clientes


add constraint FK_clientes_codigoprovincia
foreign key (codigoprovincia)
references provincias(codigo)
on update cascade,
on delete cascade;

drop table provincias;

Restricciones foreign key deshabilitar y eliminar (with check - nocheck)

Sabemos que si agregamos una restriccin a una tabla que contiene datos, SQL Server los controla
para asegurarse que cumplen con la restriccin; es posible deshabilitar esta comprobacin.

Podemos hacerlo al momento de agregar la restriccin a una tabla con datos, incluyendo la
opcin "with nocheck" en la instruccin "alter table"; si se emplea esta opcin, los datos no van a
cumplir la restriccin.

Se pueden deshabilitar las restricciones "check" y "foreign key", a las dems se las debe eliminar.

La sintaxis bsica al agregar la restricccin "foreign key" es la siguiente:

alter table NOMBRETABLA1


with OPCIONDECHEQUEO
add constraint NOMBRECONSTRAINT
foreign key (CAMPOCLAVEFORANEA)
references NOMBRETABLA2 (CAMPOCLAVEPRIMARIA)
on update OPCION
on delete OPCION;

La opcin "with OPCIONDECHEQUEO" especifica si se controlan los datos existentes o no con


"check" y "nocheck" respectivamente. Por defecto, si no se especifica, la opcin es "check".

En el siguiente ejemplo agregamos una restriccin "foreign key" que controla que todos los
cdigos de editorial tengan un cdigo vlido, es decir, dicho cdigo exista en "editoriales". La
restriccin no se aplica en los datos existentes pero si en los siguientes ingresos, modificaciones y
actualizaciones:

alter table libros


with nocheck
add constraint FK_libros_codigoeditorial
foreing key (codigoeditorial)
references editoriales(codigo);
La comprobacin de restricciones se puede deshabilitar para modificar, eliminar o agregar datos
a una tabla sin comprobar la restriccin. La sintaxis general es:

alter table NOMBRETABLA


OPCIONDECHEQUEO constraint NOMBRERESTRICCION;

En el siguiente ejemplo deshabilitamos la restriccin creada anteriormente:

alter table libros


nocheck constraint FK_libros_codigoeditorial;

Para habilitar una restriccin deshabilitada se ejecuta la misma instruccin pero con la clusula
"check" o "check all":

alter table libros


check constraint FK_libros_codigoeditorial;

Si se emplea "check constraint all" no se coloca nombre de restricciones, habilita todas las
restricciones que tiene la tabla nombrada ("check" y "foreign key").

Para saber si una restriccin est habilitada o no, podemos ejecutar el procedimiento
almacenado "sp_helpconstraint" y entenderemos lo que informa la columna "status_enabled".

Entonces, las clusulas "check" y "nocheck" permiten habilitar o deshabilitar restricciones "foreign
key" (y "check"). Pueden emplearse para evitar la comprobacin de datos existentes al crear la
restriccin o para deshabilitar la comprobacin de datos al ingresar, actualizar y eliminar algn
registro que infrinja la restriccin.

Podemos eliminar una restriccin "foreign key" con "alter table". La sintaxis bsica es la misma
que para cualquier otra restriccin:

alter table TABLA


drop constraint NOMBRERESTRICCION;

Eliminamos la restriccin de "libros":

alter table libros


drop constraint FK_libros_codigoeditorial;

No se puede eliminar una tabla si una restriccin "foreign key" hace referencia a ella.

Cuando eliminamos una tabla que tiene una restriccin "foreign key", la restriccin tambin se
elimina.

Primer problema:

Una empresa tiene registrados sus clientes en una tabla llamada "clientes", tambin
tiene una tabla
"provincias" donde registra los nombres de las provincias.
1- Elimine las tablas "clientes" y "provincias", si existen:
if object_id('clientes') is not null
drop table clientes;
if object_id('provincias') is not null
drop table provincias;

2- Crelas con las siguientes estructuras:


create table clientes (
codigo int identity,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia tinyint,
primary key(codigo)
);

create table provincias(


codigo tinyint,
nombre varchar(20),
primary key (codigo)
);

3- Ingrese algunos registros para ambas tablas:


insert into provincias values(1,'Cordoba');
insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Misiones');
insert into provincias values(4,'Rio Negro');

insert into clientes values('Perez Juan','San Martin 123','Carlos Paz',1);


insert into clientes values('Moreno Marcos','Colon 234','Rosario',2);
insert into clientes values('Garcia Juan','Sucre 345','Cordoba',1);
insert into clientes values('Lopez Susana','Caseros 998','Posadas',3);
insert into clientes values('Marcelo Moreno','Peru 876','Viedma',4);
insert into clientes values('Lopez Sergio','Avellaneda 333','La Plata',5);

4- Intente agregar una restriccin "foreign key" para que los cdigos de provincia de
"clientes"
existan en "provincias" con accin en cascada para actualizaciones y eliminaciones, sin
especificar
la opcin de comprobacin 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 opcin para la comprobacin de datos, por
defecto es "check" y
hay un registro que no cumple con la restriccin.

5- Agregue la restriccin anterior pero deshabilitando la comprobacin 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;

6- Vea las restricciones de "clientes":


sp_helpconstraint clientes;
Aparece la restriccin "primary key" y "foreign key", las columnas "delete_action" y
"update_action"
contienen "cascade" y la columna "status_enabled" contiene "Enabled".

7- Vea las restricciones de "provincias":


sp_helpconstraint provincias;
Aparece la restriccin "primary key" y la referencia a esta tabla de la restriccin
"foreign key" de
la tabla "clientes.

8- Deshabilite la restriccin "foreign key" de "clientes":


alter table clientes
nocheck constraint FK_clientes_codigoprovincia;

9- Vea las restricciones de "clientes":


sp_helpconstraint clientes;
la restriccin "foreign key" aparece inhabilitada.

10- Vea las restricciones de "provincias":


sp_helpconstraint provincias;
informa que la restriccin "foreign key" de "clientes" hace referencia a ella, an cuando
est
deshabilitada.

11- Agregue un registro que no cumpla la restriccin "foreign key":


insert into clientes values('Garcia Omar','San Martin 100','La Pampa',6);
Se permite porque la restriccin est deshabilitada.

12- Elimine una provincia de las cuales haya clientes:


delete from provincias where codigo=2;

13- Corrobore que el registro se elimin de "provincias" pero no se extendi a


"clientes":
select *from clientes;
select *from provincias;

14- Modifique un cdigo de provincia de la cual haya clientes:


update provincias set codigo=9 where codigo=3;

15- Verifique que el cambio se realiz en "provincias" pero no se extendi a "clientes":


select *from clientes;
select *from provincias;

16- Intente eliminar la tabla "provincias":


drop table provincias;
No se puede porque la restriccin "FK_clientes_codigoprovincia" la referencia, aunque
est deshabilitada.
17- Habilite la restriccin "foreign key":
alter table clientes
check constraint FK_clientes_codigoprovincia;

18- Intente agregar un cliente con cdigo de provincia inexistente en "provincias":


insert into clientes values('Hector Luduea','Paso 123','La Plata',8);
No se puede.

19- Modifique un cdigo de provincia al cual se haga referencia en "clientes":


update provincias set codigo=20 where codigo=4;
Actualizacin en cascada.

20- Vea que se modificaron en ambas tablas:


select *from clientes;
select *from provincias;

21- Elimine una provincia de la cual haya referencia en "clientes":


delete from provincias where codigo=1;
Accin en cascada.

22- Vea que los registros de ambas tablas se eliminaron:


select *from clientes;
select *from provincias;

23- Elimine la restriccion "foreign key":


alter table clientes
drop constraint FK_clientes_codigoprovincia;

24- Vea las restriciones de la tabla "provincias":


sp_helpconstraint provincias;
Solamente aparece la restriccin "primary key", ya no hay una "foreign key" que la
referencie.

25- Elimine la tabla "provincias":


drop table provincias;
Puede eliminarse porque no hay restriccin "foreign key" que la referencie.

if object_id('clientes') is not null


drop table clientes;
if object_id('provincias') is not null
drop table provincias;

create table clientes (


codigo int identity,
nombre varchar(30),
domicilio varchar(30),
ciudad varchar(20),
codigoprovincia tinyint,
primary key(codigo)
);
create table provincias(
codigo tinyint,
nombre varchar(20),
primary key (codigo)
);

insert into provincias values(1,'Cordoba');


insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Misiones');
insert into provincias values(4,'Rio Negro');

insert into clientes values('Perez Juan','San Martin 123','Carlos Paz',1);


insert into clientes values('Moreno Marcos','Colon 234','Rosario',2);
insert into clientes values('Garcia Juan','Sucre 345','Cordoba',1);
insert into clientes values('Lopez Susana','Caseros 998','Posadas',3);
insert into clientes values('Marcelo Moreno','Peru 876','Viedma',4);
insert into clientes values('Lopez Sergio','Avellaneda 333','La Plata',5);

alter table clientes


add constraint FK_clientes_codigoprovincia
foreign key (codigoprovincia)
references provincias(codigo)
on update cascade
on delete cascade;

alter table clientes


with nocheck
add constraint FK_clientes_codigoprovincia
foreign key (codigoprovincia)
references provincias(codigo)
on update cascade
on delete cascade;

sp_helpconstraint clientes;

sp_helpconstraint provincias;

alter table clientes


nocheck constraint FK_clientes_codigoprovincia;

sp_helpconstraint clientes;

sp_helpconstraint provincias;

insert into clientes values('Garcia Omar','San Martin 100','La Pampa',6);

delete from provincias where codigo=2;

select *from clientes;


select *from provincias;

update provincias set codigo=9 where codigo=3;


select *from clientes;
select *from provincias;

drop table provincias;

alter table clientes


check constraint FK_clientes_codigoprovincia;

insert into clientes values('Hector Luduea','Paso 123','La Plata',8);

update provincias set codigo=20 where codigo=4;

select *from clientes;


select *from provincias;

delete from provincias where codigo=1;

select *from clientes;


select *from provincias;

alter table clientes


drop constraint FK_clientes_codigoprovincia;

sp_helpconstraint provincias;

drop table provincias;

El procedimiento almacenado "sp_helpconstraint" devuelve las siguientes columnas:

- constraint_type: tipo de restriccin. Si es una restriccin de campo (default o check) indica


sobre qu campo fue establecida. Si es de tabla (primary key o unique) indica el tipo de ndice
creado. Si es una "foreign key" lo indica.

- constraint_name: nombre de la restriccin.

- delete_action: solamente es aplicable para restricciones de tipo "foreign key". Indica si la


accin de eliminacin acta, no acta o es en cascada. Indica "n/a" en cualquier restriccin para
la que no se aplique; "No Action" si no acta y "Cascade" si es en cascada.

- update_action: slo es aplicable para restricciones de tipo "foreign key". Indica si la accin de
actualizacin es: No Action, Cascade, or n/a. Indica "n/a" en cualquier restriccin para la que no
se aplique.

- status_enabled: solamente es aplicable para restricciones de tipo "check" y "foreign key". Indica
si est habilitada (Enabled) o no (Disabled). Indica "n/a" en cualquier restriccin para la que no se
aplique.

- status_for_replication: solamente es aplicable para restricciones de tipo "check" y "foreign key".


Indica "n/a" en cualquier restriccin para la que no se aplique.
- constraint_keys: Si es una restriccin "default" muestra la condicin de chequeo; si es una
restriccin "default", el valor por defecto; si es una "primary key", "unique" o "foreign key"
muestra el/ los campos a los que se aplicaron la restriccin. En caso de valores predeterminados
y reglas, el texto que lo define.

81 - Restricciones al crear la tabla

Hasta el momento hemos agregado restricciones a tablas existentes con "alter table" (manera
aconsejada), tambin pueden establecerse al momento de crear una tabla (en la instruccin
"create table").

Podemos aplicar restricciones a nivel de campo (restriccin de campo) o a nivel de tabla


(restriccin de tabla).

En el siguiente ejemplo creamos la tabla "libros" con varias restricciones:

create table libros(


codigo int identity,
titulo varchar(40),
codigoautor int not null,
codigoeditorial tinyint not null,
precio decimal(5,2)
constraint DF_precio default (0),
constraint PK_libros_codigo
primary key clustered (codigo),
constraint UQ_libros_tituloautor
unique (titulo,codigoautor),
constraint FK_libros_editorial
foreign key (codigoeditorial)
references editoriales(codigo)
on update cascade,
constraint FK_libros_autores
foreign key (codigoautor)
references autores(codigo)
on update cascade,
constraint CK_precio_positivo check (precio>=0)
);

En el ejemplo anterior creamos:

- una restriccin "default" para el campo "precio" (restriccin a nivel de campo);

- una restriccin "primary key" con ndice agrupado para el campo "codigo" (a nivel de tabla);

- una restriccin "unique" con ndice no agrupado (por defecto) para los campos "titulo" y
"codigoautor" (a nivel de tabla);

- una restriccin "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 restriccin "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 restriccin "check" para el campo "precio" que no admita valores negativos;

Si definimos una restriccin "foreign key" al crear una tabla, la tabla referenciada debe existir.

Primer problema:

Un club de barrio tiene en su sistema 4 tablas:


- "socios": en la cual almacena documento, nmero, nombre y domicilio de cada socio;
- "deportes": que guarda un cdigo, nombre del deporte, da de la semana que se
dicta y documento
del profesor instructor;
- "profesores": donde se guarda el documento, nombre y domicilio de los profesores e
- "inscriptos": que almacena el nmero de socio, el cdigo de deporte y si la matricula
est paga o
no.
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('profesores') is not null
drop table profesores;
if object_id('deportes') is not null
drop table deportes;

2- Considere que:
- un socio puede inscribirse en varios deportes, pero no dos veces en el mismo.
- un socio tiene un documento nico y un nmero de socio nico.
- el documento del socio debe contener 8 dgitos.
- un deporte debe tener asignado un profesor que exista en "profesores" o "null" si an
no tiene un
instructor definido.
- el campo "dia" de "deportes" puede ser: lunes, martes, miercoles, jueves, viernes o
sabado.
- el campo "dia" de "deportes" por defecto debe almacenar 'sabado'.
- un profesor puede ser instructor de varios deportes o puede no dictar ningn
deporte.
- un profesor no puede estar repetido en "profesores".
- el documento del profesor debe contener 8 dgitos.
- un inscripto debe ser socio, un socio puede no estar inscripto en ningn deporte.
- una inscripcin debe tener un valor en socio existente en "socios" y un deporte que
exista en
"deportes".
- el campo "matricula" de "inscriptos" debe aceptar solamente los caracteres 's' o 'n'.

3- Cree las tablas con las restricciones necesarias:


create table profesores(
documento char(8) not null,
nombre varchar(30),
domicilio varchar(30),
constraint CK_profesores_documento_patron check (documento like '[0-9][0-9][0-
9][0-9][0-9][0-9][0-9][0-9]'),
constraint PK_profesores_documento
primary key (documento)
);

create table deportes(


codigo tinyint identity,
nombre varchar(20) not null,
dia varchar(30)
constraint DF_deportes_dia default('sabado'),
profesor char(8),--documento del profesor
constraint CK_deportes_dia_lista check (dia in
('lunes','martes','miercoles','jueves','viernes','sabado')),
constraint PK_deportes_codigo
primary key (codigo)
);

create table socios(


numero int identity,
documento char(8),
nombre varchar(30),
domicilio varchar(30),
constraint CK_documento_patron check (documento like '[0-9][0-9][0-9][0-9][0-
9][0-9][0-9][0-9]'),
constraint PK_socios_numero
primary key nonclustered(numero),
constraint UQ_socios_documento
unique clustered(documento)
);

create table inscriptos(


numerosocio int not null,
codigodeporte tinyint,
matricula char(1),
constraint PK_inscriptos_numerodeporte
primary key clustered (numerosocio,codigodeporte),
constraint FK_inscriptos_deporte
foreign key (codigodeporte)
references deportes(codigo)
on update cascade,
constraint FK_inscriptos_socios
foreign key (numerosocio)
references socios(numero)
on update cascade
on delete cascade,
constraint CK_matricula_valores check (matricula in ('s','n'))
);

4- Ingrese registros en "profesores":


insert into profesores values('21111111','Andres Acosta','Avellaneda 111');
insert into profesores values('22222222','Betina Bustos','Bulnes 222');
insert into profesores values('23333333','Carlos Caseros','Colon 333');

5- Ingrese registros en "deportes". Ingrese el mismo da para distintos deportes, un


deporte sin da
confirmado, un deporte sin profesor definido:
insert into deportes values('basquet','lunes',null);
insert into deportes values('futbol','lunes','23333333');
insert into deportes values('natacion',null,'22222222');
insert into deportes values('padle',default,'23333333');
insert into deportes (nombre,dia) values('tenis','jueves');

6- Ingrese registros en "socios":


insert into socios values('30111111','Ana Acosta','America 111');
insert into socios values('30222222','Bernardo Bueno','Bolivia 222');
insert into socios values('30333333','Camila Conte','Caseros 333');
insert into socios values('30444444','Daniel Duarte','Dinamarca 444');

7- Ingrese registros en "inscriptos". Inscriba a un socio en distintos deportes, inscriba


varios
socios en el mismo deporte.
insert into inscriptos values(1,3,'s');
insert into inscriptos values(1,5,'s');
insert into inscriptos values(2,1,'s');
insert into inscriptos values(4,1,'n');
insert into inscriptos values(4,4,'s');

8- Realice un "join" (del tipo que sea necesario) para mostrar todos los datos del socio
junto con
el nombre de los deportes en los cuales est inscripto, el da que tiene que asistir y el
nombre del
profesor que lo instruir.
5 registros.

9- Realice la misma consulta anterior pero incluya los socios que no estn inscriptos en
ningn
deporte.
6 registros.

10- Muestre todos los datos de los profesores, incluido el deporte que dicta y el da,
incluyendo
los profesores que no tienen asignado ningn deporte.
4 registros.

11- Muestre todos los deportes y la cantidad de inscriptos, incluyendo aquellos


deportes para los
cuales no hay inscriptos.
5 registros.

12- Muestre las restricciones de "socios".


3 restricciones y 1 "foreign key" de "inscriptos" que la referencia.
13- Muestre las restricciones de "deportes".
3 restricciones y 1 "foreign key" de "inscriptos" que la referencia.

14- Muestre las restricciones de "profesores".


2 restricciones.

15- Muestre las restricciones de "inscriptos".


4 restricciones.

if object_id('inscriptos') is not null


drop table inscriptos;
if object_id('socios') is not null
drop table socios;
if object_id('profesores') is not null
drop table profesores;
if object_id('deportes') is not null
drop table deportes;

create table profesores(


documento char(8) not null,
nombre varchar(30),
domicilio varchar(30),
constraint CK_profesores_documento_patron check (documento like '[0-9][0-9][0-
9][0-9][0-9][0-9][0-9][0-9]'),
constraint PK_profesores_documento
primary key (documento)
);

create table deportes(


codigo tinyint identity,
nombre varchar(20) not null,
dia varchar(30)
constraint DF_deportes_dia default('sabado'),
profesor char(8),--documento del profesor
constraint CK_deportes_dia_lista check (dia in
('lunes','martes','miercoles','jueves','viernes','sabado')),
constraint PK_deportes_codigo
primary key (codigo)
);

create table socios(


numero int identity,
documento char(8),
nombre varchar(30),
domicilio varchar(30),
constraint CK_documento_patron check (documento like '[0-9][0-9][0-9][0-9][0-
9][0-9][0-9][0-9]'),
constraint PK_socios_numero
primary key nonclustered(numero),
constraint UQ_socios_documento
unique clustered(documento)
);

create table inscriptos(


numerosocio int not null,
codigodeporte tinyint,
matricula char(1),
constraint PK_inscriptos_numerodeporte
primary key clustered (numerosocio,codigodeporte),
constraint FK_inscriptos_deporte
foreign key (codigodeporte)
references deportes(codigo)
on update cascade,
constraint FK_inscriptos_socios
foreign key (numerosocio)
references socios(numero)
on update cascade
on delete cascade,
constraint CK_matricula_valores check (matricula in ('s','n'))
);

insert into profesores values('21111111','Andres Acosta','Avellaneda 111');


insert into profesores values('22222222','Betina Bustos','Bulnes 222');
insert into profesores values('23333333','Carlos Caseros','Colon 333');

insert into deportes values('basquet','lunes',null);


insert into deportes values('futbol','lunes','23333333');
insert into deportes values('natacion',null,'22222222');
insert into deportes values('padle',default,'23333333');
insert into deportes (nombre,dia) values('tenis','jueves');

insert into socios values('30111111','Ana Acosta','America 111');


insert into socios values('30222222','Bernardo Bueno','Bolivia 222');
insert into socios values('30333333','Camila Conte','Caseros 333');
insert into socios values('30444444','Daniel Duarte','Dinamarca 444');

insert into inscriptos values(1,3,'s');


insert into inscriptos values(1,5,'s');
insert into inscriptos values(2,1,'s');
insert into inscriptos values(4,1,'n');
insert into inscriptos values(4,4,'s');

select s.*,d.nombre as deporte,d.dia,p.nombre as profesor


from socios as s
join inscriptos as i
on numero=i.numerosocio
join deportes as d
on d.codigo=i.codigodeporte
left join profesores as p
on d.profesor=p.documento;

select s.*,d.nombre as deporte,d.dia,p.nombre as profesor


from socios as s
full join inscriptos as i
on numero=i.numerosocio
left join deportes as d
on d.codigo=i.codigodeporte
left join profesores as p
on d.profesor=p.documento;

select p.*,d.nombre as deporte,d.dia


from profesores as p
left join deportes as d
on d.profesor=p.documento;

select d.nombre,count(i.codigodeporte) as cantidad


from deportes as d
left join inscriptos as i
on d.codigo=i.codigodeporte
group by d.nombre;

sp_helpconstraint socios;

sp_helpconstraint deportes;

sp_helpconstraint profesores;

sp_helpconstraint inscriptos;

Unin
El operador "union" combina el resultado de dos o ms 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 seleccin de cada consulta. No se incluyen las
filas duplicadas en el resultado, a menos que coloque la opcin "all".

Se deben especificar los nombres de los campos en la primera instruccin "select".

Puede emplear la clusula "order by".

Puede dividir una consulta compleja en varias consultas "select" y luego emplear el operador
"union" para combinarlas.

Una academia de enseanza 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 invitacin.

Para obtener los datos necesarios de ambas tablas en una sola consulta necesitamos realizar una
unin:
select nombre, domicilio from alumnos
union
select nombre, domicilio from profesores;

El primer "select" devuelve el nombre y domicilio de todos los alumnos; el segundo, el nombre y
domicilio de todos los profesores.

Los encabezados del resultado de una unin son los que se especifican en el primer "select".

82 - Unin

Primer problema:
Un supermercado almacena en una tabla denominada "proveedores" los datos de las
compaas que le
proveen de mercaderas; 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;

2- Cree las tablas:


create table proveedores(
codigo int identity,
nombre varchar (30),
domicilio varchar(30),
primary key(codigo)
);
create table clientes(
codigo int identity,
nombre varchar (30),
domicilio varchar(30),
primary key(codigo)
);
create table empleados(
documento char(8) not null,
nombre varchar(20),
apellido varchar(20),
domicilio varchar(30),
primary key(documento)
);

3- Ingrese algunos registros:


insert into proveedores values('Bebida cola','Colon 123');
insert into proveedores values('Carnes Unica','Caseros 222');
insert into proveedores values('Lacteos Blanca','San Martin 987');
insert into clientes values('Supermercado Lopez','Avellaneda 34');
insert into clientes values('Almacen Anita','Colon 987');
insert into clientes values('Garcia Juan','Sucre 345');
insert into empleados values('23333333','Federico','Lopez','Colon 987');
insert into empleados values('28888888','Ana','Marquez','Sucre 333');
insert into empleados values('30111111','Luis','Perez','Caseros 956');

4- El supermercado quiere enviar una tarjeta de salutacin a todos los proveedores,


clientes y
empleados y necesita el nombre y domicilio de todos ellos. Emplee el operador "union"
para obtener
dicha informacin de las tres tablas.

5- Agregue una columna con un literal para indicar si es un proveedor, un cliente o un


empleado y
ordene por dicha columna.

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;

create table proveedores(


codigo int identity,
nombre varchar (30),
domicilio varchar(30),
primary key(codigo)
);
create table clientes(
codigo int identity,
nombre varchar (30),
domicilio varchar(30),
primary key(codigo)
);
create table empleados(
documento char(8) not null,
nombre varchar(20),
apellido varchar(20),
domicilio varchar(30),
primary key(documento)
);

insert into proveedores values('Bebida cola','Colon 123');


insert into proveedores values('Carnes Unica','Caseros 222');
insert into proveedores values('Lacteos Blanca','San Martin 987');
insert into clientes values('Supermercado Lopez','Avellaneda 34');
insert into clientes values('Almacen Anita','Colon 987');
insert into clientes values('Garcia Juan','Sucre 345');
insert into empleados values('23333333','Federico','Lopez','Colon 987');
insert into empleados values('28888888','Ana','Marquez','Sucre 333');
insert into empleados values('30111111','Luis','Perez','Caseros 956');

select nombre, domicilio from proveedores


union
select nombre, domicilio from clientes
union
select (apellido+' '+nombre), domicilio from empleados;

select nombre, domicilio, 'proveedor' as categoria from proveedores


union
select nombre, domicilio, 'cliente' from clientes
union
select (apellido+' '+nombre), domicilio , 'empleado' from empleados
order by categoria;

83 - Agregar y eliminar campos ( alter table - add - drop)

"alter table" permite modificar la estructura de una tabla.


Podemos utilizarla para agregar, modificar y eliminar campos de una tabla.

Para agregar un nuevo campo a una tabla empleamos la siguiente sintaxis bsica:

alter table NOMBRETABLA


add NOMBRENUEVOCAMPO DEFINICION;

En el siguiente ejemplo agregamos el campo "cantidad" a la tabla "libros", de tipo tinyint, que
acepta valores nulos:

alter table libros


add cantidad tinyint;

Puede verificarse la alteracin de la estructura de la tabla ejecutando el procedimiento


almacenado "sp_columns".

SQL Server no permite agregar campos "not null" a menos que se especifique un valor por
defecto:

alter table libros


add autor varchar(20) not null default 'Desconocido';

En el ejemplo anterior, se agreg una restriccin "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).

Para eliminar campos de una tabla la sintaxis bsica es la siguiente:


alter table NOMBRETABLA
drop column NOMBRECAMPO;

En el siguiente ejemplo eliminamos el campo "precio" de la tabla "libros":

alter table libros


drop column precio;

No pueden eliminarse los campos que son usados por un ndice o tengan restricciones. No puede
eliminarse un campo si es el nico en la tabla.

Podemos eliminar varios campos en una sola sentencia:

alter table libros


drop column editorial,edicion;

83 - Agregar y eliminar campos ( alter table - add - drop)

Primer problema:

Trabaje con una tabla llamada "empleados".


1- Elimine la tabla, si existe, crela y cargue un registro:
if object_id('empleados') is not null
drop table empleados;

create table empleados(


apellido varchar(20),
nombre varchar(20),
domicilio varchar(30),
fechaingreso datetime
);
insert into empleados(apellido,nombre) values ('Rodriguez','Pablo');

2- Agregue el campo "sueldo", de tipo decimal(5,2).

3- Verifique que la estructura de la tabla ha cambiado.

4- Agregue un campo "codigo", de tipo int con el atributo "identity".

5- Intente agregar un campo "documento" no nulo.


No es posible, porque SQL Server no permite agregar campos "not null" a menos que
se especifique un
valor por defecto.

6- Agregue el campo del punto anterior especificando un valor por defecto:


alter table empleados
add documento char(8) not null default '00000000';

7- Verifique que la estructura de la tabla ha cambiado.


8- Elimine el campo "sueldo".

9- Verifique la eliminacin:
sp_columns empleados;

10- Intente eliminar el campo "documento".


no lo permite.

11- Elimine los campos "codigo" y "fechaingreso" en una sola sentencia.

12- Verifique la eliminacin de los campos:


sp_columns empleados;

if object_id('empleados') is not null


drop table empleados;

create table empleados(


apellido varchar(20),
nombre varchar(20),
domicilio varchar(30),
fechaingreso datetime
);
insert into empleados(apellido,nombre) values ('Rodriguez','Pablo');

alter table empleados


add sueldo decimal(5,2);

sp_columns empleados;

alter table empleados


add codigo int identity;

alter table empleados


add documento char(8) not null;

alter table empleados


add documento char(8) not null default '00000000';

sp_columns empleados;

alter table empleados


drop column sueldo;

sp_columns empleados;

alter table empleados


drop column documento;

alter table empleados


drop column codigo,fechaingreso;
sp_columns empleados;

84 - Alterar campos (alter table - alter)

Hemos visto que "alter table" permite modificar la estructura de una tabla. Tambin podemos
utilizarla para modificar campos de una tabla.

La sintaxis bsica para modificar un campo existente es la siguiente:

alter table NOMBRETABLA


alter column CAMPO NUEVADEFINICION;

Modificamos el campo "titulo" extendiendo su longitud y para que NO admita valores nulos:

alter table libros


alter column titulo varchar(40) not null;

En el siguiente ejemplo alteramos el campo "precio" de la tabla "libros" que fue definido
"decimal(6,2) not null" para que no acepte valores nulos:

alter table libros


alter column precio decimal(6,2) null;

SQL Server tiene algunas excepciones al momento de modificar los campos. No permite
modificar:

- campos de tipo text, image, ntext y timestamp.

- un campo que es usado en un campo calculado.

- campos que son parte de ndices o tienen restricciones, a menos que el cambio no afecte al
ndice o a la restriccin, por ejemplo, se puede ampliar la longitud de un campo de tipo caracter.

- agregando o quitando el atributo "identity".

- campos que afecten a los datos existentes cuando una tabla contiene registros (ejemplo: 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.).

84 - Alterar campos (alter table - alter)

Primer problema:

Trabaje con una tabla llamada "empleados".


1- Elimine la tabla, si existe y crela:
if object_id('empleados') is not null
drop table empleados;

create table empleados(


legajo int not null,
documento char(7) not null,
nombre varchar(10),
domicilio varchar(30),
ciudad varchar(20) default 'Buenos Aires',
sueldo decimal(6,2),
cantidadhijos tinyint default 0,
primary key(legajo)
);

2- Modifique el campo "nombre" extendiendo su longitud.

3- Controle la modificacin:
sp_columns empleados;

4- Modifique el campo "sueldo" para que no admita valores nulos.

4- Modifique el campo "documento" ampliando su longitud a 8 caracteres.

5- Intente modificar el tipo de datos del campo "legajo" a "tinyint":


alter table empleados
alter column legajo tinyint not null;
No se puede porque tiene una restriccin.

6- Ingrese algunos registros, uno con "nombre" nulo:


insert into empleados values(1,'22222222','Juan Perez','Colon 123','Cordoba',500,3);
insert into empleados values(2,'30000000',null,'Sucre 456','Cordoba',600,2);

7- Intente modificar el campo "nombre" para que no acepte valores nulos:


alter table empleados
alter column nombre varchar(30) not null;
No se puede porque hay registros con ese valor.

8- Elimine el registro con "nombre" nulo y realice la modificacin del punto 7:


delete from empleados where nombre is null;
alter table empleados
alter column nombre varchar(30) not null;

9- Modifique el campo "ciudad" a 10 caracteres.

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 restriccin dndole una longitud de
15 caracteres.
12- Agregue el registro que no pudo ingresar en el punto 10:
insert into empleados values(3,'33333333','Juan Perez','Sarmiento
856',default,500,4);

13- Intente agregar el atributo identity de "legajo".


No se puede agregar este atributo.

if object_id('empleados') is not null


drop table empleados;

create table empleados(


legajo int not null,
documento char(7) not null,
nombre varchar(10),
domicilio varchar(30),
ciudad varchar(20) default 'Buenos Aires',
sueldo decimal(6,2),
cantidadhijos tinyint default 0,
primary key(legajo)
);

alter table empleados


alter column nombre varchar(30);

sp_columns empleados;

alter table empleados


alter column sueldo decimal(6,2) not null;

alter table empleados


alter column documento char(8) not null;

alter table empleados


alter column legajo tinyint not null;

insert into empleados values(1,'22222222','Juan Perez','Colon 123','Cordoba',500,3);


insert into empleados values(2,'30000000',null,'Sucre 456','Cordoba',600,2);

alter table empleados


alter column nombre varchar(30) not null;

delete from empleados where nombre is null;


alter table empleados
alter column nombre varchar(30) not null;

alter table empleados


alter column ciudad varchar(10);

insert into empleados values(3,'33333333','Juan Perez','Sarmiento


856',default,500,4);
alter table empleados
alter column ciudad varchar(15);

insert into empleados values(3,'33333333','Juan Perez','Sarmiento


856',default,500,4);

alter table empleados


alter column legajo int identity;

85 - Agregar campos y restricciones (alter table)

Podemos agregar un campo a una tabla y en el mismo momento aplicarle una restriccin.
Para agregar un campo y establecer una restriccin, la sintaxis bsica es la siguiente:

alter table TABLA


add CAMPO DEFINICION
constraint NOMBRERESTRICCION TIPO;

Agregamos a la tabla "libros", el campo "titulo" de tipo varchar(30) y una restriccin "unique" con
ndice agrupado:

alter table libros


add titulo varchar(30)
constraint UQ_libros_autor unique clustered;

Agregamos a la tabla "libros", el campo "codigo" de tipo int identity not null y una restriccin
"primary key" con ndice no agrupado:

alter table libros


add codigo int identity not null
constraint PK_libros_codigo primary key nonclustered;

Agregamos a la tabla "libros", el campo "precio" de tipo decimal(6,2) y una restriccin "check":

alter table libros


add precio decimal(6,2)
constraint CK_libros_precio check (precio>=0);

Primer problema:

Trabaje con una tabla llamada "empleados".


1- Elimine la tabla, si existe y crela:
if object_id('empleados') is not null
drop table empleados;

create table empleados(


documento char(8) not null,
nombre varchar(10),
domicilio varchar(30),
ciudad varchar(20) default 'Buenos Aires'
);

2- Agregue el campo "legajo" de tipo int identity y una restriccin "primary key":
alter table empleados
add legajo int identity
constraint PK_empleados_legajo primary key;

3- Vea si la estructura cambi y si se agreg la restriccin:


sp_columns empleados;
exec sp_helpconstraint empleados;

4- Agregue el campo "hijos" de tipo tinyint y en la misma sentencia una restriccin


"check" que no
permita valores superiores a 30:
alter table empleados
add hijos tinyint
constraint CK_empleados_hijos check (hijos<=30);

5- Ingrese algunos registros:


insert into empleados values('22222222','Juan Lopez','Colon 123','Cordoba',2);
insert into empleados values('23333333','Ana Garcia','Sucre 435','Cordoba',3);

6- Intente agregar el campo "sueldo" de tipo decimal(6,2) no nulo y una restriccin


"check" que no
permita valores negativos para dicho campo:
alter table empleados
add sueldo decimal(6,2) not null
constraint CK_empleados_sueldo check (sueldo>=0);
No lo permite porque no damos un valor por defecto para dicho campo no nulo y los
registros
existentes necesitan cargar un valor.

7- Agregue el campo "sueldo" de tipo decimal(6,2) no nulo, una restriccin "check" que
no permita
valores negativos para dicho campo y una restriccin "default" que almacene el valor
"0":
alter table empleados
add sueldo decimal(6,2) not null
constraint CK_empleados_sueldo check (sueldo>=0)
constraint DF_empleados_sueldo default 0;

8- Recupere los registros:


select *from empleados;

9- Vea la nueva estructura de la tabla:


sp_columns empleados;

10- Vea las restricciones:


sp_helpconstraint empleados;
if object_id('empleados') is not null
drop table empleados;

create table empleados(


documento char(8) not null,
nombre varchar(10),
domicilio varchar(30),
ciudad varchar(20) default 'Buenos Aires'
);

alter table empleados


add legajo int identity
constraint PK_empleados_legajo primary key;

sp_columns empleados;
exec sp_helpconstraint empleados;

alter table empleados


add hijos tinyint
constraint CK_empleados_hijos check (hijos<=30);

insert into empleados values('22222222','Juan Lopez','Colon 123','Cordoba',2);


insert into empleados values('23333333','Ana Garcia','Sucre 435','Cordoba',3);

alter table empleados


add sueldo decimal(6,2) not null
constraint CK_empleados_sueldo check (sueldo>=0);

alter table empleados


add sueldo decimal(6,2) not null
constraint CK_empleados_sueldo check (sueldo>=0)
constraint DF_empleados_sueldo default 0;

select *from empleados;

sp_columns empleados;

sp_helpconstraint empleados;

86 - Campos calculados

Un campo calculado es un campo que no se almacena fsicamente en la tabla. SQL Server emplea
una frmula que detalla el usuario al definir dicho campo para calcular el valor segn otros
campos de la misma tabla.

Un campo calculado no puede:


- definirse como "not null".

- ser una subconsulta.

- tener restriccin "default" o "foreign key".

- insertarse ni actualizarse.

Puede ser empleado como llave de un ndice o parte de restricciones "primary key" o "unique" si
la expresin que la define no cambia en cada consulta.

Creamos un campo calculado denominado "sueldototal" que suma al sueldo bsico de cada
empleado la cantidad abonada por los hijos (100 por cada hijo):

create table empleados(


documento char(8),
nombre varchar(10),
domicilio varchar(30),
sueldobasico decimal(6,2),
cantidadhijos tinyint default 0,
sueldototal as sueldobasico + (cantidadhijos*100)
);

Tambin se puede agregar un campo calculado a una tabla existente:

alter table NOMBRETABLA


add NOMBRECAMPOCALCULADO as EXPRESION;

alter table empleados


add sueldototal as sueldo+(cantidadhijos*100);

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 artculos para la venta en una tabla
denominada "articulos".
1- Elimine la tabla, si existe y crela nuevamente:
if object_id('articulos') is not null
drop table articulos;

create table articulos(


codigo int identity,
descripcion varchar(30),
precio decimal(5,2) not null,
cantidad smallint not null default 0,
montototal as precio *cantidad
);
El campo "montototal" es un campo calculado que multiplica el precio de cada artculo
por la
cantidad disponible.

2- Intente ingresar un registro con valor para el campo calculado:


insert into articulos values('birome',1.5,100,150);
No lo permite.

3- Ingrese algunos registros:


insert into articulos values('birome',1.5,100);
insert into articulos values('cuaderno 12 hojas',4.8,150);
insert into articulos values('lapices x 12',5,200);

4- Recupere los registros:


select *from articulos;

5- Actualice un precio y recupere los registros:


update articulos set precio=2 where descripcion='birome';
select *from articulos;
el campo calculado "montototal" recalcula los valores para cada registro
automticamente.

6- Actualice una cantidad y vea el resultado:


update articulos set cantidad=200 where descripcion='birome';
select *from articulos;
el campo calculado "montototal" recalcula sus valores.

7- Intente actualizar un campo calculado:


update articulos set montototal=300 where descripcion='birome';
No lo permite.

if object_id('articulos') is not null


drop table articulos;

create table articulos(


codigo int identity,
descripcion varchar(30),
precio decimal(5,2) not null,
cantidad smallint not null default 0,
montototal as precio *cantidad
);

insert into articulos values('birome',1.5,100,150);

insert into articulos values('birome',1.5,100);


insert into articulos values('cuaderno 12 hojas',4.8,150);
insert into articulos values('lapices x 12',5,200);

select *from articulos;


update articulos set precio=2 where descripcion='birome';
select *from articulos;

update articulos set cantidad=200 where descripcion='birome';


select *from articulos;

update articulos set montototal=300 where descripcion='birome';

87 - Tipo de dato definido por el usuario (crear - informacion)

Cuando definimos un campo de una tabla debemos especificar el tipo de datos, sabemos que los
tipos de datos especifican el tipo de informacin (caracteres, nmeros, fechas) que pueden
almacenarse en un campo. SQL Server proporciona distintos tipos de datos del sistema (char,
varchar, int, decimal, datetime, etc.) y permite tipos de datos definidos por el usuario siempre
que se basen en los tipos de datos existentes.

Se pueden crear y eliminar tipos de datos definidos por el usuario.


Se emplean cuando varias tablas deben almacenar el mismo tipo de datos en un campo y se
quiere garantizar que todas tengan el mismo tipo y longitud.

Para darle un nombre a un tipo de dato definido por el usuario debe considerar las mismas 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 bsica:

exec sp_addtype NOMBRENUEVOTIPO, 'TIPODEDATODELSISTEMA', 'OPCIONNULL';

Creamos un tipo de datos definido por el usuario llamado "tipo_documento" que admite valores
nulos:

exec sp_addtype tipo_documento, 'char(8)', 'null';

Ejecutando el procedimiento almacenado "sp_help" junto al nombre del tipo de dato definido por
el usuario se obtiene informacin 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).

Tambin podemos consultar la tabla "systypes" en la cual se almacena informacin de todos los
tipos de datos:

select name from systypes;

87 - Tipo de dato definido por el usuario (crear - informacion)


Primer problema:

Un comercio 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- Defina un nuevo tipo de dato llamado "tipo_legajo". Primero debe eliminarlo (si
existe) para
volver a crearlo. Para ello emplee esta sentencia que explicaremos en el siguiente
captulo:
if exists (select name from systypes
where name = 'tipo_legajo')
exec sp_droptype tipo_legajo;

3- Cree un tipo de dato definido por el usuario llamado "tipo_legajo" basado en el tipo
"char" de 4
caracteres que no permita valores nulos.

4- Ejecute el procedimiento almacenado "sp_help" junto al nombre del tipo de dato


definido
anteriormente para obtener informacin del mismo.

5- Cree la tabla "empleados" con 3 campos: legajo (tipo_legajo), documento (char de


8) y nombre (30
caracteres):
create table empleados(
legajo tipo_legajo,
documento char(8),
nombre varchar(30)
);

6- Intente ingresar un registro con valores por defecto:


insert into empleados default values;
No se puede porque el campo "tipo_legajo" no admite valores nulos y no tiene definido
un valor por
defecto.

7- Ingrese un registro con valores vlidos.

88 - Tipo de dato definido por el usuario (asociacin de reglas)

Se puede asociar una regla a un tipo de datos definido por el usuario. Luego de crear la regla se
establece la asociacin; la sintaxis es la siguiente:

exec sp_bindrule NOMBREREGLA, 'TIPODEDATODEFINIDOPORELUSUARIO',


'futureonly';
El parmetro "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
debern cumplir la regla. Si no se especifica este parmetro, 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 instruccin "insert" o
"update" muestra un mensaje de error.

Si asocia una regla a un tipo de dato definido por el usuario que tiene otra regla asociada, esta
ltima la reemplaza.

Para quitar la asociacin, empleamos el mismo procedimiento almacenado que aprendimos


cuando quitamos asociaciones a campos, ejecutamos el procedimiento almacenado
"sp_unbindrule" seguido del nombre del tipo de dato al que est asociada la regla:

exec sp_unbindrule 'TIPODEDATODEFINIDOPORELUSUARIO';

Si asocia una regla a un campo cuyo tipo de dato definido por el usuario ya tiene una regla
asociada, la nueva regla se aplica al campo, pero el tipo de dato contina 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 instruccin "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 informacin 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.

88 - Tipo de dato definido por el usuario (asociacin de reglas)

Primer problema:

Un comercio almacena los datos de sus empleados en una tabla denominada


"empleados" y en otra
llamada "clientes" los datos de sus clientes".
1- Elimine ambas tablas, si existen:
if object_id ('empleados') is not null
drop table empleados;
if object_id ('clientes') is not null
drop table clientes;

2- Defina un nuevo tipo de dato llamado "tipo_ao". Primero debe eliminarlo, si existe,
para volver
a crearlo. Para ello emplee esta sentencia que explicaremos en el siguiente captulo:
if exists (select *from systypes
where name = 'tipo_ao')
exec sp_droptype tipo_ao;

3- Cree un tipo de dato definido por el usuario llamado "tipo_ao" basado en el tipo
"int" que
permita valores nulos:
exec sp_addtype tipo_ao, 'int','null';

4- Ejecute el procedimiento almacenado "sp_help" junto al nombre del tipo de dato


definido
anteriormente para obtener informacin del mismo:
sp_help tipo_ao;
5- Cree la tabla "empleados" con 3 campos: documento (char de 8), nombre (30
caracteres) y
aoingreso (tipo_ao):
create table empleados(
documento char(8),
nombre varchar(30),
aoingreso tipo_ao
);

6- Elimine la regla llamada "RG_ao" si existe:


if object_id ('RG_ao') is not null
drop rule RG_ao;

7- Cree la regla que permita valores integer desde 1990 (ao en que se inaugur el
comercio) y el
ao actual:
create rule RG_ao
as @ao between 1990 and datepart(year,getdate());

8- Asocie la regla al tipo de datos "tipo_ao" especificando que solamente se aplique a


los futuros
campos de este tipo:
exec sp_bindrule RG_ao, 'tipo_ao', 'futureonly';

9- Vea si se aplic a la tabla empleados:


sp_helpconstraint empleados;
No se aplic porque especificamos la opcin "futureonly":

10- Cree la tabla "clientes" con 3 campos: nombre (30 caracteres), aoingreso
(tipo_ao) y domicilio
(30 caracteres):
create table clientes(
documento char(8),
nombre varchar(30),
aoingreso tipo_ao
);

11- Vea si se aplic la regla en la nueva tabla:


sp_helpconstraint clientes;
Si aparece.

12- Ingrese registros con valores para el ao que infrinjan la regla en la tabla
"empleados":
insert into empleados values('11111111','Ana Acosta',2050);
select *from empleados;
Lo acepta porque en esta tabla no se aplica la regla.

13- Intente ingresar en la tabla "clientes" un valor de fecha que infrinja la regla:
insert into clientes values('22222222','Juan Perez',2050);
No lo permite.

14- Quite la asociacin de la regla con el tipo de datos:


exec sp_unbindrule 'tipo_ao';

15- Vea si se quit la asociacin:


sp_helpconstraint clientes;
Si se quit.

16- Vuelva a asociar la regla, ahora sin el parmetro "futureonly":


exec sp_bindrule RG_ao, 'tipo_ao';
Note que hay valores que no cumplen la regla pero SQL Server NO lo verifica al
momento de asociar
una regla.

17- Intente agregar una fecha de ingreso fuera del intervalo que admite la regla en
cualquiera de
las tablas (ambas tienen la asociacin):
insert into empleados values('33333333','Romina Guzman',1900);
Mensaje de error.

18- Vea la informacin del tipo de dato:


exec sp_help tipo_ao;
En la columna que hace referencia a la regla asociada aparece "RG_ao".

19- Elimine la regla llamada "RG_aonegativo", si existe:


if object_id ('RG_aonegativo') is not null
drop rule RG_aonegativo;

20- Cree una regla llamada "RG_aonegativo" que admita valores entre -2000 y -1:
create rule RG_aonegativo
as @ao between -2000 and -1;

21- Asocie la regla "RG_aonegativo" al campo "aoingreso" de la tabla "clientes":


exec sp_bindrule RG_aonegativo, 'clientes.aoingreso';

22- Vea si se asoci:


sp_helpconstraint clientes;
Se asoci.

23- Verifique que no est asociada al tipo de datos "tipo_ao":


sp_help tipo_ao;
No, tiene asociada la regla "RG_ao".
24- Intente ingresar un registro con valor '-1900' para el campo "aoingreso" de
"empleados":
insert into empleados values('44444444','Pedro Perez',-1900);
No lo permite por la regla asociada al tipo de dato.

25- Ingrese un registro con valor '-1900' para el campo "aoingreso" de "clientes" y
recupere los
registros de dicha tabla:
insert into clientes values('44444444','Pedro Perez',-1900);
select *from clientes;
Note que se ingreso, si bien el tipo de dato de "aoingreso" tiene asociada una regla
que no admite
tal valor, el campo tiene asociada una regla que si lo admite y sta prevalece.

89 - Tipo de dato definido por el usuario (valores predeterminados)

Se puede asociar un valor predeterminado a un tipo de datos definido por el usuario. Luego de
crear un valor predeterminado, se puede asociar a un tipo de dato definido por el usuario con la
siguiente sintaxis:

exec sp_bindefault NOMBREVALORPREDETERMINADO,


'TIPODEDATODEFINIDOPORELUSUARIO','futureonly';

El parmetro "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 parmetro,
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.

Para quitar la asociacin, empleamos el mismo procedimiento almacenado que aprendimos


cuando quitamos asociaciones a campos:

sp_unbindefault 'TIPODEDATODEFINIDOPORELUSUARIO';

Debe tener en cuenta que NO se puede aplicar una restriccin "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 restriccin "default" y luego se
asocia un valor predeterminado al tipo de dato, el valor predeterminado no queda asociado en el
campo que tiene la restriccin "default".

Un tipo de dato definido por el usuario puede tener un solo valor predeterminado asociado.

Cuando obtenemos informacin 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 ningn valor predeterminado asociado.

89 - Tipo de dato definido por el usuario (valores predeterminados)

Primer problema:

Un comercio almacena los datos de sus empleados en una tabla denominada


"empleados" y en otra
llamada "clientes" los datos de sus clientes".
1- Elimine ambas tablas, si existen:
if object_id ('empleados') is not null
drop table empleados;
if object_id ('clientes') is not null
drop table clientes;

2- Defina un nuevo tipo de dato llamado "tipo_ao". Primero debe eliminarlo, si existe,
para volver
a crearlo. Para ello emplee esta sentencia que explicaremos en el siguiente captulo:
if exists (select *from systypes
where name = 'tipo_ao')
exec sp_droptype tipo_ao;

3- Cree un tipo de dato definido por el usuario llamado "tipo_ao" basado en el tipo
"int" que
permita valores nulos:
exec sp_addtype tipo_ao, 'int','null';

4- Ejecute el procedimiento almacenado "sp_help" junto al nombre del tipo de dato


definido
anteriormente para obtener informacin del mismo:
sp_help tipo_ao;

5- Cree la tabla "empleados" con 3 campos: documento (char de 8), nombre (30
caracteres) y
aoingreso (tipo_ao):
create table empleados(
documento char(8),
nombre varchar(30),
aoingreso tipo_ao
);
6- Elimine el valor predeterminado "VP_aoactual" si existe:
if object_id ('VP_aoactual') is not null
drop default VP_aoactual;

7- Cree el valor predeterminado "VP_aoactual" que almacene el ao actual:


create default VP_aoactual
as datepart(year,getdate());

8- Asocie el valor predeterminado al tipo de datos "tipo_ao" especificando que


solamente se aplique
a los futuros campos de este tipo:
exec sp_bindefault VP_aoactual, 'tipo_ao', 'futureonly';

9- Vea si se aplic a la tabla empleados:


sp_helpconstraint empleados;
No se aplic porque especificamos la opcin "futureonly":

10- Cree la tabla "clientes" con 3 campos: nombre (30 caracteres), aoingreso
(tipo_ao) y domicilio
(30 caracteres):
create table clientes(
documento char(8),
nombre varchar(30),
aoingreso tipo_ao
);

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
"aoingreso":
insert into empleados default values;
select *from empleados;
Se almacen "null" porque en esta tabla no se aplica el valor predeterminado.

13- Ingrese en la tabla "clientes" un registro con valores por defecto y recupere los
registros:
insert into clientes default values;
select *from clientes;
Se almacen el valor predeterminado.

14- Elimine el valor predeterminado llamado "VP_ao2000", si existe:


if object_id ('VP_ao2000') is not null
drop default Vp_ao2000;

15- Cree un valor predeterminado llamado "VP_ao2000" con el valor 2000:


create default VP_ao2000
as 2000;

16- Ascielo al tipo de dato definido sin especificar "futureonly":


exec sp_bindefault VP_ao2000, 'tipo_ao';
17- Verifique que se asoci a la tabla "empleados":
sp_helpconstraint empleados;

18- Verifique que reemplaz al valor predeterminado anterior en la tabla "clientes":


sp_helpconstraint clientes;

18- Ingrese un registro en ambas tablas con valores por defecto y vea qu se
almacen en el ao de
ingreso:
insert into empleados default values;
select *from empleados;
insert into clientes default values;
select *from clientes;

19- Vea la informacin del tipo de dato:


exec sp_help tipo_ao;
La columna que hace referencia al valor predeterminado asociado muestra
"VP_ao2000".

20- Intente agregar a la tabla "empleados" una restriccin "default":


alter table empleados
add constraint DF_empleados_ao
default 1990
for aoingreso;
No lo permite porque el tipo de dato del campo ya tiene un valor predeterminado
asociado.

21- Quite la asociacin del valor predeterminado al tipo de dato:


sp_unbindefault 'tipo_ao';

22- Agregue a la tabla "empleados" una restriccin "default":


alter table empleados
add constraint DF_empleados_ao
default 1990
for aoingreso;

23- Asocie el valor predeterminado "VP_aoactual" al tipo de dato "tipo_ao":


exec sp_bindefault VP_aoactual, 'tipo_ao';

24- Verifique que el tipo de dato tiene asociado el valor predeterminado:


sp_help tipo_ao;

25- Verifique que la tabla "clientes" tiene asociado el valor predeterminado:


sp_helpconstraint clientes;

26- Verifique que la tabla "empleados" no tiene asociado el valor predeterminado


"VP_aoactual"
asociado al tipo de dato y tiene la restriccin "default":
sp_helpconstraint empleados;
90 - Tipo de dato definido por el usuario (eliminar)

Podemos eliminar un tipo de dato definido por el usuario con el procedimiento almacenado
"sp_droptype":

exec sp_droptype TIPODEDATODEFINIDOPORELUSUARIO;

Eliminamos el tipo de datos definido por el usuario llamado "tipo_documento":

exec sp_droptype tipo_documento;

Si intentamos eliminar un tipo de dato inexistente, aparece un mensaje indicando que no existe.

Los tipos de datos definidos por el usuario se almacenan en la tabla del sistema "systypes".
Podemos averiguar si un tipo de dato definido por el usuario existe para luego eliminarlo:

if exists (select *from systypes


where name = 'NOMBRETIPODEDATODEFINIDOPORELUSUARIO')
exec sp_droptype TIPODEDATODEFINIDOPORELUSUARIO;

Consultamos la tabla "systypes" para ver si existe el tipo de dato "tipo_documento", si es as, lo
eliminamos:

if exists (select *from systypes


where name = 'tipo_documento')
exec sp_droptype tipo_documento;

No se puede eliminar un tipo de datos definido por el usuario si alguna tabla (u otro objeto) 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.

90 - Tipo de dato definido por el usuario (eliminar)

Primer problema:

Un comercio 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- Defina un nuevo tipo de dato llamado "tipo_ao". Primero debe eliminarlo, si existe
para volver a
crearlo:
if exists (select *from systypes
where name = 'tipo_ao')
exec sp_droptype tipo_ao;

3- Cree un tipo de dato definido por el usuario llamado "tipo_ao" basado en el tipo
"int" que
permita valores nulos:
exec sp_addtype tipo_ao, 'int','null';

4- Elimine la regla llamada "RG_ao" si existe:


if object_id ('RG_ao') is not null
drop rule RG_ao;

5- Cree la regla que permita valores integer desde 1990 (fecha en que se inaugur el
comercio) y el
ao actual:
create rule RG_ao
as @ao between 1990 and datepart(year,getdate());

6- Asocie la regla al tipo de datos "tipo_ao":


exec sp_bindrule RG_ao, 'tipo_ao';

7- Cree la tabla "empleados" con un campo del tipo creado anteriormente:


create table empleados(
documento char(8),
nombre varchar(30),
aoingreso tipo_ao
);

8- Intente ingresar un registro con un valor invlido para el campo "aoingreso":


insert into empleados values('22222222','Juan Lopez',1980);
No lo permite.

9- Ingrese un registro con un valor vlido para el campo "aoingreso":


insert into empleados values('22222222','Juan Lopez',2000);

10- Intente eliminar la regla asociada al tipo de datos:


drop rule RG_ao;
No se puede porque est asociada a un tipo de datos.

11- Elimine la asociacin:


exec sp_unbindrule 'tipo_ao';

12- Verifique que la asociacin ha sido eliminada pero la regla sigue existiendo:
sp_helpconstraint empleados;
exec sp_help tipo_ao;

13- Elimine la regla:


drop rule RG_ao;

14- Verifique que la regla ya no existe:


sp_help RG_ao;
15- Ingrese el registro que no pudo ingresar en el punto 8:
insert into empleados values('22222222','Juan Lopez',1980);
Lo permite porque el tipo de dato ya no tiene asociada la regla.

16- Intente eliminar el tipo de datos "tipo_ao":


exec sp_droptype tipo_ao;
No lo permite porque hay una tabla que lo utiliza.

17- Elimine la tabla "empleados":


drop table empleados;

18- Verifique que el tipo de dato "tipo_ao" an existe:


sp_help tipo_ao;

19- Elimine el tipo de datos:


exec sp_droptype tipo_ao;

20- Verifique que el tipo de dato "tipo_ao" ya no existe:


sp_help tipo_ao;

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 lgicos y se obtiene el resultado con una nica instruccin y cuando la consulta
depende de los resultados de otra consulta.

Generalmente, una subconsulta se puede reemplazar por combinaciones y estas ltimas son ms
eficientes.

Las subconsultas se DEBEN incluir entre parntesis.

Puede haber subconsultas dentro de subconsultas, se admiten hasta 32 niveles de anidacin.

Se pueden emplear subconsultas:

- en lugar de una expresin, 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 combinacin (join).

Hay tres tipos bsicos de subconsultas:

1. las que retornan un solo valor escalar que se utiliza con un operador de comparacin o en
lugar de una expresin.
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".

Reglas a tener en cuenta al emplear subconsultas:

- la lista de seleccin de una subconsulta que va luego de un operador de comparacin puede


incluir slo una expresin o campo (excepto si se emplea "exists" y "in").

- si el "where" de la consulta exterior incluye un campo, este debe ser compatible con el campo
en la lista de seleccin de la subconsulta.

- no se pueden emplear subconsultas que recuperen campos de tipos text o image.

- las subconsultas luego de un operador de comparacin (que no es seguido por "any" o "all") no
pueden incluir clusulas "group by" ni "having".

- "distinct" no puede usarse con subconsultas que incluyan "group by".

- no pueden emplearse las clusulas "compute" y "compute by".

- "order by" puede emplearse solamente si se especifica "top" tambin.

- una vista creada con una subconsulta no puede actualizarse.

- 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


sern incluidos en la salida (en la lista de seleccin de la consulta externa).

92 - Subconsultas como expresin

Una subconsulta puede reemplazar una expresin. Dicha subconsulta debe devolver un valor
escalar (o una lista de valores de un campo).

Las subconsultas que retornan un solo valor escalar se utiliza con un operador de comparacin o
en lugar de una expresin:

select CAMPOS
from TABLA
where CAMPO OPERADOR (SUBCONSULTA);

select CAMPO OPERADOR (SUBCONSULTA)


from TABLA;

Si queremos saber el precio de un determinado libro y la diferencia con el precio del libro ms
costoso, anteriormente debamos averiguar en una consulta el precio del libro ms 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 ttulo, el precio de un libro y la diferencia entre el precio


del libro y el mximo valor de precio.

Queremos saber el ttulo, autor y precio del libro ms costoso:

select titulo,autor, precio


from libros
where precio=
(select max(precio) from libros);

Note que el campo del "where" de la consulta exterior es compatible con el valor retornado por la
expresin de la subconsulta.

Se pueden emplear en "select", "insert", "update" y "delete".

Para actualizar un registro empleando subconsulta la sintaxis bsica es la siguiente:

update TABLA set CAMPO=NUEVOVALOR


where CAMPO= (SUBCONSULTA);

Para eliminar registros empleando subconsulta empleamos la siguiente sintaxis bsica:

delete from TABLA


where CAMPO=(SUBCONSULTA);

Recuerde que la lista de seleccin de una subconsulta que va luego de un operador de


comparacin puede incluir slo una expresin o campo (excepto si se emplea "exists" o "in").

No olvide que las subconsultas luego de un operador de comparacin (que no es seguido por "any"
o "all") no pueden incluir clusulas "group by".

92 - Subconsultas como expresin

Primer problema:

Un profesor almacena el documento, nombre y la nota final de cada alumno de su


clase en una tabla
llamada "alumnos".
1- Elimine la tabla, si existe:
if object_id('alumnos') is not null
drop table alumnos;

2- Crela con los campos necesarios. Agregue una restriccin "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),
);

3-Ingrese algunos registros:


insert into alumnos values('30111111','Ana Algarbe',5.1);
insert into alumnos values('30222222','Bernardo Bustamante',3.2);
insert into alumnos values('30333333','Carolina Conte',4.5);
insert into alumnos values('30444444','Diana Dominguez',9.7);
insert into alumnos values('30555555','Fabian Fuentes',8.5);
insert into alumnos values('30666666','Gaston Gonzalez',9.70);

4- Obtenga todos los datos de los alumnos con la nota ms alta, empleando
subconsulta.
2 registros.

5- realice la misma consulta anterior pero intente que la consulta interna retorne,
adems del
mximo valor de precio, el ttulo:
select titulo,autor, precio
from libros
where precio=
(select titulo, max(precio) from libros);
Mensaje de error, porque la lista de seleccin de una subconsulta que va luego de un
operador de
comparacin puede incluir slo un campo o expresin (excepto si se emplea "exists" o
"in").

6- Muestre los alumnos que tienen una nota menor al promedio, su nota, y la
diferencia con el
promedio.
3 registros.

7- Cambie la nota del alumno que tiene la menor nota por 4.


1 registro modificado.

8- Elimine los alumnos cuya nota es menor al promedio.


3 registros eliminados.

if object_id('alumnos') is not null


drop table alumnos;

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),
);

insert into alumnos values('30111111','Ana Algarbe',5.1);


insert into alumnos values('30222222','Bernardo Bustamante',3.2);
insert into alumnos values('30333333','Carolina Conte',4.5);
insert into alumnos values('30444444','Diana Dominguez',9.7);
insert into alumnos values('30555555','Fabian Fuentes',8.5);
insert into alumnos values('30666666','Gaston Gonzalez',9.70);

select alumnos.*
from alumnos
where nota=
(select max(nota) from alumnos);

select titulo,autor, precio


from libros
where precio=
(select titulo, max(precio) from libros);

select alumnos.*,
(select avg(nota) from alumnos)-nota as diferencia
from alumnos
where nota<
(select avg(nota) from alumnos);

update alumnos set nota=4


where nota=
(select min(nota) from alumnos);

delete from alumnos


where nota<
(select avg(nota) from alumnos);

93 - Subconsultas con in

Vimos que una subconsulta puede reemplazar una expresin. 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 expresin en una clusula "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.

La sintaxis bsica es la siguiente:

...where EXPRESION in (SUBCONSULTA);


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.

Podemos reemplazar por un "join" la consulta anterior:

select distinct nombre


from editoriales as e
join libros
on codigoeditorial=e.codigo
where autor='Richard Bach';

Una combinacin (join) siempre puede ser expresada como una subconsulta; pero una subconsulta
no siempre puede reemplazarse por una combinacin que retorne el mismo resultado. Si es
posible, es aconsejable emplear combinaciones en lugar de subconsultas, son ms eficientes.

Se recomienda probar las subconsultas antes de incluirlas en una consulta exterior, as puede
verificar que retorna lo necesario, porque a veces resulta difcil verlo en consultas anidadas.

Tambin 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 especfico:

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", tambin
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;
2- Cree la tabla "clientes" (codigo, nombre, domicilio, ciudad, codigociudad) y
"ciudades" (codigo,
nombre). Agregue una restriccin "primary key" para el campo "codigo" de ambas
tablas y una "foreing
key" para validar que el campo "codigociudad" exista en "ciudades" con actualizacin
en cascada:
create table ciudades(
codigo tinyint identity,
nombre varchar(20),
primary key (codigo)
);

create table clientes (


codigo int identity,
nombre varchar(30),
domicilio varchar(30),
codigociudad tinyint not null,
primary key(codigo),
constraint FK_clientes_ciudad
foreign key (codigociudad)
references ciudades(codigo)
on update cascade,
);

3- Ingrese algunos registros para ambas tablas:


insert into ciudades (nombre) values('Cordoba');
insert into ciudades (nombre) values('Cruz del Eje');
insert into ciudades (nombre) values('Carlos Paz');
insert into ciudades (nombre) values('La Falda');
insert into ciudades (nombre) values('Villa Maria');

insert into clientes values ('Lopez Marcos','Colon 111',1);


insert into clientes values ('Lopez Hector','San Martin 222',1);
insert into clientes values ('Perez Ana','San Martin 333',2);
insert into clientes values ('Garcia Juan','Rivadavia 444',3);
insert into clientes values ('Perez Luis','Sarmiento 555',3);
insert into clientes values ('Gomez Ines','San Martin 666',4);
insert into clientes values ('Torres Fabiola','Alem 777',5);
insert into clientes values ('Garcia Luis','Sucre 888',5);

4- Necesitamos conocer los nombres de las ciudades de aquellos clientes cuyo


domicilio es en calle
"San Martin", empleando subconsulta.
3 registros.

5- Obtenga la misma salida anterior pero empleando join.

6- Obtenga los nombre de las ciudades de los clientes cuyo apellido no comienza con
una letra
especfica, empleando subconsulta.
2 registros.
7- Pruebe la subconsulta del punto 6 separada de la consulta exterior para verificar
que retorna una
lista de valores de un solo campo.

if (object_id('ciudades')) is not null


drop table ciudades;
if (object_id('clientes')) is not null
drop table clientes;

create table ciudades(


codigo tinyint identity,
nombre varchar(20),
primary key (codigo)
);

create table clientes (


codigo int identity,
nombre varchar(30),
domicilio varchar(30),
codigociudad tinyint not null,
primary key(codigo),
constraint FK_clientes_ciudad
foreign key (codigociudad)
references ciudades(codigo)
on update cascade,
);

insert into ciudades (nombre) values('Cordoba');


insert into ciudades (nombre) values('Cruz del Eje');
insert into ciudades (nombre) values('Carlos Paz');
insert into ciudades (nombre) values('La Falda');
insert into ciudades (nombre) values('Villa Maria');

insert into clientes values ('Lopez Marcos','Colon 111',1);


insert into clientes values ('Lopez Hector','San Martin 222',1);
insert into clientes values ('Perez Ana','San Martin 333',2);
insert into clientes values ('Garcia Juan','Rivadavia 444',3);
insert into clientes values ('Perez Luis','Sarmiento 555',3);
insert into clientes values ('Gomez Ines','San Martin 666',4);
insert into clientes values ('Torres Fabiola','Alem 777',5);
insert into clientes values ('Garcia Luis','Sucre 888',5);

select nombre
from ciudades
where codigo in
(select codigociudad
from clientes
where domicilio like 'San Martin %');

select distinct ci.nombre


from ciudades as ci
join clientes as cl
on codigociudad=ci.codigo
where domicilio like 'San Martin%';

select nombre
from ciudades
where codigo not in
(select codigociudad
from clientes
where nombre like 'G%');

select codigociudad
from clientes
where nombre like 'G%';

94 - Subconsultas any - some - all

"any" y "some" son sinnimos. Chequean si alguna fila de la lista resultado de una subconsulta se
encuentra el valor especificado en la condicin.

Compara un valor escalar con los valores de un campo y devuelven "true" si la comparacin con
cada valor de la lista de la subconsulta es verdadera, sino "false".

El tipo de datos que se comparan deben ser compatibles.

La sintaxis bsica es:

...VALORESCALAR OPERADORDECOMPARACION
ANY (SUBCONSULTA);

Queremos saber los ttulos de los libros de "Borges" que pertenecen a editoriales que han
publicado tambin 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 ttulos de "Borges" que coinciden.

"all" tambin 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:

VALORESCALAR OPERADORDECOMPARACION all (SUBCONSULTA);

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 ttulos.

Veamos otro ejemplo con un operador de comparacin diferente:

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 condicin, es decir, es mayor a ALGUN precio de
"Richard Bach", se lista.

Veamos la diferencia si empleamos "all" en lugar de "any":

select titulo,precio
from libros
where autor='borges' and
precio > all
(select precio
from libros
where autor='bach');

El precio de cada libro de "Borges" es comparado con cada valor de la lista de valores retornada
por la subconsulta; si cumple la condicin, es decir, si es mayor a TODOS los precios de "Richard
Bach" (o al mayor), se lista.

Emplear "= any" es lo mismo que emplear "in".


Emplear "<> all" es lo mismo que emplear "not in".

Recuerde que solamente las subconsultas luego de un operador de comparacin al cual es seguido
por "any" o "all") pueden incluir clusulas "group by".

94 - Subconsultas any - some - all

Primer problema:

Un club dicta clases de distintos deportes a sus socios. El club tiene una tabla llamada
"inscriptos" en la cual almacena el nmero de "socio", el cdigo del deporte en el cual
se inscribe
y la cantidad de cuotas pagas (desde 0 hasta 10 que es el total por todo el ao), 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)
);

create table inscriptos (


numerosocio int not null,
deporte varchar(20) not null,
cuotas tinyint
constraint CK_inscriptos_cuotas
check (cuotas>=0 and cuotas<=10)
constraint DF_inscriptos_cuotas default 0,
primary key(numerosocio,deporte),
constraint FK_inscriptos_socio
foreign key (numerosocio)
references socios(numero)
on update cascade
on delete cascade,
);

3- Ingrese algunos registros:


insert into socios values('23333333','Alberto Paredes','Colon 111');
insert into socios values('24444444','Carlos Conte','Sarmiento 755');
insert into socios values('25555555','Fabian Fuentes','Caseros 987');
insert into socios values('26666666','Hector Lopez','Sucre 344');

insert into inscriptos values(1,'tenis',1);


insert into inscriptos values(1,'basquet',2);
insert into inscriptos values(1,'natacion',1);
insert into inscriptos values(2,'tenis',9);
insert into inscriptos values(2,'natacion',1);
insert into inscriptos values(2,'basquet',default);
insert into inscriptos values(2,'futbol',2);
insert into inscriptos values(3,'tenis',8);
insert into inscriptos values(3,'basquet',9);
insert into inscriptos values(3,'natacion',0);
insert into inscriptos values(4,'basquet',10);

4- Muestre el nmero de socio, el nombre del socio y el deporte en que est inscripto
con un join de
ambas tablas.

5- Muestre los socios que se sern compaeros en tenis y tambin en natacin


(empleando
subconsulta)
3 filas devueltas.

6- vea si el socio 1 se ha inscripto en algn deporte en el cual se haya inscripto el


socio 2.
3 filas.

7- Obtenga el mismo resultado anterior pero empleando join.

8- Muestre los deportes en los cuales el socio 2 pag ms cuotas que ALGUN deporte
en los que se
inscribi el socio 1.
2 registros.

9- Muestre los deportes en los cuales el socio 2 pag ms cuotas que TODOS los
deportes en que se
inscribi el socio 1.
1 registro.

10- Cuando un socio no ha pagado la matrcula de alguno de los deportes en que se ha


inscripto, se
lo borra de la inscripcin de todos los deportes. Elimine todos los socios que no
pagaron ninguna
cuota en algn deporte.
7 registros.

if object_id('inscriptos') is not null


drop table inscriptos;
if object_id('socios') is not null
drop table socios;
create table socios(
numero int identity,
documento char(8),
nombre varchar(30),
domicilio varchar(30),
primary key (numero)
);

create table inscriptos (


numerosocio int not null,
deporte varchar(20) not null,
cuotas tinyint
constraint CK_inscriptos_cuotas
check (cuotas>=0 and cuotas<=10)
constraint DF_inscriptos_cuotas default 0,
primary key(numerosocio,deporte),
constraint FK_inscriptos_socio
foreign key (numerosocio)
references socios(numero)
on update cascade
on delete cascade,
);

insert into socios values('23333333','Alberto Paredes','Colon 111');


insert into socios values('24444444','Carlos Conte','Sarmiento 755');
insert into socios values('25555555','Fabian Fuentes','Caseros 987');
insert into socios values('26666666','Hector Lopez','Sucre 344');

insert into inscriptos values(1,'tenis',1);


insert into inscriptos values(1,'basquet',2);
insert into inscriptos values(1,'natacion',1);
insert into inscriptos values(2,'tenis',9);
insert into inscriptos values(2,'natacion',1);
insert into inscriptos values(2,'basquet',default);
insert into inscriptos values(2,'futbol',2);
insert into inscriptos values(3,'tenis',8);
insert into inscriptos values(3,'basquet',9);
insert into inscriptos values(3,'natacion',0);
insert into inscriptos values(4,'basquet',10);

select numero,nombre,deporte
from socios as s
join inscriptos as i
on numerosocio=numero;

select nombre
from socios
join inscriptos as i
on numero=numerosocio
where deporte='natacion' and
numero= any
(select numerosocio
from inscriptos as i
where deporte='tenis');

select deporte
from inscriptos as i
where numerosocio=1 and
deporte= any
(select deporte
from inscriptos as i
where numerosocio=2);

select i1.deporte
from inscriptos as i1
join inscriptos as i2
on i1.deporte=i2.deporte
where i1.numerosocio=1 and
i2.numerosocio=2;

select deporte
from inscriptos as i
where numerosocio=2 and
cuotas>any
(select cuotas
from inscriptos
where numerosocio=1);

select deporte
from inscriptos as i
where numerosocio=2 and
cuotas>all
(select cuotas
from inscriptos
where numerosocio=1);

delete from inscriptos


where numerosocio=any
(select numerosocio
from inscriptos
where cuotas=0);

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 ningn registro, es como un test de existencia; SQL
Server termina la recuperacin de registros cuando por lo menos un registro cumple la condicin
"where" de la subconsulta.

La sintaxis bsica es la siguiente:

... where exists (SUBCONSULTA);

En este ejemplo se usa una subconsulta correlacionada con un operador "exists" en la clusula
"where" para devolver una lista de clientes que compraron el artculo "lapiz":

select cliente,numero
from facturas as f
where exists
(select *from Detalles as d
where f.numero=d.numerofactura
and d.articulo='lapiz');

Puede obtener el mismo resultado empleando una combinacin.

Podemos buscar los clientes que no han adquirido el artculo "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 nmero de "socio", el cdigo del deporte en el cual
se inscribe
y la cantidad de cuotas pagas (desde 0 hasta 10 que es el total por todo el ao), 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)
);

create table inscriptos (


numerosocio int not null,
deporte varchar(20) not null,
cuotas tinyint
constraint CK_inscriptos_cuotas
check (cuotas>=0 and cuotas<=10)
constraint DF_inscriptos_cuotas default 0,
primary key(numerosocio,deporte),
constraint FK_inscriptos_socio
foreign key (numerosocio)
references socios(numero)
on update cascade
on delete cascade,
);

3- Ingrese algunos registros:


insert into socios values('23333333','Alberto Paredes','Colon 111');
insert into socios values('24444444','Carlos Conte','Sarmiento 755');
insert into socios values('25555555','Fabian Fuentes','Caseros 987');
insert into socios values('26666666','Hector Lopez','Sucre 344');

insert into inscriptos values(1,'tenis',1);


insert into inscriptos values(1,'basquet',2);
insert into inscriptos values(1,'natacion',1);
insert into inscriptos values(2,'tenis',9);
insert into inscriptos values(2,'natacion',1);
insert into inscriptos values(2,'basquet',default);
insert into inscriptos values(2,'futbol',2);
insert into inscriptos values(3,'tenis',8);
insert into inscriptos values(3,'basquet',9);
insert into inscriptos values(3,'natacion',0);
insert into inscriptos values(4,'basquet',10);

4- Emplee una subconsulta con el operador "exists" para devolver la lista de socios que
se
inscribieron en un determinado deporte.
3 registros.

5- Busque los socios que NO se han inscripto en un deporte determinado empleando


"not exists".
1 registro.

6- Muestre todos los datos de los socios que han pagado todas las cuotas.
1 registro.

if object_id('inscriptos') is not null


drop table inscriptos;
if object_id('socios') is not null
drop table socios;

create table socios(


numero int identity,
documento char(8),
nombre varchar(30),
domicilio varchar(30),
primary key (numero)
);

create table inscriptos (


numerosocio int not null,
deporte varchar(20) not null,
cuotas tinyint
constraint CK_inscriptos_cuotas
check (cuotas>=0 and cuotas<=10)
constraint DF_inscriptos_cuotas default 0,
primary key(numerosocio,deporte),
constraint FK_inscriptos_socio
foreign key (numerosocio)
references socios(numero)
on update cascade
on delete cascade,
);

insert into socios values('23333333','Alberto Paredes','Colon 111');


insert into socios values('24444444','Carlos Conte','Sarmiento 755');
insert into socios values('25555555','Fabian Fuentes','Caseros 987');
insert into socios values('26666666','Hector Lopez','Sucre 344');

insert into inscriptos values(1,'tenis',1);


insert into inscriptos values(1,'basquet',2);
insert into inscriptos values(1,'natacion',1);
insert into inscriptos values(2,'tenis',9);
insert into inscriptos values(2,'natacion',1);
insert into inscriptos values(2,'basquet',default);
insert into inscriptos values(2,'futbol',2);
insert into inscriptos values(3,'tenis',8);
insert into inscriptos values(3,'basquet',9);
insert into inscriptos values(3,'natacion',0);
insert into inscriptos values(4,'basquet',10);

select nombre
from socios as s
where exists
(select *from inscriptos as i
where s.numero=i.numerosocio
and i.deporte='natacion');

select nombre
from socios as s
where not exists
(select *from inscriptos as i
where s.numero=i.numerosocio
and i.deporte='natacion');

select s.*
from socios as s
where exists
(select *from inscriptos as i
where s.numero=i.numerosocio
and i.cuotas=10);

97 - Subconsulta simil autocombinacin

Algunas sentencias en las cuales la consulta interna y la externa emplean la misma tabla pueden
reemplazarse por una autocombinacin.

Por ejemplo, queremos una lista de los libros que han sido publicados por distintas editoriales.

select distinct l1.titulo


from libros as l1
where l1.titulo in
(select l2.titulo
from libros as l2
where l1.editorial <> l2.editorial);

En el ejemplo anterior empleamos una subconsulta correlacionada y las consultas interna y


externa emplean la misma tabla. La subconsulta devuelve una lista de valores por ello se emplea
"in" y sustituye una expresin en una clusula "where".

Con el siguiente "join" se obtiene el mismo resultado:

select distinct l1.titulo


from libros as l1
join libros as l2
on l1.titulo=l1.titulo and
l1.autor=l2.autor
where l1.editorial<>l2.editorial;

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');
La subconsulta retorna un solo valor.

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 evala la subconsulta, si el precio es mayor que el promedio.

97 - Subconsulta simil autocombinacin

Primer problema:

Un club dicta clases de distintos deportes a sus socios. El club tiene una tabla llamada
"deportes"
en la cual almacena el nombre del deporte, el nombre del profesor que lo dicta, el da
de la semana
que se dicta y el costo de la cuota mensual.
1- Elimine la tabla si existe:
if object_id('deportes') is not null
drop table deportes;

2- Cree la tabla:
create table deportes(
nombre varchar(15),
profesor varchar(30),
dia varchar(10),
cuota decimal(5,2),
);

3- Ingrese algunos registros. Incluya profesores que dicten ms de un curso:


insert into deportes values('tenis','Ana Lopez','lunes',20);
insert into deportes values('natacion','Ana Lopez','martes',15);
insert into deportes values('futbol','Carlos Fuentes','miercoles',10);
insert into deportes values('basquet','Gaston Garcia','jueves',15);
insert into deportes values('padle','Juan Huerta','lunes',15);
insert into deportes values('handball','Juan Huerta','martes',10);

4- Muestre los nombres de los profesores que dictan ms de un deporte empleando


subconsulta.

5- Obtenga el mismo resultado empleando join.

6- Buscamos todos los deportes que se dictan el mismo da que un determinado


deporte (natacion)
empleando subconsulta.

7- Obtenga la misma salida empleando "join".

98 - Subconsulta en lugar de una tabla

Se pueden emplear subconsultas que retornen un conjunto de registros de varios campos en lugar
de una tabla.

Se la denomina tabla derivada y se coloca en la clusula "from" para que la use un "select"
externo.

La tabla derivada debe ir entre parntesis y tener un alias para poder referenciarla. La sintaxis
bsica es la siguiente:

select ALIASdeTABLADERIVADA.CAMPO
from (TABLADERIVADA) as ALIAS;

La tabla derivada es una subsonsulta.

Podemos probar la consulta que retorna la tabla derivada y luego agregar el "select" externo:

select f.*,
(select sum(d.precio*cantidad)
from Detalles as d
where f.numero=d.numerofactura) as total
from facturas as f;

La consulta anterior contiene una subconsulta correlacionada; retorna todos los datos de
"facturas" y el monto total por factura de "detalles". Esta consulta retorna varios registros y varios
campos 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 nmero 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.

98 - Subconsulta en lugar de una tabla


Primer problema:

Un club dicta clases de distintos deportes. En una tabla llamada "socios" guarda los
datos de los
socios, en una tabla llamada "deportes" la informacin referente a los diferentes
deportes que se
dictan y en una tabla denominada "inscriptos", las inscripciones de los socios a los
distintos
deportes.
Un socio puede inscribirse en varios deportes el mismo ao. Un socio no puede
inscribirse en el
mismo deporte el mismo ao. Distintos socios se inscriben en un mismo deporte en el
mismo ao.

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('deportes') is not null
drop table deportes;

2- Cree las tablas con las siguientes estructuras:


create table socios(
documento char(8) not null,
nombre varchar(30),
domicilio varchar(30),
primary key(documento)
);
create table deportes(
codigo tinyint identity,
nombre varchar(20),
profesor varchar(15),
primary key(codigo)
);
create table inscriptos(
documento char(8) not null,
codigodeporte tinyint not null,
ao char(4),
matricula char(1),--'s'=paga, 'n'=impaga
primary key(documento,codigodeporte,ao),
constraint FK_inscriptos_socio
foreign key (documento)
references socios(documento)
on update cascade
on delete cascade
);

3- Ingrese algunos registros en las 3 tablas:


insert into socios values('22222222','Ana Acosta','Avellaneda 111');
insert into socios values('23333333','Betina Bustos','Bulnes 222');
insert into socios values('24444444','Carlos Castro','Caseros 333');
insert into socios values('25555555','Daniel Duarte','Dinamarca 44');

insert into deportes values('basquet','Juan Juarez');


insert into deportes values('futbol','Pedro Perez');
insert into deportes values('natacion','Marina Morales');
insert into deportes values('tenis','Marina Morales');

insert into inscriptos values ('22222222',3,'2006','s');


insert into inscriptos values ('23333333',3,'2006','s');
insert into inscriptos values ('24444444',3,'2006','n');
insert into inscriptos values ('22222222',3,'2005','s');
insert into inscriptos values ('22222222',3,'2007','n');
insert into inscriptos values ('24444444',1,'2006','s');
insert into inscriptos values ('24444444',2,'2006','s');

4- Realice una consulta en la cual muestre todos los datos de las inscripciones,
incluyendo el
nombre del deporte y del profesor.
Esta consulta es un join.

5- Utilice el resultado de la consulta anterior como una tabla derivada para emplear en
lugar de una
tabla para realizar un "join" y recuperar el nombre del socio, el deporte en el cual est
inscripto,
el ao, el nombre del profesor y la matrcula.

99 - Subconsulta (update - delete)

Dijimos que podemos emplear subconsultas en sentencias "insert", "update", "delete", adems de
"select".

La sintaxis bsica para realizar actualizaciones con subconsulta es la siguiente:

update TABLA set CAMPO=NUEVOVALOR


where CAMPO= (SUBCONSULTA);

Actualizamos el precio de todos los libros de editorial "Emece":

update libros set precio=precio+(precio*0.1)


where codigoeditorial=
(select codigo
from editoriales
where nombre='Emece');

La subconsulta retorna un nico valor. Tambin podemos hacerlo con un join.


La sintaxis bsica para realizar eliminaciones con subconsulta es la siguiente:

delete from TABLA


where CAMPO in (SUBCONSULTA);

Eliminamos todos los libros de las editoriales que tiene publicados libros de "Juan Perez":

delete from libros


where codigoeditorial in
(select e.codigo
from editoriales as e
join libros
on codigoeditorial=e.codigo
where autor='Juan Perez');

La subconsulta es una combinacin que retorna una lista de valores que la consulta externa
emplea al seleccionar los registros para la eliminacin.

99 - Subconsulta (update - delete)

Primer problema:

Un club dicta clases de distintos deportes a sus socios. El club tiene una tabla llamada
"inscriptos" en la cual almacena el nmero de "socio", el cdigo del deporte en el cual
se inscribe
y si la matricula est o no paga, 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)
);

create table inscriptos (


numerosocio int not null,
deporte varchar(20) not null,
matricula char(1),-- 'n' o 's'
primary key(numerosocio,deporte),
constraint FK_inscriptos_socio
foreign key (numerosocio)
references socios(numero)
);

3- Ingrese algunos registros:


insert into socios values('23333333','Alberto Paredes','Colon 111');
insert into socios values('24444444','Carlos Conte','Sarmiento 755');
insert into socios values('25555555','Fabian Fuentes','Caseros 987');
insert into socios values('26666666','Hector Lopez','Sucre 344');

insert into inscriptos values(1,'tenis','s');


insert into inscriptos values(1,'basquet','s');
insert into inscriptos values(1,'natacion','s');
insert into inscriptos values(2,'tenis','s');
insert into inscriptos values(2,'natacion','s');
insert into inscriptos values(2,'basquet','n');
insert into inscriptos values(2,'futbol','n');
insert into inscriptos values(3,'tenis','s');
insert into inscriptos values(3,'basquet','s');
insert into inscriptos values(3,'natacion','n');
insert into inscriptos values(4,'basquet','n');

4- Actualizamos la cuota ('s') de todas las inscripciones de un socio determinado (por


documento)
empleando subconsulta.

5- Elimine todas las inscripciones de los socios que deben alguna matrcula.
5 registros eliminados.

100 - Subconsulta (insert)

Aprendimos que una subconsulta puede estar dentro de un "select", "update" y "delete"; tambin
puede estar dentro de un "insert".

Podemos ingresar registros en una tabla empleando un "select".

La sintaxis bsica es la siguiente:

insert into TABLAENQUESEINGRESA (CAMPOSTABLA1)


select (CAMPOSTABLACONSULTADA)
from TABLACONSULTADA;

Un profesor almacena las notas de sus alumnos en una tabla llamada "alumnos". Tiene otra tabla
llamada "aprobados", con algunos campos iguales a la tabla "alumnos" pero en ella solamente
almacenar los alumnos que han aprobado el ciclo.

Ingresamos registros en la tabla "aprobados" seleccionando registros de la tabla "alumnos":

insert into aprobados (documento,nota)


select (documento,nota)
from alumnos;

Entonces, se puede insertar registros en una tabla con la salida devuelta por una consulta a 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 cargarn (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".

100 - Subconsulta (insert)

Primer problema:

Un comercio que vende artculos de librera y papelera almacena la informacin de sus


ventas en una
tabla llamada "facturas" y otra "clientes".
1- Elimine las tablas si existen:
if object_id('facturas') is not null
drop table facturas;
if object_id('clientes') is not null
drop table clientes;

2-Crelas:
create table clientes(
codigo int identity,
nombre varchar(30),
domicilio varchar(30),
primary key(codigo)
);

create table facturas(


numero int not null,
fecha datetime,
codigocliente int not null,
total decimal(6,2),
primary key(numero),
constraint FK_facturas_cliente
foreign key (codigocliente)
references clientes(codigo)
on update cascade
);

3-Ingrese algunos registros:


insert into clientes values('Juan Lopez','Colon 123');
insert into clientes values('Luis Torres','Sucre 987');
insert into clientes values('Ana Garcia','Sarmiento 576');
insert into clientes values('Susana Molina','San Martin 555');

insert into facturas values(1200,'2007-01-15',1,300);


insert into facturas values(1201,'2007-01-15',2,550);
insert into facturas values(1202,'2007-01-15',3,150);
insert into facturas values(1300,'2007-01-20',1,350);
insert into facturas values(1310,'2007-01-22',3,100);

4- El comercio necesita una tabla llamada "clientespref" en la cual quiere almacenar el


nombre y
domicilio de aquellos clientes que han comprado hasta el momento ms de 500 pesos
en mercaderas.
Elimine la tabla si existe y crela con esos 2 campos:
if object_id ('clientespref') is not null
drop table clientespref;
create table clientespref(
nombre varchar(30),
domicilio varchar(30)
);

5- Ingrese los registros en la tabla "clientespref" seleccionando registros de la tabla


"clientes" y
"facturas".

6- Vea los registros de "clientespref":


select *from clientespref;