Base de Datos SQL

135
1 - OBJETIVOS Y ALCANCES DEL TUTORIAL DE MICROSOFT SQL SERVER EL CURSO BRINDA UN CONCEPTO TEÓRICO CORTO, LUEGO UN PROBLEMA RESUELTO QUE INVITO A EJECUTAR, MODIFICAR Y JUGAR CON EL MISMO. POR ÚLTIMO, Y LO MÁS IMPORTANTE, UNA SERIE DE EJERCICIOS PROPUESTOS QUE NOS PERMITIRÁ SABER SI PODEMOS APLICAR EL CONCEPTO. LA ÚNICA HERRAMIENTA QUE NECESITAMOS INICIALMENTE ES ESTE SITIO YA QUE PODRÁ EJECUTAR TODOS LOS PROBLEMAS COMO SON LA CREACIÓN DE TABLAS, INSERT, DELETE, UPDATE, DEFINICIÓN DE ÍNDICES Y RESTRICCIONES, CREACIÓN Y EJECUCIÓN DE PROCEDIMIENTOS ALMACENADOS, VISTAS, SUBCONSULTAS, CREACIÓN DE TRIGGER ETC. LA ÚNICA RESTRICCIÓN ES QUE TODOS LOS VISITANTES DE ESTE SITIO COMPARTEN LA MISMA BASE DE DATOS LLAMADA: WI520641_SQLSERVERYA (ESTE NOMBRE UN POCO SINGULAR SE DEBE A QUE LAS EMPRESAS DE HOSTING ES LA QUE LO DEFINE) SIEMPRE QUE LANCEMOS UN COMANDO SQL EN EL SITIO WWW. SQLSERVERYA. COM. AR ESTAREMOS ACCEDIENDO A LA BASE DE DATOS WI 520641_SQLSERVERYA 2 - CREAR UNA TABLA (CREATE TABLE - SP_TABLES - SP_COLUMNS - DROP TABLE) UNA BASE DE DATOS ALMACENA SU INFORMACIÓN EN TABLAS. UNA TABLA ES UNA ESTRUCTURA DE DATOS QUE ORGANIZA LOS DATOS EN COLUMNAS Y FILAS; CADA COLUMNA ES UN CAMPO (O ATRIBUTO) Y CADA FILA, UN REGISTRO. LA INTERSECCIÓN DE UNA COLUMNA CON UNA FILA, CONTIENE UN DATO ESPECÍFICO, UN SOLO VALOR. CADA REGISTRO CONTIENE UN DATO POR CADA COLUMNA DE LA TABLA. CADA CAMPO (COLUMNA) DEBE TENER UN NOMBRE. EL NOMBRE DEL CAMPO HACE REFERENCIA A LA INFORMACIÓN QUE ALMACENARÁ. CADA CAMPO (COLUMNA) TAMBIÉN DEBE DEFINIR EL TIPO DE DATO QUE ALMACENARÁ. LAS TABLAS FORMAN PARTE DE UNA BASE DE DATOS. NOSOTROS TRABAJAREMOS CON LA BASE DE DATOS LLAMADA WI 520641_SQLSERVERYA (ESTE NOMBRE SE DEBE A QUE LAS EMPRESAS DE HOSTING ES LA QUE LO DEFINE ), QUE YA HE CREADO EN EL SERVIDOR SQLSERVERYA. COM. AR. PARA VER LAS TABLAS EXISTENTES CREADAS POR LOS USUARIOS EN UNA BASE DE DATOS USAMOS EL PROCEDIMIENTO ALMACENADO "SP_TABLES @TABLE_OWNER='DBO';": SP_TABLES @TABLE_OWNER='DBO'; EL PARÁMETRO @TABLE_OWNER='DBO' INDICA QUE SOLO MUESTRE LAS TABLAS DE USUARIOS Y NO LAS QUE CREA EL SQL SERVER PARA ADMINISTRACIÓN INTERNA. FINALIZAMOS CADA COMANDO CON UN PUNTO Y COMA.

Transcript of Base de Datos SQL

Page 1: Base de Datos SQL

1 - OBJETIVOS Y ALCANCES DEL TUTORIAL DE

MICROSOFT SQL SERVER

EL CURSO BRINDA UN CONCEPTO TEÓRICO CORTO, LUEGO UN PROBLEMA RESUELTO QUE INVITO A EJECUTAR, MODIFICAR Y JUGAR

CON EL MISMO. POR ÚLTIMO, Y LO MÁS IMPORTANTE, UNA SERIE DE EJERCICIOS PROPUESTOS QUE NOS PERMITIRÁ SABER SI

PODEMOS APLICAR EL CONCEPTO.

LA ÚNICA HERRAMIENTA QUE NECESITAMOS INICIALMENTE ES ESTE SITIO YA QUE PODRÁ EJECUTAR TODOS LOS PROBLEMAS COMO

SON LA CREACIÓN DE TABLAS, INSERT, DELETE, UPDATE, DEFINICIÓN DE ÍNDICES Y RESTRICCIONES, CREACIÓN Y EJECUCIÓN DE

PROCEDIMIENTOS ALMACENADOS, VISTAS, SUBCONSULTAS, CREACIÓN DE TRIGGER ETC.

LA ÚNICA RESTRICCIÓN ES QUE TODOS LOS VISITANTES DE ESTE SITIO COMPARTEN LA MISMA BASE DE DATOS LLAMADA:

WI520641_SQLSERVERYA (ESTE NOMBRE UN POCO SINGULAR SE DEBE A QUE LAS EMPRESAS DE HOSTING ES LA QUE LO DEFINE)

SIEMPRE QUE LANCEMOS UN COMANDO SQL EN EL SITIO WWW.SQLSERVERYA.COM.AR ESTAREMOS ACCEDIENDO A LA BASE DE

DATOS WI520641_SQLSERVERYA

2 - CREAR UNA TABLA (CREATE TABLE - SP_TABLES - SP_COLUMNS - DROP TABLE)

UNA BASE DE DATOS ALMACENA SU INFORMACIÓN EN TABLAS.

UNA TABLA ES UNA ESTRUCTURA DE DATOS QUE ORGANIZA LOS DATOS EN COLUMNAS Y FILAS; CADA COLUMNA ES UN CAMPO (O

ATRIBUTO) Y CADA FILA, UN REGISTRO. LA INTERSECCIÓN DE UNA COLUMNA CON UNA FILA, CONTIENE UN DATO ESPECÍFICO, UN

SOLO VALOR.

CADA REGISTRO CONTIENE UN DATO POR CADA COLUMNA DE LA TABLA. CADA CAMPO (COLUMNA) DEBE TENER UN NOMBRE. EL NOMBRE DEL CAMPO HACE REFERENCIA A LA INFORMACIÓN QUE

ALMACENARÁ. CADA CAMPO (COLUMNA) TAMBIÉN DEBE DEFINIR EL TIPO DE DATO QUE ALMACENARÁ.

LAS TABLAS FORMAN PARTE DE UNA BASE DE DATOS.

NOSOTROS TRABAJAREMOS CON LA BASE DE DATOS LLAMADA WI520641_SQLSERVERYA (ESTE NOMBRE SE DEBE A QUE LAS

EMPRESAS DE HOSTING ES LA QUE LO DEFINE), QUE YA HE CREADO EN EL SERVIDOR SQLSERVERYA.COM.AR.

PARA VER LAS TABLAS EXISTENTES CREADAS POR LOS USUARIOS EN UNA BASE DE DATOS USAMOS EL PROCEDIMIENTO ALMACENADO

"SP_TABLES @TABLE_OWNER='DBO';":

SP_TABLES @TABLE_OWNER='DBO';

EL PARÁMETRO @TABLE_OWNER='DBO' INDICA QUE SOLO MUESTRE LAS TABLAS DE USUARIOS Y NO LAS QUE CREA EL SQL SERVER

PARA ADMINISTRACIÓN INTERNA.

FINALIZAMOS CADA COMANDO CON UN PUNTO Y COMA.

Page 2: Base de Datos SQL

AL CREAR UNA TABLA DEBEMOS RESOLVER QUÉ CAMPOS (COLUMNAS) TENDRÁ Y QUE TIPO DE DATOS ALMACENARÁN CADA UNO DE

ELLOS, ES DECIR, SU ESTRUCTURA.

LA SINTAXIS BÁSICA Y GENERAL PARA CREAR UNA TABLA ES LA SIGUIENTE:

CREATE TABLE NOMBRETABLA( NOMBRECAMPO1 TIPODEDATO, ... NOMBRECAMPON TIPODEDATO );

LA TABLA DEBE SER DEFINIDA CON UN NOMBRE QUE LA IDENTIFIQUE Y CON EL CUAL ACCEDEREMOS A ELLA.

CREAMOS UNA TABLA LLAMADA "USUARIOS" Y ENTRE PARÉNTESIS DEFINIMOS LOS CAMPOS Y SUS TIPOS:

CREATE TABLE USUARIOS ( NOMBRE VARCHAR(30), CLAVE VARCHAR(10) );

CADA CAMPO CON SU TIPO DEBE SEPARARSE CON COMAS DE LOS SIGUIENTES, EXCEPTO EL ÚLTIMO.

CUANDO SE CREA UNA TABLA DEBEMOS INDICAR SU NOMBRE Y DEFINIR AL MENOS UN CAMPO CON SU TIPO DE DATO. EN ESTA TABLA

"USUARIOS" DEFINIMOS 2 CAMPOS:

NOMBRE: QUE CONTENDRÁ UNA CADENA DE CARACTERES DE 30 CARACTERES DE LONGITUD, QUE ALMACENARÁ EL NOMBRE

DE USUARIO Y CLAVE: OTRA CADENA DE CARACTERES DE 10 DE LONGITUD, QUE GUARDARÁ LA CLAVE DE CADA USUARIO.

CADA USUARIO OCUPARÁ UN REGISTRO DE ESTA TABLA, CON SU RESPECTIVO NOMBRE Y CLAVE.

PARA NOMBRES DE TABLAS, SE PUEDE UTILIZAR CUALQUIER CARACTER PERMITIDO PARA NOMBRES DE DIRECTORIOS, EL PRIMERO

DEBE SER UN CARACTER ALFABÉTICO Y NO PUEDE CONTENER ESPACIOS. LA LONGITUD MÁXIMA ES DE 128 CARACTERES.

SI INTENTAMOS CREAR UNA TABLA CON UN NOMBRE YA EXISTENTE (EXISTE OTRA TABLA CON ESE NOMBRE), MOSTRARÁ UN MENSAJE

INDICANDO QUE YA HAY UN OBJETO LLAMADO 'USUARIOS' EN LA BASE DE DATOS Y LA SENTENCIA NO SE EJECUTARÁ. ESTO ES MUY

IMPORTANTE YA QUE CUANDO HAGA LOS EJERCICIOS EN ESTE SITIO PUEDE HABER OTRA PERSONA QUE HAYA CREADO UNA TABLA CON

EL NOMBRE QUE USTED ESPECIFIQUE.

PARA VER LA ESTRUCTURA DE UNA TABLA USAMOS EL PROCEDIMIENTO ALMACENADO "SP_COLUMNS" JUNTO AL NOMBRE DE LA

TABLA:

SP_COLUMNS USUARIOS;

APARECE MUCHA INFORMACIÓN QUE NO ANALIZAREMOS EN DETALLE, COMO EL NOMBRE DE LA TABLA, SU PROPIETARIO, LOS

CAMPOS, EL TIPO DE DATO DE CADA CAMPO, SU LONGITUD, ETC.:

...COLUMN_NAME TYPE_NAME LENGHT _______________________________________ NOMBRE VARCHAR 30 CLAVE VARCHAR 10

Page 3: Base de Datos SQL

PARA ELIMINAR UNA TABLA USAMOS "DROP TABLE" JUNTO AL NOMBRE DE LA TABLA A ELIMINAR:

DROP TABLE USUARIOS;

SI INTENTAMOS ELIMINAR UNA TABLA QUE NO EXISTE, APARECE UN MENSAJE DE ERROR INDICANDO TAL SITUACIÓN Y LA SENTENCIA

NO SE EJECUTA. PARA EVITAR ESTE MENSAJE PODEMOS AGREGAR A LA INSTRUCCIÓN LO SIGUIENTE:

IF OBJECT_ID('USUARIOS') IS NOT NULL DROP TABLE USUARIOS;

EN LA SENTENCIA PRECEDENTE ESPECIFICAMOS QUE ELIMINE LA TABLA "USUARIOS" SI EXISTE.

3 - INSERTAR Y RECUPERAR REGISTROS DE UNA TABLA

(INSERT INTO - SELECT)

UN REGISTRO ES UNA FILA DE LA TABLA QUE CONTIENE LOS DATOS PROPIAMENTE DICHOS. CADA

REGISTRO TIENE UN DATO POR CADA COLUMNA (CAMPO). NUESTRA TABLA "USUARIOS" CONSTA DE 2

CAMPOS, "NOMBRE" Y "CLAVE".

AL INGRESAR LOS DATOS DE CADA REGISTRO DEBE TENERSE EN CUENTA LA CANTIDAD Y EL ORDEN DE LOS CAMPOS.

LA SINTAXIS BÁSICA Y GENERAL ES LA SIGUIENTE:

INSERT INTO NOMBRETABLA (NOMBRECAMPO1, ..., NOMBRECAMPON) VALUES (VALORCAMPO1, ..., VALORCAMPON);

USAMOS "INSERT INTO", LUEGO EL NOMBRE DE LA TABLA, DETALLAMOS LOS NOMBRES DE LOS CAMPOS ENTRE PARÉNTESIS Y

SEPARADOS POR COMAS Y LUEGO DE LA CLÁUSULA "VALUES" COLOCAMOS LOS VALORES PARA CADA CAMPO, TAMBIÉN ENTRE

PARÉNTESIS Y SEPARADOS POR COMAS.

PARA AGREGAR UN REGISTRO A LA TABLA TIPEAMOS:

INSERT INTO USUARIOS (NOMBRE, CLAVE) VALUES ('MARIANO','PAYASO');

NOTE QUE LOS DATOS INGRESADOS, COMO CORRESPONDEN A CADENAS DE CARACTERES SE COLOCAN ENTRE COMILLAS SIMPLES.

PARA VER LOS REGISTROS DE UNA TABLA USAMOS "SELECT":

SELECT * FROM USUARIOS;

EL COMANDO "SELECT" RECUPERA LOS REGISTROS DE UNA TABLA. CON EL ASTERISCO INDICAMOS QUE MUESTRE TODOS LOS CAMPOS DE LA TABLA "USUARIOS".

ES IMPORTANTE INGRESAR LOS VALORES EN EL MISMO ORDEN EN QUE SE NOMBRAN LOS CAMPOS:

INSERT INTO USUARIOS (CLAVE, NOMBRE) VALUES ('RIVER','JUAN');

Page 4: Base de Datos SQL

EN EL EJEMPLO ANTERIOR SE NOMBRA PRIMERO EL CAMPO "CLAVE" Y LUEGO EL CAMPO "NOMBRE" POR ESO, LOS VALORES TAMBIÉN

SE COLOCAN EN ESE ORDEN.

SI INGRESAMOS LOS DATOS EN UN ORDEN DISTINTO AL ORDEN EN QUE SE NOMBRARON LOS CAMPOS, NO APARECE UN MENSAJE DE

ERROR Y LOS DATOS SE GUARDAN DE MODO INCORRECTO.

EN EL SIGUIENTE EJEMPLO SE COLOCAN LOS VALORES EN DISTINTO ORDEN EN QUE SE NOMBRAN LOS CAMPOS, EL VALOR DE LA CLAVE

(LA CADENA "BOCA") SE GUARDARÁ EN EL CAMPO "NOMBRE" Y EL VALOR DEL NOMBRE (LA CADENA "LUIS") EN EL CAMPO "CLAVE":

INSERT INTO USUARIOS (NOMBRE,CLAVE) VALUES ('BOCA','LUIS');

4 - TIPOS DE DATOS BÁSICOS

YA EXPLICAMOS QUE AL CREAR UNA TABLA DEBEMOS RESOLVER QUÉ CAMPOS (COLUMNAS) TENDRÁ Y QUE TIPO DE DATOS

ALMACENARÁ CADA UNO DE ELLOS, ES DECIR, SU ESTRUCTURA.

EL TIPO DE DATO ESPECIFICA EL TIPO DE INFORMACIÓN QUE PUEDE GUARDAR UN CAMPO: CARACTERES, NÚMEROS, ETC.

ESTOS SON ALGUNOS TIPOS DE DATOS BÁSICOS DE SQL SERVER (POSTERIORMENTE VEREMOS OTROS):

VARCHAR: SE USA PARA ALMACENAR CADENAS DE CARACTERES. UNA CADENA ES UNA SECUENCIA DE CARACTERES. SE

COLOCA ENTRE COMILLAS (SIMPLES); EJEMPLO: 'HOLA', 'JUAN PEREZ'. EL TIPO "VARCHAR" DEFINE UNA CADENA DE

LONGITUD VARIABLE EN LA CUAL DETERMINAMOS EL MÁXIMO DE CARACTERES ENTRE PARÉNTESIS. PUEDE GUARDAR HASTA

8000 CARACTERES. POR EJEMPLO, PARA ALMACENAR CADENAS DE HASTA 30 CARACTERES, DEFINIMOS UN CAMPO DE TIPO

VARCHAR(30), ES DECIR, ENTRE PARÉNTESIS, JUNTO AL NOMBRE DEL CAMPO COLOCAMOS LA LONGITUD. SI ASIGNAMOS UNA CADENA DE CARACTERES DE MAYOR LONGITUD QUE LA DEFINIDA, LA CADENA NO SE CARGA, APARECE

UN MENSAJE INDICANDO TAL SITUACIÓN Y LA SENTENCIA NO SE EJECUTA. POR EJEMPLO, SI DEFINIMOS UN CAMPO DE TIPO VARCHAR(10) E INTENTAMOS ASIGNARLE LA CADENA 'BUENAS TARDES', APARECE UN MENSAJE DE ERROR Y LA SENTENCIA NO SE EJECUTA.

INTEGER: SE USA PARA GUARDAR VALORES NUMÉRICOS ENTEROS, DE -2000000000 A 2000000000 APROX. DEFINIMOS

CAMPOS DE ESTE TIPO CUANDO QUEREMOS REPRESENTAR, POR EJEMPLO, CANTIDADES. FLOAT: SE USA PARA ALMACENAR VALORES NUMÉRICOS CON DECIMALES. SE UTILIZA COMO SEPARADOR EL PUNTO (.).

DEFINIMOS CAMPOS DE ESTE TIPO PARA PRECIOS, POR EJEMPLO.

ANTES DE CREAR UNA TABLA DEBEMOS PENSAR EN SUS CAMPOS Y OPTAR POR EL TIPO DE DATO ADECUADO PARA CADA UNO DE

ELLOS. POR EJEMPLO, SI EN UN CAMPO ALMACENAREMOS NÚMEROS ENTEROS, EL TIPO "FLOAT" SERÍA UNA MALA ELECCIÓN; SI VAMOS A

GUARDAR PRECIOS, EL TIPO "FLOAT" ES MÁS ADECUADO, NO ASÍ "INTEGER" QUE NO TIENE DECIMALES. OTRO EJEMPLO, SI EN UN

CAMPO VAMOS A GUARDAR UN NÚMERO TELEFÓNICO O UN NÚMERO DE DOCUMENTO, USAMOS "VARCHAR", NO "INTEGER"

PORQUE SI BIEN SON DÍGITOS, CON ELLOS NO REALIZAMOS OPERACIONES MATEMÁTICAS.

5 - RECUPERAR ALGUNOS CAMPOS (SELECT)

HEMOS APRENDIDO CÓMO VER TODOS LOS REGISTROS DE UNA TABLA, EMPLEANDO LA INSTRUCCIÓN "SELECT".

LA SINTAXIS BÁSICA Y GENERAL ES LA SIGUIENTE:

SELECT * FROM NOMBRETABLA;

Page 5: Base de Datos SQL

EL ASTERISCO (*) INDICA QUE SE SELECCIONAN TODOS LOS CAMPOS DE LA TABLA.

PODEMOS ESPECIFICAR EL NOMBRE DE LOS CAMPOS QUE QUEREMOS VER SEPARÁNDOLOS POR COMAS:

SELECT TITULO,AUTOR FROM LIBROS;

LA LISTA DE CAMPOS LUEGO DEL "SELECT" SELECCIONA LOS DATOS CORRESPONDIENTES A LOS CAMPOS NOMBRADOS. EN EL EJEMPLO

ANTERIOR SELECCIONAMOS LOS CAMPOS "TITULO" Y "AUTOR" DE LA TABLA "LIBROS", MOSTRANDO TODOS LOS REGISTROS. LOS

DATOS APARECEN ORDENADOS SEGÚN LA LISTA DE SELECCIÓN, EN DICHA LISTA LOS NOMBRES DE LOS CAMPOS SE SEPARAN CON

COMAS.

6 - RECUPERAR ALGUNOS REGISTROS (WHERE)

HEMOS APRENDIDO A SELECCIONAR ALGUNOS CAMPOS DE UNA TABLA. TAMBIÉN ES POSIBLE RECUPERAR ALGUNOS REGISTROS.

EXISTE UNA CLÁUSULA, "WHERE" CON LA CUAL PODEMOS ESPECIFICAR CONDICIONES PARA UNA CONSULTA "SELECT". ES DECIR, PODEMOS RECUPERAR ALGUNOS REGISTROS, SÓLO LOS QUE CUMPLAN CON CIERTAS CONDICIONES INDICADAS CON LA CLÁUSULA

"WHERE". POR EJEMPLO, QUEREMOS VER EL USUARIO CUYO NOMBRE ES "MARCELO", PARA ELLO UTILIZAMOS "WHERE" Y LUEGO DE

ELLA, LA CONDICIÓN:

SELECT NOMBRE, CLAVE FROM USUARIOS WHERE NOMBRE='MARCELO';

LA SINTAXIS BÁSICA Y GENERAL ES LA SIGUIENTE:

SELECT NOMBRECAMPO1, ..., NOMBRECAMPON FROM NOMBRETABLA WHERE CONDICION;

PARA LAS CONDICIONES SE UTILIZAN OPERADORES RELACIONALES (TEMA QUE TRATAREMOS MÁS ADELANTE EN DETALLE). EL SIGNO

IGUAL(=) ES UN OPERADOR RELACIONAL. PARA LA SIGUIENTE SELECCIÓN DE REGISTROS ESPECIFICAMOS UNA CONDICIÓN QUE SOLICITA LOS USUARIOS CUYA CLAVE ES IGUAL A

"RIVER":

SELECT NOMBRE,CLAVE FROM USUARIOS WHERE CLAVE='RIVER';

SI NINGÚN REGISTRO CUMPLE LA CONDICIÓN ESTABLECIDA CON EL "WHERE", NO APARECERÁ NINGÚN REGISTRO.

ENTONCES, CON "WHERE" ESTABLECEMOS CONDICIONES PARA RECUPERAR ALGUNOS REGISTROS.

PARA RECUPERAR ALGUNOS CAMPOS DE ALGUNOS REGISTROS COMBINAMOS EN LA CONSULTA LA LISTA DE CAMPOS Y LA CLÁUSULA

"WHERE":

SELECT NOMBRE FROM USUARIOS WHERE CLAVE='RIVER';

Page 6: Base de Datos SQL

EN LA CONSULTA ANTERIOR SOLICITAMOS EL NOMBRE DE TODOS LOS USUARIOS CUYA CLAVE SEA IGUAL A "RIVER".

7 - OPERADORES RELACIONALES

LOS OPERADORES SON SÍMBOLOS QUE PERMITEN REALIZAR OPERACIONES MATEMÁTICAS, CONCATENAR CADENAS, HACER

COMPARACIONES.

SQL SERVER TIENE 4 TIPOS DE OPERADORES:

1. RELACIONALES (O DE COMPARACIÓN) 2. ARITMÉTICOS 3. DE CONCATENACIÓN 4. LÓGICOS.

POR AHORA VEREMOS SOLAMENTE LOS PRIMEROS.

LOS OPERADORES RELACIONALES (O DE COMPARACIÓN) NOS PERMITEN COMPARAR DOS EXPRESIONES, QUE PUEDEN SER VARIABLES, VALORES DE CAMPOS, ETC.

HEMOS APRENDIDO A ESPECIFICAR CONDICIONES DE IGUALDAD PARA SELECCIONAR REGISTROS DE UNA TABLA; POR EJEMPLO:

SELECT *FROM LIBROS WHERE AUTOR='BORGES';

UTILIZAMOS EL OPERADOR RELACIONAL DE IGUALDAD.

LOS OPERADORES RELACIONALES VINCULAN UN CAMPO CON UN VALOR PARA QUE SQL SERVER COMPARE CADA REGISTRO (EL

CAMPO ESPECIFICADO) CON EL VALOR DADO.

LOS OPERADORES RELACIONALES SON LOS SIGUIENTES:

= IGUAL <> DISTINTO > MAYOR < MENOR >= MAYOR O IGUAL <= MENOR O IGUAL

PODEMOS SELECCIONAR LOS REGISTROS CUYO AUTOR SEA DIFERENTE DE "BORGES", PARA ELLO USAMOS LA CONDICIÓN:

SELECT * FROM LIBROS WHERE AUTOR<>'BORGES';

PODEMOS COMPARAR VALORES NUMÉRICOS. POR EJEMPLO, QUEREMOS MOSTRAR LOS TÍTULOS Y PRECIOS DE LOS LIBROS CUYO

PRECIO SEA MAYOR A 20 PESOS:

SELECT TITULO, PRECIO FROM LIBROS WHERE PRECIO>20;

QUEREMOS SELECCIONAR LOS LIBROS CUYO PRECIO SEA MENOR O IGUAL A 30:

Page 7: Base de Datos SQL

SELECT *FROM LIBROS WHERE PRECIO<=30;

LOS OPERADORES RELACIONALES COMPARAN VALORES DEL MISMO TIPO. SE EMPLEAN PARA COMPROBAR SI UN CAMPO CUMPLE CON

UNA CONDICIÓN.

NO SON LOS ÚNICOS, EXISTEN OTROS QUE VEREMOS MAS ADELANTE.

8 - BORRAR REGISTROS (DELETE)

PARA ELIMINAR LOS REGISTROS DE UNA TABLA USAMOS EL COMANDO "DELETE":

DELETE FROM USUARIOS;

MUESTRA UN MENSAJE INDICANDO LA CANTIDAD DE REGISTROS QUE HA ELIMINADO.

SI NO QUEREMOS ELIMINAR TODOS LOS REGISTROS, SINO SOLAMENTE ALGUNOS, DEBEMOS INDICAR CUÁL O CUÁLES, PARA ELLO

UTILIZAMOS EL COMANDO "DELETE" JUNTO CON LA CLAUSULA "WHERE" CON LA CUAL ESTABLECEMOS LA CONDICIÓN QUE DEBEN

CUMPLIR LOS REGISTROS A BORRAR.

POR EJEMPLO, QUEREMOS ELIMINAR AQUEL REGISTRO CUYO NOMBRE DE USUARIO ES "MARCELO":

DELETE FROM USUARIOS WHERE NOMBRE='MARCELO';

SI SOLICITAMOS EL BORRADO DE UN REGISTRO QUE NO EXISTE, ES DECIR, NINGÚN REGISTRO CUMPLE CON LA CONDICIÓN

ESPECIFICADA, NINGÚN REGISTRO SERÁ ELIMINADO.

TENGA EN CUENTA QUE SI NO COLOCAMOS UNA CONDICIÓN, SE ELIMINAN TODOS LOS REGISTROS DE LA TABLA NOMBRADA.

9 - ACTUALIZAR REGISTROS (UPDATE)

DECIMOS QUE ACTUALIZAMOS UN REGISTRO CUANDO MODIFICAMOS ALGUNO DE SUS VALORES.

PARA MODIFICAR UNO O VARIOS DATOS DE UNO O VARIOS REGISTROS UTILIZAMOS "UPDATE" (ACTUALIZAR).

POR EJEMPLO, EN NUESTRA TABLA "USUARIOS", QUEREMOS CAMBIAR LOS VALORES DE TODAS LAS CLAVES, POR "REALMADRID":

UPDATE USUARIOS SET CLAVE='REALMADRID';

UTILIZAMOS "UPDATE" JUNTO AL NOMBRE DE LA TABLA Y "SET" JUNTO CON EL CAMPO A MODIFICAR Y SU NUEVO VALOR.

EL CAMBIO AFECTARÁ A TODOS LOS REGISTROS.

PODEMOS MODIFICAR ALGUNOS REGISTROS, PARA ELLO DEBEMOS ESTABLECER CONDICIONES DE SELECCIÓN CON "WHERE". POR EJEMPLO, QUEREMOS CAMBIAR EL VALOR CORRESPONDIENTE A LA CLAVE DE NUESTRO USUARIO LLAMADO "FEDERICOLOPEZ", QUEREMOS COMO NUEVA CLAVE "BOCA", NECESITAMOS UNA CONDICIÓN "WHERE" QUE AFECTE SOLAMENTE A ESTE REGISTRO:

UPDATE USUARIOS SET CLAVE='BOCA'

Page 8: Base de Datos SQL

WHERE NOMBRE='FEDERICOLOPEZ';

SI MICROSOFT SQL SERVER NO ENCUENTRA REGISTROS QUE CUMPLAN CON LA CONDICIÓN DEL "WHERE", NO SE MODIFICA

NINGUNO.

LAS CONDICIONES NO SON OBLIGATORIAS, PERO SI OMITIMOS LA CLÁUSULA "WHERE", LA ACTUALIZACIÓN AFECTARÁ A TODOS LOS

REGISTROS.

TAMBIÉN PODEMOS ACTUALIZAR VARIOS CAMPOS EN UNA SOLA INSTRUCCIÓN:

UPDATE USUARIOS SET NOMBRE='MARCELODUARTE', CLAVE='MARCE' WHERE NOMBRE='MARCELO';

PARA ELLO COLOCAMOS "UPDATE", EL NOMBRE DE LA TABLA, "SET" JUNTO AL NOMBRE DEL CAMPO Y EL NUEVO VALOR Y SEPARADO

POR COMA, EL OTRO NOMBRE DEL CAMPO CON SU NUEVO VALOR.

10 - COMENTARIOS

PARA ACLARAR ALGUNAS INSTRUCCIONES, EN OCASIONES, NECESITAMOS AGREGAR COMENTARIOS. ES POSIBLE INGRESAR COMENTARIOS EN LA LÍNEA DE COMANDOS, ES DECIR, UN TEXTO QUE NO SE EJECUTA; PARA ELLO SE EMPLEAN

DOS GUIONES (--) AL COMIENZO DE LA LÍNEA:

SELECT * FROM LIBROS --MOSTRAMOS LOS REGISTROS DE LIBROS;

EN LA LÍNEA ANTERIOR, TODO LO QUE ESTÁ LUEGO DE LOS GUIONES (HACIA LA DERECHA) NO SE EJECUTA.

PARA AGREGAR VARIAS LÍNEAS DE COMENTARIOS, SE COLOCA UNA BARRA SEGUIDA DE UN ASTERISCO (/*) AL COMIENZO DEL

BLOQUE DE COMENTARIO Y AL FINALIZARLO, UN ASTERISCO SEGUIDO DE UNA BARRA (*/).

SELECT TITULO, AUTOR /*MOSTRAMOS TÍTULOS Y NOMBRES DE LOS AUTORES*/ FROM LIBROS;

TODO LO QUE ESTÁ ENTRE LOS SÍMBOLOS "/*" Y "*/" NO SE EJECUTA.

11 - VALORES NULL (IS NULL)

"NULL" SIGNIFICA "DATO DESCONOCIDO" O "VALOR INEXISTENTE". NO ES LO MISMO QUE UN VALOR "0", UNA CADENA VACÍA O

UNA CADENA LITERAL "NULL".

A VECES, PUEDE DESCONOCERSE O NO EXISTIR EL DATO CORRESPONDIENTE A ALGÚN CAMPO DE UN REGISTRO. EN ESTOS CASOS

DECIMOS QUE EL CAMPO PUEDE CONTENER VALORES NULOS.

POR EJEMPLO, EN NUESTRA TABLA DE LIBROS, PODEMOS TENER VALORES NULOS EN EL CAMPO "PRECIO" PORQUE ES POSIBLE QUE

PARA ALGUNOS LIBROS NO LE HAYAMOS ESTABLECIDO EL PRECIO PARA LA VENTA.

EN CONTRAPOSICIÓN, TENEMOS CAMPOS QUE NO PUEDEN ESTAR VACÍOS JAMÁS.

Page 9: Base de Datos SQL

VEAMOS UN EJEMPLO. TENEMOS NUESTRA TABLA "LIBROS". EL CAMPO "TITULO" NO DEBERÍA ESTAR VACÍO NUNCA, IGUALMENTE EL

CAMPO "AUTOR". PARA ELLO, AL CREAR LA TABLA, DEBEMOS ESPECIFICAR QUE DICHOS CAMPOS NO ADMITAN VALORES NULOS:

CREATE TABLE LIBROS( TITULO VARCHAR(30) NOT NULL, AUTOR VARCHAR(20) NOT NULL, EDITORIAL VARCHAR(15) NULL, PRECIO FLOAT );

PARA ESPECIFICAR QUE UN CAMPO NO ADMITA VALORES NULOS, DEBEMOS COLOCAR "NOT NULL" LUEGO DE LA DEFINICIÓN DEL

CAMPO. EN EL EJEMPLO ANTERIOR, LOS CAMPOS "EDITORIAL" Y "PRECIO" SI ADMITEN VALORES NULOS. CUANDO COLOCAMOS "NULL" ESTAMOS DICIENDO QUE ADMITE VALORES NULOS (CASO DEL CAMPO "EDITORIAL"); POR DEFECTO, ES

DECIR, SI NO LO ACLARAMOS, LOS CAMPOS PERMITEN VALORES NULOS (CASO DEL CAMPO "PRECIO").

SI INGRESAMOS LOS DATOS DE UN LIBRO, PARA EL CUAL AÚN NO HEMOS DEFINIDO EL PRECIO PODEMOS COLOCAR "NULL" PARA

MOSTRAR QUE NO TIENE PRECIO:

INSERT INTO LIBROS (TITULO,AUTOR,EDITORIAL,PRECIO) VALUES('EL ALEPH','BORGES','EMECE',NULL);

NOTE QUE EL VALOR "NULL" NO ES UNA CADENA DE CARACTERES, NO SE COLOCA ENTRE COMILLAS. ENTONCES, SI UN CAMPO ACEPTA VALORES NULOS, PODEMOS INGRESAR "NULL" CUANDO NO CONOCEMOS EL VALOR.

TAMBIÉN PODEMOS COLOCAR "NULL" EN EL CAMPO "EDITORIAL" SI DESCONOCEMOS EL NOMBRE DE LA EDITORIAL A LA CUAL

PERTENECE EL LIBRO QUE VAMOS A INGRESAR:

INSERT INTO LIBROS (TITULO,AUTOR,EDITORIAL,PRECIO) VALUES('ALICIA EN EL PAIS','LEWIS CARROLL',NULL,25);

SI INTENTAMOS INGRESAR EL VALOR "NULL" EN CAMPOS QUE NO ADMITEN VALORES NULOS (COMO "TITULO" O "AUTOR"), SQL

SERVER NO LO PERMITE, MUESTRA UN MENSAJE Y LA INSERCIÓN NO SE REALIZA; POR EJEMPLO:

INSERT INTO LIBROS (TITULO,AUTOR,EDITORIAL,PRECIO) VALUES(NULL,'BORGES','SIGLO XXI',25);

PARA VER CUÁLES CAMPOS ADMITEN VALORES NULOS Y CUÁLES NO, PODEMOS EMPLEAR EL PROCEDIMIENTO ALMACENADO

"SP_COLUMNS" JUNTO AL NOMBRE DE LA TABLA. NOS MUESTRA MUCHA INFORMACIÓN, EN LA COLUMNA "IS_NULLABLE" VEMOS

QUE MUESTRA "NO" EN LOS CAMPOS QUE NO PERMITEN VALORES NULOS Y "YES" EN LOS CAMPOS QUE SI LOS PERMITEN.

PARA RECUPERAR LOS REGISTROS QUE CONTENGAN EL VALOR "NULL" EN ALGÚN CAMPO, NO PODEMOS UTILIZAR LOS OPERADORES

RELACIONALES VISTOS ANTERIORMENTE: = (IGUAL) Y <> (DISTINTO); DEBEMOS UTILIZAR LOS OPERADORES "IS NULL" (ES IGUAL A

NULL) Y "IS NOT NULL" (NO ES NULL):

SELECT * FROM LIBROS WHERE PRECIO IS NULL;

LA SENTENCIA ANTERIOR TENDRÁ UNA SALIDA DIFERENTE A LA SIGUIENTE:

SELECT * FROM LIBROS WHERE PRECIO=0;

Page 10: Base de Datos SQL

CON LA PRIMERA SENTENCIA VEREMOS LOS LIBROS CUYO PRECIO ES IGUAL A "NULL" (DESCONOCIDO); CON LA SEGUNDA, LOS LIBROS

CUYO PRECIO ES 0.

IGUALMENTE PARA CAMPOS DE TIPO CADENA, LAS SIGUIENTES SENTENCIAS "SELECT" NO RETORNAN LOS MISMOS REGISTROS:

SELECT * FROM LIBROS WHERE EDITORIAL IS NULL; SELECT * FROM LIBROS WHERE EDITORIAL='';

CON LA PRIMERA SENTENCIA VEREMOS LOS LIBROS CUYA EDITORIAL ES IGUAL A "NULL", CON LA SEGUNDA, LOS LIBROS CUYA

EDITORIAL GUARDA UNA CADENA VACÍA.

ENTONCES, PARA QUE UN CAMPO NO PERMITA VALORES NULOS DEBEMOS ESPECIFICARLO LUEGO DE DEFINIR EL CAMPO, AGREGANDO

"NOT NULL". POR DEFECTO, LOS CAMPOS PERMITEN VALORES NULOS, PERO PODEMOS ESPECIFICARLO IGUALMENTE AGREGANDO

"NULL".

12 - CLAVE PRIMARIA

UNA CLAVE PRIMARIA ES UN CAMPO (O VARIOS) QUE IDENTIFICA UN SOLO REGISTRO (FILA) EN UNA TABLA. PARA UN VALOR DEL CAMPO CLAVE EXISTE SOLAMENTE UN REGISTRO.

VEAMOS UN EJEMPLO, SI TENEMOS UNA TABLA CON DATOS DE PERSONAS, EL NÚMERO DE DOCUMENTO PUEDE ESTABLECERSE COMO

CLAVE PRIMARIA, ES UN VALOR QUE NO SE REPITE; PUEDE HABER PERSONAS CON IGUAL APELLIDO Y NOMBRE, INCLUSO EL MISMO

DOMICILIO (PADRE E HIJO POR EJEMPLO), PERO SU DOCUMENTO SERÁ SIEMPRE DISTINTO.

SI TENEMOS LA TABLA "USUARIOS", EL NOMBRE DE CADA USUARIO PUEDE ESTABLECERSE COMO CLAVE PRIMARIA, ES UN VALOR QUE

NO SE REPITE; PUEDE HABER USUARIOS CON IGUAL CLAVE, PERO SU NOMBRE DE USUARIO SERÁ SIEMPRE DIFERENTE.

PODEMOS ESTABLECER QUE UN CAMPO SEA CLAVE PRIMARIA AL MOMENTO DE CREAR LA TABLA O LUEGO QUE HA SIDO CREADA.

VAMOS A APRENDER A ESTABLECERLA AL CREAR LA TABLA. HAY 2 MANERAS DE HACERLO, POR AHORA VEREMOS LA SINTAXIS MÁS

SENCILLA.

TENEMOS NUESTRA TABLA "USUARIOS" DEFINIDA CON 2 CAMPOS ("NOMBRE" Y "CLAVE"). LA SINTAXIS BÁSICA Y GENERAL ES LA SIGUIENTE:

CREATE TABLE NOMBRETABLA( CAMPO TIPO, ... PRIMARY KEY (NOMBRECAMPO) );

EN EL SIGUIENTE EJEMPLO DEFINIMOS UNA CLAVE PRIMARIA, PARA NUESTRA TABLA "USUARIOS" PARA ASEGURARNOS QUE CADA

USUARIO TENDRÁ UN NOMBRE DIFERENTE Y ÚNICO:

CREATE TABLE USUARIOS( NOMBRE VARCHAR(20), CLAVE VARCHAR(10), PRIMARY KEY(NOMBRE) );

LO QUE HACEMOS AGREGAR LUEGO DE LA DEFINICIÓN DE CADA CAMPO, "PRIMARY KEY" Y ENTRE PARÉNTESIS, EL NOMBRE DEL

CAMPO QUE SERÁ CLAVE PRIMARIA.

Page 11: Base de Datos SQL

UNA TABLA SÓLO PUEDE TENER UNA CLAVE PRIMARIA. CUALQUIER CAMPO (DE CUALQUIER TIPO) PUEDE SER CLAVE PRIMARIA, DEBE

CUMPLIR COMO REQUISITO, QUE SUS VALORES NO SE REPITAN NI SEAN NULOS. POR ELLO, AL DEFINIR UN CAMPO COMO CLAVE

PRIMARIA, AUTOMÁTICAMENTE SQL SERVER LO CONVIERTE A "NOT NULL".

LUEGO DE HABER ESTABLECIDO UN CAMPO COMO CLAVE PRIMARIA, AL INGRESAR LOS REGISTROS, SQL SERVER CONTROLA QUE LOS

VALORES PARA EL CAMPO ESTABLECIDO COMO CLAVE PRIMARIA NO ESTÉN REPETIDOS EN LA TABLA; SI ESTUVIESEN REPETIDOS, MUESTRA UN MENSAJE Y LA INSERCIÓN NO SE REALIZA. ES DECIR, SI EN NUESTRA TABLA "USUARIOS" YA EXISTE UN USUARIO CON

NOMBRE "JUANPEREZ" E INTENTAMOS INGRESAR UN NUEVO USUARIO CON NOMBRE "JUANPEREZ", APARECE UN MENSAJE Y LA

INSTRUCCIÓN "INSERT" NO SE EJECUTA.

IGUALMENTE, SI REALIZAMOS UNA ACTUALIZACIÓN, SQL SERVER CONTROLA QUE LOS VALORES PARA EL CAMPO ESTABLECIDO COMO

CLAVE PRIMARIA NO ESTÉN REPETIDOS EN LA TABLA, SI LO ESTUVIESE, APARECE UN MENSAJE INDICANDO QUE SE VIOLA LA CLAVE

PRIMARIA Y LA ACTUALIZACIÓN NO SE REALIZA.

13 - CAMPO CON ATRIBUTO IDENTITY

UN CAMPO NUMÉRICO PUEDE TENER UN ATRIBUTO EXTRA "IDENTITY". LOS VALORES DE UN CAMPO CON ESTE ATRIBUTO GENERA

VALORES SECUENCIALES QUE SE INICIAN EN 1 Y SE INCREMENTAN EN 1 AUTOMÁTICAMENTE.

SE UTILIZA GENERALMENTE EN CAMPOS CORRESPONDIENTES A CÓDIGOS DE IDENTIFICACIÓN PARA GENERAR VALORES ÚNICOS PARA

CADA NUEVO REGISTRO QUE SE INSERTA.

SÓLO PUEDE HABER UN CAMPO "IDENTITY" POR TABLA.

PARA QUE UN CAMPO PUEDA ESTABLECERSE COMO "IDENTITY", ÉSTE DEBE SER ENTERO (TAMBIÉN PUEDE SER DE UN SUBTIPO DE

ENTERO O DECIMAL CON ESCALA 0, TIPOS QUE ESTUDIAREMOS POSTERIORMENTE).

PARA QUE UN CAMPO GENERE SUS VALORES AUTOMÁTICAMENTE, DEBEMOS AGREGAR EL ATRIBUTO "IDENTITY" LUEGO DE SU

DEFINICIÓN AL CREAR LA TABLA:

CREATE TABLE LIBROS( CODIGO INT IDENTITY, TITULO VARCHAR(40) NOT NULL, AUTOR VARCHAR(30), EDITORIAL VARCHAR(15), PRECIO FLOAT );

CUANDO UN CAMPO TIENE EL ATRIBUTO "IDENTITY" NO SE PUEDE INGRESAR VALOR PARA ÉL, PORQUE SE INSERTA

AUTOMÁTICAMENTE TOMANDO EL ÚLTIMO VALOR COMO REFERENCIA, O 1 SI ES EL PRIMERO.

PARA INGRESAR REGISTROS OMITIMOS EL CAMPO DEFINIDO COMO "IDENTITY", POR EJEMPLO:

INSERT INTO LIBROS (TITULO,AUTOR,EDITORIAL,PRECIO) VALUES('EL ALEPH','BORGES','EMECE',23);

ESTE PRIMER REGISTRO INGRESADO GUARDARÁ EL VALOR 1 EN EL CAMPO CORRESPONDIENTE AL CÓDIGO.

SI CONTINUAMOS INGRESANDO REGISTROS, EL CÓDIGO (DATO QUE NO INGRESAMOS) SE CARGARÁ AUTOMÁTICAMENTE SIGUIENDO

LA SECUENCIA DE AUTOINCREMENTO.

Page 12: Base de Datos SQL

NO ESTÁ PERMITIDO INGRESAR EL VALOR CORRESPONDIENTE AL CAMPO "IDENTITY", POR EJEMPLO:

INSERT INTO LIBROS (CODIGO,TITULO,AUTOR,EDITORIAL,PRECIO) VALUES(5,'MARTIN FIERRO','JOSE HERNANDEZ','PAIDOS',25);

GENERARÁ UN MENSAJE DE ERROR.

"IDENTITY" PERMITE INDICAR EL VALOR DE INICIO DE LA SECUENCIA Y EL INCREMENTO, PERO LO VEREMOS POSTERIORMENTE.

UN CAMPO DEFINIDO COMO "IDENTITY" GENERALMENTE SE ESTABLECE COMO CLAVE PRIMARIA.

UN CAMPO "IDENTITY" NO ES EDITABLE, ES DECIR, NO SE PUEDE INGRESAR UN VALOR NI ACTUALIZARLO.

UN CAMPO DE IDENTIDAD NO PERMITE VALORES NULOS, AUNQUE NO SE INDIQUE ESPECIFICAMENTE. SI EJECUTAMOS EL

PROCEDIMIENTO "SP_COLUMNS()" VEREMOS QUE EN EL CAMPO "CODIGO" EN LA COLUMNA "TYPE_NAME" APARECE "INT

IDENTITY" Y EN LA COLUMNA "IS_NULLABLE" APARECE "NO".

LOS VALORES SECUENCIALES DE UN CAMPO "IDENTITY" SE GENERAN TOMANDO COMO REFERENCIA EL ÚLTIMO VALOR INGRESADO; SI

SE ELIMINA EL ÚLTIMO REGISTRO INGRESADO (POR EJEMPLO 3) Y LUEGO SE INSERTA OTRO REGISTRO, SQL SERVER SEGUIRÁ LA

SECUENCIA, ES DECIR, COLOCARÁ EL VALOR "4".

14 - OTRAS CARACTERÍSTICAS DEL ATRIBUTO IDENTITY

EL ATRIBUTO "IDENTITY" PERMITE INDICAR EL VALOR DE INICIO DE LA SECUENCIA Y EL INCREMENTO, PARA ELLO USAMOS LA

SIGUIENTE SINTAXIS:

CREATE TABLE LIBROS( CODIGO INT IDENTITY(100,2), TITULO VARCHAR(20), AUTOR VARCHAR(30), PRECIO FLOAT );

LOS VALORES COMENZARÁN EN "100" Y SE INCREMENTARÁN DE 2 EN 2; ES DECIR, EL PRIMER REGISTRO INGRESADO TENDRÁ EL

VALOR "100", LOS SIGUIENTES "102", "104", "106", ETC.

LA FUNCIÓN "IDENT_SEED()" RETORNA EL VALOR DE INICIO DEL CAMPO "IDENTITY" DE LA TABLA QUE NOMBRAMOS:

SELECT IDENT_SEED('LIBROS');

LA FUNCIÓN "IDENT_INCR()" RETORNA EL VALOR DE INCREMENTO DEL CAMPO "IDENTITY" DE LA TABLA NOMBRADA:

SELECT IDENT_INCR('LIBROS');

HEMOS VISTO QUE EN UN CAMPO DECLARADO "IDENTITY" NO PUEDE INGRESARSE EXPLÍCITAMENTE UN VALOR. PARA PERMITIR INGRESAR UN VALOR EN UN CAMPO DE IDENTIDAD SE DEBE ACTIVAR LA OPCIÓN "IDENTITY_INSERT":

SET IDENTITY_INSERT LIBROS ON;

ES DECIR, PODEMOS INGRESAR VALOR EN UN CAMPO "IDENTITY" SETEANDO LA OPCIÓN "IDENTITY_INSERT" EN "ON".

Page 13: Base de Datos SQL

CUANDO "IDENTITY_INSERT" ESTÁ EN ON, LAS INSTRUCCIONES "INSERT" DEBEN EXPLICITAR UN VALOR:

INSERT INTO LIBROS (CODIGO,TITULO) VALUES (5,'ALICIA EN EL PAIS DE LAS MARAVILLAS');

SI NO SE COLOCA UN VALOR PARA EL CAMPO DE IDENTIDAD, LA SENTENCIA NO SE EJECUTA Y APARECE UN MENSAJE DE ERROR:

INSERT INTO LIBROS (TITULO,AUTOR, EDITORIAL) VALUES ('MATEMATICA ESTAS AHI','PAENZA','PAIDOS');

EL ATRIBUTO "IDENTITY" NO IMPLICA UNICIDAD, ES DECIR, PERMITE REPETICIÓN DE VALORES; POR ELLO HAY QUE TENER CUIDADO AL

EXPLICITAR UN VALOR PORQUE SE PUEDE INGRESAR UN VALOR REPETIDO.

PARA DESACTIVAR LA OPCIÓN "IDENTITY_INSERT" TIPEAMOS:

SET IDENTITY_INSERT LIBROS OFF;

15 - TRUNCATE TABLE

APRENDIMOS QUE PARA BORRAR TODOS LOS REGISTRO DE UNA TABLA SE USA "DELETE" SIN CONDICIÓN "WHERE". TAMBIÉN PODEMOS ELIMINAR TODOS LOS REGISTROS DE UNA TABLA CON "TRUNCATE TABLE". POR EJEMPLO, QUEREMOS VACIAR LA TABLA "LIBROS", USAMOS:

TRUNCATE TABLE LIBROS;

LA SENTENCIA "TRUNCATE TABLE" VACÍA LA TABLA (ELIMINA TODOS LOS REGISTROS) Y CONSERVA LA ESTRUCTURA DE LA TABLA.

LA DIFERENCIA CON "DROP TABLE" ES QUE ESTA SENTENCIA BORRA LA TABLA, "TRUNCATE TABLE" LA VACÍA.

LA DIFERENCIA CON "DELETE" ES LA VELOCIDAD, ES MÁS RÁPIDO "TRUNCATE TABLE" QUE "DELETE" (SE NOTA CUANDO LA CANTIDAD

DE REGISTROS ES MUY GRANDE) YA QUE ÉSTE BORRA LOS REGISTROS UNO A UNO.

OTRA DIFERENCIA ES LA SIGUIENTE: CUANDO LA TABLA TIENE UN CAMPO "IDENTITY", SI BORRAMOS TODOS LOS REGISTROS CON

"DELETE" Y LUEGO INGRESAMOS UN REGISTRO, AL CARGARSE EL VALOR EN EL CAMPO DE IDENTIDAD, CONTINÚA CON LA SECUENCIA

TENIENDO EN CUENTA EL VALOR MAYOR QUE SE HABÍA GUARDADO; SI USAMOS "TRUNCATE TABLE" PARA BORRAR TODOS LOS

REGISTROS, AL INGRESAR OTRA VEZ UN REGISTRO, LA SECUENCIA DEL CAMPO DE IDENTIDAD VUELVE A INICIARSE EN 1.

POR EJEMPLO, TENEMOS LA TABLA "LIBROS" CON EL CAMPO "CODIGO" DEFINIDO "IDENTITY", Y EL VALOR MÁS ALTO DE ESE CAMPO

ES "2", SI BORRAMOS TODOS LOS REGISTROS CON "DELETE" Y LUEGO INGRESAMOS UN REGISTRO, ÉSTE GUARDARÁ EL VALOR DE

CÓDIGO "3"; SI EN CAMBIO, VACIAMOS LA TABLA CON "TRUNCATE TABLE", AL INGRESAR UN NUEVO REGISTRO EL VALOR DEL CÓDIGO

SE INICIARÁ EN 1 NUEVAMENTE.

16 - OTROS TIPOS DE DATOS EN SQL SERVER

YA EXPLICAMOS QUE AL CREAR UNA TABLA DEBEMOS ELEGIR LA ESTRUCTURA ADECUADA, ESTO ES, DEFINIR LOS CAMPOS Y SUS TIPOS

MÁS PRECISOS, SEGÚN EL CASO.

EL TIPO DE DATO ESPECIFICADO EN LA DEFINICIÓN DE CADA CAMPO INDICA LOS VALORES PERMITIDOS PARA CADA UNO DE ELLOS.

Page 14: Base de Datos SQL

HASTA AHORA HEMOS VISTO 3 TIPOS DE DATOS: VARCHAR, INTEGER Y FLOAT. HAY MÁS TIPOS, INCLUSO, SUBTIPOS.

LOS VALORES QUE PODEMOS GUARDAR SON:

1. TEXTO: PARA ALMACENAR TEXTO USAMOS CADENAS DE CARACTERES. LAS CADENAS SE COLOCAN ENTRE COMILLAS SIMPLES. PODEMOS ALMACENAR LETRAS, SÍMBOLOS Y DÍGITOS CON LOS QUE

NO SE REALIZAN OPERACIONES MATEMÁTICAS, POR EJEMPLO, CÓDIGOS DE IDENTIFICACIÓN, NÚMEROS DE DOCUMENTOS, NÚMEROS TELEFÓNICOS. SQL SERVER OFRECE LOS SIGUIENTES TIPOS: CHAR, NCHAR, VARCHAR, NVARCHAR, TEXT Y NTEXT.

2. NUMEROS: EXISTE VARIEDAD DE TIPOS NUMÉRICOS PARA REPRESENTAR ENTEROS, DECIMALES, MONEDAS. PARA ALMACENAR VALORES ENTEROS, POR EJEMPLO, EN CAMPOS QUE HACEN REFERENCIA A CANTIDADES, PRECIOS, ETC., USAMOS EL TIPO INTEGER (Y SUS SUBTIPOS: TINYINT, SMALLINT Y BIGINT). PARA ALMACENAR VALORES CON DECIMALES EXACTOS, UTILIZAMOS: NUMERIC O DECIMAL (SON EQUIVALENTES). PARA GUARDAR VALORES DECIMALES APROXIMADOS: FLOAT Y REAL. PARA ALMACENAR VALORES MONETARIOS: MONEY Y

SMALLMONEY. 3. FECHAS Y HORAS: PARA GUARDAR FECHAS Y HORAS SQL SERVER DISPONE DE 2 TIPOS: DATETIME Y SMALLDATETIME.

EXISTEN OTROS TIPOS DE DATOS QUE ANALIZAREMOS EN SECCIONES PRÓXIMAS.

ENTONCES, CUANDO CREAMOS UNA TABLA Y DEFINIR SUS CAMPOS DEBEMOS ELEGIR EL TIPO DE DATO MÁS PRECISO. POR EJEMPLO, SI NECESITAMOS ALMACENAR NOMBRES USAMOS TEXTO; SI UN CAMPO NUMÉRICO ALMACENARÁ SOLAMENTE VALORES ENTEROS EL

TIPO "INTEGER" ES MÁS ADECUADO QUE, POR EJEMPLO UN "FLOAT"; SI NECESITAMOS ALMACENAR PRECIOS, LO MÁS LÓGICO ES

UTILIZAR EL TIPO "MONEY".

A CONTINUACIÓN ANALIZAREMOS EN DETALLE CADA TIPO DE DATO BÁSICOS.

17 - TIPO DE DATO (TEXTO)

YA EXPLICAMOS QUE AL CREAR UNA TABLA DEBEMOS ELEGIR LA ESTRUCTURA ADECUADA, ESTO ES, DEFINIR LOS CAMPOS Y SUS TIPOS

MÁS PRECISOS, SEGÚN EL CASO.

PARA ALMACENAR TEXTO USAMOS CADENAS DE CARACTERES. LAS CADENAS SE COLOCAN ENTRE COMILLAS SIMPLES. PODEMOS ALMACENAR LETRAS, SÍMBOLOS Y DÍGITOS CON LOS QUE NO SE REALIZAN OPERACIONES MATEMÁTICAS, POR EJEMPLO, CÓDIGOS DE IDENTIFICACIÓN, NÚMEROS DE DOCUMENTOS, NÚMEROS TELEFÓNICOS.

TENEMOS LOS SIGUIENTES TIPOS:

1. VARCHAR(X): DEFINE UNA CADENA DE CARACTERES DE LONGITUD VARIABLE EN LA CUAL DETERMINAMOS EL MÁXIMO DE

CARACTERES CON EL ARGUMENTO "X" QUE VA ENTRE PARÉNTESIS. SI SE OMITE EL ARGUMENTO COLOCA 1 POR DEFECTO. SU RANGO VA DE 1 A 8000 CARACTERES.

2. CHAR(X): DEFINE UNA CADENA DE LONGITUD FIJA DETERMINADA POR EL ARGUMENTO "X". SI SE OMITE EL ARGUMENTO

COLOCA 1 POR DEFECTO. SU RANGO ES DE 1 A 8000 CARACTERES. SI LA LONGITUD ES INVARIABLE, ES CONVENIENTE UTILIZAR EL TIPO CHAR; CASO CONTRARIO, EL TIPO VARCHAR. OCUPA TANTOS BYTES COMO SE DEFINEN CON EL ARGUMENTO "X". "CHAR" VIENE DE CHARACTER, QUE SIGNIFICA CARACTER EN INGLÉS.

3. TEXT: GUARDA DATOS BINARIOS DE LONGITUD VARIABLE, PUEDE CONTENER HASTA 2000000000 CARACTERES. NO ADMITE

ARGUMENTO PARA ESPECIFICAR SU LONGITUD. 4. NVARCHAR(X): ES SIMILAR A "VARCHAR", EXCEPTO QUE PERMITE ALMACENAR CARACTERES UNICODE, SU RANGO VA DE 0 A

4000 CARACTERES PORQUE SE EMPLEAN 2 BYTES POR CADA CARACTER. 5. NCHAR(X): ES SIMILAR A "CHAR" EXCPETO QUE ACEPTA CARACTERES UNICODE, SU RANGO VA DE 0 A 4000 CARACTERES

PORQUE SE EMPLEAN 2 BYTES POR CADA CARACTER.

Page 15: Base de Datos SQL

6. NTEXT: ES SIMILAR A "TEXT" EXCEPTO QUE PERMITE ALMACENAR CARACTERES UNICODE, PUEDE CONTENER HASTA

1000000000 CARACTERES. NO ADMITE ARGUMENTO PARA ESPECIFICAR SU LONGITUD.

EN GENERAL SE USARÁN LOS 3 PRIMEROS.

SI INTENTAMOS ALMACENAR EN UN CAMPO UNA CADENA DE CARACTERES DE MAYOR LONGITUD QUE LA DEFINIDA, APARECE UN

MENSAJE INDICANDO TAL SITUACIÓN Y LA SENTENCIA NO SE EJECUTA.

POR EJEMPLO, SI DEFINIMOS UN CAMPO DE TIPO VARCHAR(10) Y LE ASIGNAMOS LA CADENA 'APRENDA PHP' (11 CARACTERES), APARECE UN MENSAJE Y LA SENTENCIA NO SE EJECUTA.

SI INGRESAMOS UN VALOR NUMÉRICO (OMITIENDO LAS COMILLAS), LO CONVIERTE A CADENA Y LO INGRESA COMO TAL.

POR EJEMPLO, SI EN UN CAMPO DEFINIDO COMO VARCHAR(5) INGRESAMOS EL VALOR 12345, LO TOMA COMO SI HUBIÉSEMOS

TIPEADO '12345', IGUALMENTE, SI INGRESAMOS EL VALOR 23.56, LO CONVIERTE A '23.56'. SI EL VALOR NUMÉRICO, AL SER

CONVERTIDO A CADENA SUPERA LA LONGITUD DEFINIDA, APARECE UN MENSAJE DE ERROR Y LA SENTENCIA NO SE EJECUTA.

ES IMPORTANTE ELEGIR EL TIPO DE DATO ADECUADO SEGÚN EL CASO, EL MÁS PRECISO.

PARA ALMACENAR CADENAS QUE VARÍAN EN SU LONGITUD, ES DECIR, NO TODOS LOS REGISTROS TENDRÁN LA MISMA LONGITUD EN

UN CAMPO DETERMINADO, SE EMPLEA "VARCHAR" EN LUGAR DE "CHAR".

POR EJEMPLO, EN CAMPOS QUE GUARDAMOS NOMBRES Y APELLIDOS, NO TODOS LOS NOMBRES Y APELLIDOS TIENEN LA MISMA

LONGITUD.

PARA ALMACENAR CADENAS QUE NO VARÍAN EN SU LONGITUD, ES DECIR, TODOS LOS REGISTROS TENDRÁN LA MISMA LONGITUD EN

UN CAMPO DETERMINADO, SE EMPLEA "CHAR".

POR EJEMPLO, DEFINIMOS UN CAMPO "CODIGO" QUE CONSTARÁ DE 5 CARACTERES, TODOS LOS REGISTROS TENDRÁN UN CÓDIGO DE

5 CARACTERES, NI MÁS NI MENOS.

PARA ALMACENAR VALORES SUPERIORES A 8000 CARACTERES SE DEBE EMPLEAR "TEXT".

TIPO BYTES DE ALMACENAMIENTO _______________________________________ VARCHAR(X) 0 A 8K CHAR(X) 0 A 8K TEXT 0 A 2GB NVARCHAR(X) 0 A 8K NCHAR(X) 0 A 8K NTEXT 0 A 2GB

18 - TIPO DE DATO (NUMÉRICO)

YA EXPLICAMOS QUE AL CREAR UNA TABLA DEBEMOS ELEGIR LA ESTRUCTURA ADECUADA, ESTO ES, DEFINIR LOS CAMPOS Y SUS TIPOS

MÁS PRECISOS, SEGÚN EL CASO.

PARA ALMACENAR VALORES NUMERICOS SQL SERVER DISPONE DE VARIOS TIPOS.

PARA ALMACENAR VALORES ENTEROS, POR EJEMPLO, EN CAMPOS QUE HACEN REFERENCIA A CANTIDADES, USAMOS:

Page 16: Base de Datos SQL

1) INTEGER O INT: SU RANGO ES DE -2000000000 A 2000000000 APROX. EL TIPO "INTEGER" TIENE SUBTIPOS: - SMALLINT: PUEDE CONTENER HASTA 5 DIGITOS. SU RANGO VA DESDE –32000 HASTA 32000 APROX. - TINYINT: PUEDE ALMACENAR VALORES ENTRE 0 Y 255. - BIGINT: DE –9000000000000000000 HASTA 9000000000000000000 APROX.

PARA ALMACENAR VALORES NUMÉRICOS EXACTOS CON DECIMALES, ESPECIFICANDO LA CANTIDAD DE CIFRAS A LA IZQUIERDA Y

DERECHA DEL SEPARADOR DECIMAL, UTILIZAMOS:

2) DECIMAL O NUMERIC (T,D): PUEDEN TENER HASTA 38 DIGITOS, GUARDA UN VALOR EXACTO. EL PRIMER ARGUMENTO INDICA EL

TOTAL DE DÍGITOS Y EL SEGUNDO, LA CANTIDAD DE DECIMALES. POR EJEMPLO, SI QUEREMOS ALMACENAR VALORES ENTRE -99.99 Y 99.99 DEBEMOS DEFINIR EL CAMPO COMO TIPO

"DECIMAL(4,2)". SI NO SE INDICA EL VALOR DEL SEGUNDO ARGUMENTO, POR DEFECTO ES "0". POR EJEMPLO, SI DEFINIMOS

"DECIMAL(4)" SE PUEDEN GUARDAR VALORES ENTRE -9999 Y 9999.

EL RANGO DEPENDE DE LOS ARGUMENTOS, TAMBIÉN LOS BYTES QUE OCUPA. SE UTILIZA EL PUNTO COMO SEPARADOR DE DECIMALES.

SI INGRESAMOS UN VALOR CON MÁS DECIMALES QUE LOS PERMITIDOS, REDONDEA AL MÁS CERCANO; POR EJEMPLO, SI DEFINIMOS

"DECIMAL(4,2)" E INGRESAMOS EL VALOR "12.686", GUARDARÁ "12.69", REDONDEANDO HACIA ARRIBA; SI INGRESAMOS EL

VALOR "12.682", GUARDARÁ "12.67", REDONDEANDO HACIA ABAJO.

PARA ALMACENAR VALORES NUMÉRICOS APROXIMADOS CON DECIMALES UTILIZAMOS:

3) FLOAT Y REAL: DE 1.79E+308 HASTA 1.79E+38. GUARDA VALORES APROXIMADOS. 4) REAL: DESDE 3.40E+308 HASTA 3.40E+38. GUARDA VALORES APROXIMADOS.

PARA ALMACENAR VALORES MONETARIOS EMPLEAMOS:

5) MONEY: PUEDE TENER HASTA 19 DIGITOS Y SÓLO 4 DE ELLOS PUEDE IR LUEGO DEL SEPARADOR DECIMAL; ENTRE –900000000000000.5808 APROX Y 900000000000000.5807.

6) SMALLMONEY: ENTRE –200000.3648 Y 200000.3647 APROX.

PARA TODOS LOS TIPOS NUMÉRICOS: - SI INTENTAMOS INGRESAR UN VALOR FUERA DE RANGO, NO LO PERMITE. - SI INGRESAMOS UNA CADENA, SQL SERVER INTENTA CONVERTIRLA A VALOR NUMÉRICO, SI DICHA CADENA CONSTA SOLAMENTE DE

DÍGITOS, LA CONVERSIÓN SE REALIZA, LUEGO VERIFICA SI ESTÁ DENTRO DEL RANGO, SI ES ASÍ, LA INGRESA, SINO, MUESTRA UN

MENSAJE DE ERROR Y NO EJECUTA LA SENTENCIA. SI LA CADENA CONTIENE CARACTERES QUE SQL SERVER NO PUEDE CONVERTIR A

VALOR NUMÉRICO, MUESTRA UN MENSAJE DE ERROR Y LA SENTENCIA NO SE EJECUTA. POR EJEMPLO, DEFINIMOS UN CAMPO DE TIPO DECIMAL(5,2), SI INGRESAMOS LA CADENA '12.22', LA CONVIERTE AL VALOR

NUMÉRICO 12.22 Y LA INGRESA; SI INTENTAMOS INGRESAR LA CADENA '1234.56', LA CONVIERTE AL VALOR NUMÉRICO 1234.56,

PERO COMO EL MÁXIMO VALOR PERMITIDO ES 999.99, MUESTRA UN MENSAJE INDICANDO QUE ESTÁ FUERA DE RANGO. SI

INTENTAMOS INGRESAR EL VALOR '12Y.25', SQL SERVER NO PUEDE REALIZAR LA CONVERSIÓN Y MUESTRA UN MENSAJE DE ERROR.

ES IMPORTANTE ELEGIR EL TIPO DE DATO ADECUADO SEGÚN EL CASO, EL MÁS PRECISO. POR EJEMPLO, SI UN CAMPO NUMÉRICO

ALMACENARÁ VALORES POSITIVOS MENORES A 255, EL TIPO "INT" NO ES EL MÁS ADECUADO, CONVIENE EL TIPO "TINYINT", DE ESTA

MANERA USAMOS EL MENOR ESPACIO DE ALMACENAMIENTO POSIBLE. SI VAMOS A GUARDAR VALORES MONETARIOS MENORES A 200000 CONVIENE EMPLEAR "SMALLMONEY" EN LUGAR DE "MONEY".

TIPO BYTES DE ALMACENAMIENTO _______________________________________ INT 4 SMALLINT 2

Page 17: Base de Datos SQL

TINYINT 1 BIGINT 8 DECIMAL 2 A 17 FLOAT 4 U 8 REAL 4 U 8 MONEY 8 SMALLMONEY 4

19 - TIPO DE DATO (FECHA Y HORA)

YA EXPLICAMOS QUE AL CREAR UNA TABLA DEBEMOS ELEGIR LA ESTRUCTURA ADECUADA, ESTO ES, DEFINIR LOS CAMPOS Y SUS TIPOS

MÁS PRECISOS, SEGÚN EL CASO.

PARA ALMACENAR VALORES DE TIPO FECHA Y HORA SQL SERVER DISPONE DE DOS TIPOS:

1) DATETIME: PUEDE ALMACENAR VALORES DESDE 01 DE ENERO DE 1753 HASTA 31 DE DICIEMBRE DE 9999.

2) SMALLDATETIME: EL RANGO VA DE 01 DE ENERO DE 1900 HASTA 06 DE JUNIO DE 2079.

LAS FECHAS SE INGRESAN ENTRE COMILLAS SIMPLES.

PARA ALMACENAR VALORES DE TIPO FECHA SE PERMITEN COMO SEPARADORES "/", "-" Y ".".

SQL SERVER RECONOCE VARIOS FORMATOS DE ENTRADA DE DATOS DE TIPO FECHA. PARA ESTABLECER EL ORDEN DE LAS PARTES DE

UNA FECHA (DIA, MES Y AÑO) EMPLEAMOS "SET DATEFORMAT". ESTOS SON LOS FORMATOS:

-MDY: 4/15/96 (MES Y DÍA CON 1 Ó 2 DÍGITOS Y AÑO CON 2 Ó 4 DÍGITOS), -MYD: 4/96/15, -DMY: 15/4/1996 -DYM: 15/96/4, -YDM: 96/15/4, -YDM: 1996/15/4,

PARA INGRESAR UNA FECHA CON FORMATO "DÍA-MES-AÑO", TIPEAMOS:

SET DATEFORMAT DMY;

EL FORMATO POR DEFECTO ES "MDY".

TODOS LOS VALORES DE TIPO "DATETIME" SE MUESTRAN EN FORMATO "AÑO-MES-DÍA HORA:MINUTO:SEGUNDO .MILISEGUNDOS", INDEPENDIENTEMENTE DEL FORMATO DE INGRESO QUE HAYAMOS SETEADO.

PODEMOS INGRESAR UNA FECHA, SIN HORA, EN TAL CASO LA HORA SE GUARDA COMO "00:00:00". POR EJEMPLO, SI INGRESAMOS

'25-12-01' (AÑO DE 2 DÍGITOS), LO MOSTRARÁ ASÍ: '2001-12-25 00:00:00.000'.

PODEMOS INGRESAR UNA HORA SIN FECHA, EN TAL CASO, COLOCA LA FECHA "1900-01-01". POR EJEMPLO, SI INGRESAMOS

'10:15', MOSTRARÁ '1900-01-01 10:15.000'.

Page 18: Base de Datos SQL

PODEMOS EMPLEAR LOS OPERADORES RELACIONALES VISTOS PARA COMPARAR FECHAS.

TIPO BYTES DE ALMACENAMIENTO _______________________________________ DATETIME 8 SMALLDATETIME 4

20 - INGRESAR ALGUNOS CAMPOS (INSERT INTO)

HEMOS APRENDIDO A INGRESAR REGISTROS LISTANDO TODOS LOS CAMPOS Y COLOCANDO VALORES

PARA TODOS Y CADA UNO DE ELLOS LUEGO DE "VALUES".

SI INGRESAMOS VALORES PARA TODOS LOS CAMPOS, PODEMOS OMITIR LA LISTA DE NOMBRES DE LOS

CAMPOS.

POR EJEMPLO, SI TENEMOS CREADA LA TABLA "LIBROS" CON LOS CAMPOS "TITULO", "AUTOR" Y

"EDITORIAL", PODEMOS INGRESAR UN REGISTRO DE LA SIGUIENTE MANERA:

INSERT INTO LIBROS

VALUES ('UNO','RICHARD BACH','PLANETA');

TAMBIÉN 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 MÁS (O MENOS) CAMPOS QUE LOS VALORES INGRESADOS, APARECE

UN MENSAJE DE ERROR Y LA SENTENCIA NO SE EJECUTA.

- SI INGRESAMOS VALORES PARA TODOS LOS CAMPOS PODEMOS OBVIAR LA LISTA DE CAMPOS.

- PODEMOS OMITIR VALORES PARA LOS CAMPOS QUE NO HAYAN SIDO DECLARADOS "NOT NULL", ES

DECIR, QUE PERMITAN VALORES NULOS (SE GUARDARÁ "NULL"); SI OMITIMOS EL VALOR PARA UN

CAMPO "NOT NULL", LA SENTENCIA NO SE EJECUTA.

- SE DEBE OMITIR EL VALOR PARA EL CAMPO"IDENTITY". SALVO QUE IDENTITY_INSERT ESTE EN ON.

- SE PUEDEN OMITIR VALORES PARA CAMPOS DECLARADOS "NOT NULL" SIEMPRE QUE TENGAN DEFINIDO

UN VALOR POR DEFECTO CON LA CLÁUSULA "DEFAULT" (TEMA QUE VEREMOS A CONTINUACIÓN).

Page 19: Base de Datos SQL

21 - VALORES POR DEFECTO (DEFAULT)

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 INVÁLIDO.

PARA CAMPOS DE CUALQUIER TIPO NO DECLARADOS "NOT NULL", ES DECIR, QUE ADMITEN VALORES NULOS, EL VALOR POR DEFECTO

ES "NULL". PARA CAMPOS DECLARADOS "NOT NULL", NO EXISTE VALOR POR DEFECTO, A MENOS QUE SE DECLARE EXPLÍCITAMENTE

CON LA CLÁUSULA "DEFAULT".

PARA TODOS LOS TIPOS, EXCEPTO LOS DECLARADOS "IDENTITY", SE PUEDEN EXPLICITAR VALORES POR DEFECTO CON LA CLÁUSULA

"DEFAULT".

PODEMOS ESTABLECER VALORES POR DEFECTO PARA LOS CAMPOS CUANDO CREAMOS LA TABLA. PARA ELLO UTILIZAMOS "DEFAULT"

AL DEFINIR EL CAMPO. POR EJEMPLO, QUEREMOS QUE EL VALOR POR DEFECTO DEL CAMPO "AUTOR" DE LA TABLA "LIBROS" SEA

"DESCONOCIDO" Y EL VALOR POR DEFECTO DEL CAMPO "CANTIDAD" SEA "0":

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 CLÁUSULA "DEFAULT", ÉSE SERÁ EL VALOR POR

DEFECTO.

AHORA, AL VISUALIZAR LA ESTRUCTURA DE LA TABLA CON "SP_COLUMNS" PODEMOS ENTENDER LO QUE INFORMA LA COLUMNA

"COLUMN_DEF", MUESTRA EL VALOR POR DEFECTO DEL CAMPO.

TAMBIÉN SE PUEDE UTILIZAR "DEFAULT" PARA DAR EL VALOR POR DEFECTO A LOS CAMPOS EN SENTENCIAS "INSERT", POR EJEMPLO:

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.

Page 20: Base de Datos SQL

ENTONCES, LA CLÁUSULA "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" TOMARÁN LOS VALORES POR DEFECTO:

- SI TIENE EL ATRIBUTO "IDENTITY": EL VALOR DE INICIO DE LA SECUENCIA SI ES EL PRIMERO O EL SIGUIENTE VALOR DE LA SECUENCIA, NO ADMITE CLÁUSULA "DEFAULT";

- SI PERMITE VALORES NULOS Y NO TIENE CLÁUSULA "DEFAULT", ALMACENARÁ "NULL";

- SI ESTÁ DECLARADO EXPLÍCITAMENTE "NOT NULL", NO TIENE VALOR "DEFAULT" Y NO TIENE EL ATRIBUTO "IDENTITY", NO HAY

VALOR POR DEFECTO, ASÍ QUE CAUSARÁ UN ERROR Y EL "INSERT" NO SE EJECUTARÁ.

- SI TIENE CLÁUSULA "DEFAULT" (ADMITA O NO VALORES NULOS), EL VALOR DEFINIDO COMO PREDETERMINADO;

- PARA CAMPOS DE TIPO FECHA Y HORA, SI OMITIMOS LA PARTE DE LA FECHA, EL VALOR PREDETERMINADO PARA LA FECHA ES

"1900-01-01" Y SI OMITIMOS LA PARTE DE LA HORA, "00:00:00".

UN CAMPO SÓLO PUEDE TENER UN VALOR POR DEFECTO. UNA TABLA PUEDE TENER TODOS SUS CAMPOS CON VALORES POR DEFECTO.

QUE UN CAMPO TENGA VALOR POR DEFECTO NO SIGNIFICA QUE NO ADMITA VALORES NULOS, PUEDE O NO ADMITIRLOS.

22 - COLUMNAS CALCULADAS (OPERADORES

ARITMÉTICOS Y DE CONCATENACIÓN)

APRENDIMOS QUE LOS OPERADORES SON SÍMBOLOS QUE PERMITEN REALIZAR DISTINTOS TIPOS DE

OPERACIONES.

DIJIMOS QUE SQL SERVER TIENE 4 TIPOS DE OPERADORES: 1) RELACIONALES O DE COMPARACIÓN (LOS

VIMOS), 2) LÓGICOS (LO VEREMOS MÁS ADELANTE, 3) ARITMÉTICOS Y 4) DE CONCATENACIÓN.

LOS OPERADORES ARITMÉTICOS PERMITEN REALIZAR CÁLCULOS CON VALORES NUMÉRICOS.

SON: MULTIPLICACIÓN (*), DIVISIÓN (/) Y MÓDULO (%) (EL RESTO DE DIVIDIR NÚMEROS ENTEROS),

SUMA (+) Y RESTA (-).

ES POSIBLE OBTENER SALIDAS EN LAS CUALES UNA COLUMNA SEA EL RESULTADO DE UN CÁLCULO Y NO

UN CAMPO DE UNA TABLA.

SI QUEREMOS VER LOS TÍTULOS, PRECIO Y CANTIDAD DE CADA LIBRO ESCRIBIMOS LA SIGUIENTE

SENTENCIA:

SELECT TITULO,PRECIO,CANTIDAD

FROM LIBROS;

SI QUEREMOS SABER EL MONTO TOTAL EN DINERO DE UN TÍTULO PODEMOS MULTIPLICAR EL PRECIO POR

LA CANTIDAD POR CADA TÍTULO, PERO TAMBIÉN PODEMOS HACER QUE SQL SERVER REALICE EL

CÁLCULO Y LO INCLUYA EN UNA COLUMNA EXTRA EN LA SALIDA:

SELECT TITULO, PRECIO,CANTIDAD,

PRECIO*CANTIDAD

FROM LIBROS;

Page 21: Base de Datos SQL

SI QUEREMOS SABER EL PRECIO DE CADA LIBRO CON UN 10% DE DESCUENTO PODEMOS INCLUIR EN LA

SENTENCIA LOS SIGUIENTES CÁLCULOS:

SELECT TITULO,PRECIO,

PRECIO-(PRECIO*0.1)

FROM LIBROS;

TAMBIÉN PODEMOS ACTUALIZAR LOS DATOS EMPLEANDO OPERADORES ARITMÉTICOS:

UPDATE LIBROS SET PRECIO=PRECIO-(PRECIO*0.1);

TODAS LAS OPERACIONES MATEMÁTICAS RETORNAN "NULL" EN CASO DE ERROR. EJEMPLO:

SELECT 5/0;

LOS OPERADORES DE CONCATENACIÓN: PERMITE CONCATENAR CADENAS, EL MÁS (+).

PARA CONCATENAR EL TÍTULO, EL AUTOR Y LA EDITORIAL DE CADA LIBRO USAMOS EL OPERADOR DE

CONCATENACIÓN ("+"):

SELECT TITULO+'-'+AUTOR+'-'+EDITORIAL

FROM LIBROS;

NOTE QUE CONCATENAMOS ADEMÁS UNOS GUIONES PARA SEPARAR LOS CAMPOS.

23 - ALIAS

UNA MANERA DE HACER MÁS COMPRENSIBLE EL RESULTADO DE UNA CONSULTA CONSISTE EN CAMBIAR

LOS ENCABEZADOS DE LAS COLUMNAS.

POR EJEMPLO, TENEMOS LA TABLA "AGENDA" CON UN CAMPO "NOMBRE" (ENTRE OTROS) EN EL CUAL

SE ALMACENA EL NOMBRE Y APELLIDO DE NUESTROS AMIGOS; QUEREMOS QUE AL MOSTRAR LA

INFORMACIÓN DE DICHA TABLA APAREZCA COMO ENCABEZADO DEL CAMPO "NOMBRE" EL TEXTO

"NOMBRE Y APELLIDO", PARA ELLO COLOCAMOS UN ALIAS DE LA SIGUIENTE MANERA:

SELECT NOMBRE AS NOMBREYAPELLIDO,

DOMICILIO,TELEFONO

FROM AGENDA;

PARA REEMPLAZAR EL NOMBRE DE UN CAMPO POR OTRO, SE COLOCA LA PALABRA CLAVE "AS" SEGUIDO

DEL TEXTO DEL ENCABEZADO.

SI EL ALIAS CONSTA DE UNA SOLA CADENA LAS COMILLAS NO SON NECESARIAS, PERO SI CONTIENE MÁS

DE UNA PALABRA, ES NECESARIO COLOCARLA ENTRE COMILLAS SIMPLES:

SELECT NOMBRE AS 'NOMBRE Y APELLIDO',

DOMICILIO,TELEFONO

FROM AGENDA;

UN ALIAS PUEDE CONTENER HASTA 128 CARACTERES.

TAMBIÉN SE PUEDE CREAR UN ALIAS PARA COLUMNAS CALCULADAS.

LA PALABRA CLAVE "AS" ES OPCIONAL EN ALGUNOS CASOS, PERO ES CONVENIENTE USARLA.

Page 22: Base de Datos SQL

ENTONCES, UN "ALIAS" SE USA COMO NOMBRE DE UN CAMPO O DE UNA EXPRESIÓN. EN ESTOS CASOS,

SON OPCIONALES, SIRVEN PARA HACER MÁS COMPRENSIBLE EL RESULTADO; EN OTROS CASOS, QUE

VEREMOS MÁS ADELANTE, SON OBLIGATORIOS.

24 - FUNCIONES

UNA FUNCIÓN ES UN CONJUNTO DE SENTENCIAS QUE OPERAN COMO UNA UNIDAD LÓGICA.

UNA FUNCIÓN TIENE UN NOMBRE, RETORNA UN PARÁMETRO DE SALIDA Y OPCIONALMENTE ACEPTA PARÁMETROS DE ENTRADA. LAS

FUNCIONES DE SQL SERVER NO PUEDEN SER MODIFICADAS, LAS FUNCIONES DEFINIDAS POR EL USUARIO SI.

SQL SERVER OFRECE VARIOS TIPOS DE FUNCIONES PARA REALIZAR DISTINTAS OPERACIONES. SE PUEDEN CLASIFICAR DE LA SIGUIENTE

MANERA:

1) DE AGREGADO: REALIZAN OPERACIONES QUE COMBINAN VARIOS VALORES Y RETORNAN UN ÚNICO VALOR. SON "COUNT", "SUM", "MIN" Y "MAX".

2) ESCALARES: TOMAN UN SOLO VALOR Y RETORNAN UN ÚNICO VALOR. PUEDEN AGRUPARSE DE LA SIGUIENTE MANERA:

- DE CONFIGURACIÓN: RETORNAN INFORMACIÓN REFERIDA A LA CONFIGURACIÓN. EJEMPLO:

SELECT @@VERSION;

RETORNA LA FECHA, VERSIÓN Y TIPO DE PROCESADOR DE SQL SERVER.

- DE CURSORES: RETORNAN INFORMACIÓN SOBRE EL ESTADO DE UN CURSOR.

- DE FECHA Y HORA: OPERAN CON VALORES "DATETIME" Y "SMALLDATETIME". RECIBEN UN PARÁMETRO DE TIPO FECHA Y HORA Y

RETORNAN UN VALOR DE CADENA, NUMÉRICO O DE FECHA Y HORA.

- MATEMÁTICAS: REALIZAN OPERACIONES NUMÉRICAS, GEOMÉTRICAS Y TRIGONOMÉTRICAS.

- DE METADATOS: INFORMAN SOBRE LAS BASES DE DATOS Y LOS OBJETOS.

- DE SEGURIDAD: DEVUELVEN INFORMACIÓN REFERENTE A USUARIOS Y FUNCIONES.

- DE CADENA: OPERAN CON VALORES "CHAR", "VARCHAR", "NCHAR", "NVARCHAR", "BINARY" Y "VARBINARY" Y DEVUELVEN UN

VALOR DE CADENA O NUMÉRICO.

- DEL SISTEMA: INFORMAN SOBRE OPCIONES, OBJETOS Y CONFIGURACIONES DEL SISTEMA. EJEMPLO:

SELECT USER_NAME();

- ESTADÍSTICAS DEL SISTEMA: RETORNAN INFORMACIÓN REFERENTE AL RENDIMIENTO DEL SISTEMA.

- TEXTO E IMAGEN: REALIZAN OPERACIONES CON VALOR DE ENTRADA DE TIPO TEXT O IMAGE Y RETORNAN INFORMACIÓN REFERENTE

AL MISMO.

3) DE CONJUNTOS DE FILAS: RETORNAN CONJUNTOS DE REGISTROS.

Page 23: Base de Datos SQL

SE PUEDEN EMPLEAR LAS FUNCIONES DEL SISTEMA EN CUALQUIER LUGAR EN EL QUE SE PERMITA UNA EXPRESIÓN EN UNA SENTENCIA

"SELECT".

ESTUDIAREMOS ALGUNAS DE ELLAS.

25 - FUNCIONES PARA EL MANEJO DE CADENAS

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 POSICIÓN 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 NÚMEROS A CARACTERES; EL PRIMER PARÁMETRO INDICA EL VALOR

NUMÉRICO A CONVERTIR, EL SEGUNDO LA LONGITUD DEL RESULTADO (DEBE SER MAYOR O IGUAL A LA PARTE ENTERA DEL NÚMERO

MÁS 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 INGLÉS.

EJEMPLO: SE CONVIERTE EL VALOR NUMÉRICO "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 NUMÉRICO "123.456" A CADENA:

SELECT STR(123.456);

RETORNA '123';

SELECT STR(123.456,3);

RETORNA '123';

SI EL SEGUNDO PARÁMETRO ES MENOR A LA PARTE ENTERA DEL NÚMERO, DEVUELVE ASTERISCOS (*). EJEMPLO: SELECT

STR(123.456,2,3);

RETORNA "**".

- STUFF(CADENA1,INICIO,CANTIDAD,CADENA2): INSERTA LA CADENA ENVIADA COMO CUARTO ARGUMENTO, EN LA POSICIÓN

INDICADA EN EL SEGUNDO ARGUMENTO, REEMPLAZANDO LA CANTIDAD DE CARACTERES INDICADA POR EL TERCER ARGUMENTO EN LA

CADENA QUE ES PRIMER PARÁMETRO. STUFF SIGNIFICA RELLENAR EN INGLÉS. EJEMPLO:

SELECT STUFF('ABCDE',3,2,'OPQRS');

Page 24: Base de Datos SQL

RETORNA "ABOPQRSE". ES DECIR, COLOCA EN LA POSICIÓN 2 LA CADENA "OPQRS" Y REEMPLAZA 2 CARACTERES DE LA PRIMER

CADENA.

LOS ARGUMENTOS NUMÉRICOS DEBEN SER POSITIVOS Y MENOR O IGUAL A LA LONGITUD DE LA PRIMERA CADENA, CASO CONTRARIO, RETORNA "NULL".

SI EL TERCER ARGUMENTO ES MAYOR QUE LA PRIMERA CADENA, SE ELIMINA HASTA EL PRIMER CARÁCTER.

- LEN(CADENA): RETORNA LA LONGITUD DE LA CADENA ENVIADA COMO ARGUMENTO. "LEN" VIENE DE LENGTH, QUE SIGNIFICA

LONGITUD EN INGLÉS. EJEMPLO:

SELECT LEN('HOLA');

DEVUELVE 4.

- CHAR(X): RETORNA UN CARACTER EN CÓDIGO ASCII DEL ENTERO ENVIADO COMO ARGUMENTO. EJEMPLO:

SELECT CHAR(65);

RETORNA "A".

- 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 MINÚSCULAS. LOWER SIGNIFICA REDUCIR EN INGLÉS.

EJEMPLO:

SELECT LOWER('HOLA ESTUDIANTE');

RETORNA "HOLA ESTUDIANTE".

-UPPER(CADENA): RETORNAN LA CADENA CON TODOS LOS CARACTERES EN MAYÚSCULAS. EJEMPLO:

SELECT UPPER('HOLA ESTUDIANTE');

-LTRIM(CADENA): RETORNA LA CADENA CON LOS ESPACIOS DE LA IZQUIERDA ELIMINADOS. TRIM SIGNIFICA RECORTAR. EJEMPLO:

SELECT LTRIM(' HOLA ');

RETORNA "HOLA ".

Page 25: Base de Datos SQL

- 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 POSICIÓN DE COMIENZO (DE LA PRIMERA OCURRENCIA) DEL PATRÓN 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 POSICIÓN DONDE COMIENZA LA SUBCADENA EN LA CADENA, COMENZANDO

LA BÚSQUEDA DESDE LA POSICIÓN INDICADA POR "INICIO". SI EL TERCER ARGUMENTO NO SE COLOCA, LA BÚSQUEDA SE INICIA DESDE

0. SI NO LA ENCUENTRA, RETORNA 0. EJEMPLOS:

SELECT CHARINDEX('OR','JORGE LUIS BORGES',5);

RETORNA 13.

SELECT CHARINDEX('OR','JORGE LUIS BORGES');

RETORNA 2.

SELECT CHARINDEX('OR','JORGE LUIS BORGES',14);

RETORNA 0.

SELECT CHARINDEX('OR', 'JORGE LUIS BORGES');

Page 26: Base de Datos SQL

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.

26 - FUNCIONES MATEMÁTICAS

LAS FUNCIONES MATEMÁTICAS REALIZAN OPERACIONES CON EXPRESIONES NUMÉRICAS Y RETORNAN UN RESULTADO, OPERAN CON

TIPOS DE DATOS NUMÉRICOS.

MICROSOFT SQL SERVER TIENE ALGUNAS FUNCIONES PARA TRABAJAR CON NÚMEROS. AQUÍ PRESENTAMOS ALGUNAS.

-ABS(X): RETORNA EL VALOR ABSOLUTO DEL ARGUMENTO "X". EJEMPLO:

SELECT ABS(-20);

RETORNA 20.

-CEILING(X): REDONDEA HACIA ARRIBA EL ARGUMENTO "X". EJEMPLO:

SELECT CEILING(12.34);

RETORNA 13.

-FLOOR(X): REDONDEA HACIA ABAJO EL ARGUMENTO "X". EJEMPLO:

SELECT FLOOR(12.34);

RETORNA 12.

- %: %: DEVUELVE EL RESTO DE UNA DIVISIÓN. EJEMPLOS:

SELECT 10%3;

RETORNA 1.

SELECT 10%2;

RETORNA 0.

Page 27: Base de Datos SQL

-POWER(X,Y): RETORNA EL VALOR DE "X" ELEVADO A LA "Y" POTENCIA. EJEMPLO:

SELECT POWER(2,3);

RETORNA 8.

-ROUND(NUMERO,LONGITUD): RETORNA UN NÚMERO REDONDEADO A LA LONGITUD ESPECIFICADA. "LONGITUD" DEBE SER TINYINT, SMALLINT O INT. SI "LONGITUD" ES POSITIVO, EL NÚMERO DE DECIMALES ES REDONDEADO SEGÚN "LONGITUD"; SI ES NEGATIVO, EL

NÚMERO ES REDONDEADO DESDE LA PARTE ENTERA SEGÚN EL VALOR DE "LONGITUD". EJEMPLOS:

SELECT ROUND(123.456,1);

RETORNA "123.400", ES DECIR, REDONDEA DESDE EL PRIMER DECIMAL.

SELECT ROUND(123.456,2);

RETORNA "123.460", ES DECIR, REDONDEA DESDE EL SEGUNDO DECIMAL.

SELECT ROUND(123.456,-1);

RETORNA "120.000", ES DECIR, REDONDEA DESDE EL PRIMER VALOR ENTERO (HACIA LA IZQUIERDA).

SELECT ROUND(123.456,-2);

RETORNA "100.000", ES DECIR, REDONDEA DESDE EL SEGUNDO VALOR ENTERO (HACIA LA IZQUIERDA).

-SIGN(X): SI EL ARGUMENTO ES UN VALOR POSITIVO DEVUELVE 1;-1 SI ES NEGATIVO Y SI ES 0, 0.

-SQUARE(X): RETORNA EL CUADRADO DEL ARGUMENTO. EJEMPLO:

SELECT SQUARE(3); RETORNA 9.

-SRQT(X): DEVUELVE LA RAIZ CUADRADA DEL VALOR ENVIADO COMO ARGUMENTO.

SQL SERVER DISPONE DE FUNCIONES TRIGONOMÉTRICAS QUE RETORNAN RADIANES.

SE PUEDEN EMPLEAR ESTAS FUNCIONES ENVIANDO COMO ARGUMENTO EL NOMBRE DE UN CAMPO DE TIPO NUMÉRICO.

27 - FUNCIONES PARA EL USO DE FECHAS Y HORAS

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 ESPECÍFICA DE UNA FECHA, EL AÑO, TRIMESTRE, DÍA, HORA, ETC.

LOS VALORES PARA "PARTEDEFECHA" PUEDEN SER: YEAR (AÑO), QUARTER (CUARTO), MONTH (MES), DAY (DIA), WEEK (SEMANA), HOUR (HORA), MINUTE (MINUTO), SECOND (SEGUNDO) Y MILLISECOND (MILISEGUNDO). EJEMPLOS:

Page 28: Base de Datos SQL

SELECT DATEPART(MONTH,GETDATE());

RETORNA EL NÚMERO DE MES ACTUAL;

SELECT DATEPART(DAY,GETDATE());

RETORNA EL DÍA ACTUAL;

SELECT DATEPART(HOUR,GETDATE());

RETORNA LA HORA ACTUAL;

- DATENAME(PARTEDEFECHA,FECHA): RETORNA EL NOMBRE DE UNA PARTE ESPECÍFICA DE UNA FECHA. 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 PARÁMETRO, TANTAS VECES COMO LO INDICA EL SEGUNDO PARÁMETRO. LOS VALORES PARA EL PRIMER ARGUMENTO PUEDEN SER: YEAR (AÑO), QUARTER (CUARTO), MONTH (MES), DAY (DIA), WEEK (SEMANA), HOUR (HORA), MINUTE (MINUTO), SECOND (SEGUNDO) Y

MILLISECOND (MILISEGUNDO). EJEMPLOS:

SELECT DATEADD(DAY,3,'1980/11/02');

RETORNA "1980/11/05", AGREGA 3 DÍAS.

SELECT DATEADD(MONTH,3,'1980/11/02');

RETORNA "1981/02/02", AGREGA 3 MESES.

SELECT DATEADD(HOUR,2,'1980/11/02');

RETORNA "1980/02/02 2:00:00", AGREGA 2 HORAS.

SELECT DATEADD(MINUTE,16,'1980/11/02');

RETORNA "1980/02/02 00:16:00", AGREGA 16 MINUTOS.

- DATEDIFF(PARTEDELAFECHA,FECHA1,FECHA2): CALCULA EL INTERVALO DE TIEMPO (SEGÚN EL PRIMER ARGUMENTO) ENTRE LAS 2

FECHAS. EL RESULTADO ES UN VALOR ENTERO QUE CORRESPONDE A FECHA2-FECHA1. LOS VALORES DE "PARTEDELAFECHA) PUEDEN

SER LOS MISMOS QUE SE ESPECIFICARON ANTERIORMENTE. EJEMPLOS:

SELECT DATEDIFF (DAY,'2005/10/28','2006/10/28');

RETORNA 365 (DÍAS).

SELECT DATEDIFF(MONTH,'2005/10/28','2006/11/29');

Page 29: Base de Datos SQL

RETORNA 13 (MESES).

- DAY(FECHA): RETORNA EL DÍA DE LA FECHA ESPECIFICADA. EJEMPLO:

SELECT DAY(GETDATE());

- MONTH(FECHA): RETORNA EL MES DE LA FECHA ESPECIFICADA. EJEMPLO:

SELECT MONTH(GETDATE());

- YEAR(FECHA): RETORNA EL AÑO DE LA FECHA ESPECIFICADA. EJEMPLO:

SELECT YEAR(GETDATE());

SE PUEDEN EMPLEAR ESTAS FUNCIONES ENVIANDO COMO ARGUMENTO EL NOMBRE DE UN CAMPO DE TIPO DATETIME O

SMALLDATETIME.

28 - ORDENAR REGISTROS (ORDER BY)

PODEMOS ORDENAR EL RESULTADO DE UN "SELECT" PARA QUE LOS REGISTROS SE MUESTREN ORDENADOS POR ALGÚN CAMPO, PARA

ELLO USAMOS LA CLÁUSULA "ORDER BY".

LA SINTAXIS BÁSICA ES LA SIGUIENTE:

SELECT *FROM NOMBRETABLA ORDER BY CAMPO;

POR EJEMPLO, RECUPERAMOS LOS REGISTROS DE LA TABLA "LIBROS" ORDENADOS POR EL TÍTULO:

SELECT *FROM LIBROS ORDER BY TITULO;

APARECEN LOS REGISTROS ORDENADOS ALFABÉTICAMENTE POR EL CAMPO ESPECIFICADO.

TAMBIÉN PODEMOS COLOCAR EL NÚMERO DE ORDEN DEL CAMPO POR EL QUE QUEREMOS QUE SE ORDENE EN LUGAR DE SU NOMBRE, ES DECIR, REFERENCIAR A LOS CAMPOS POR SU POSICIÓN EN LA LISTA DE SELECCIÓN. POR EJEMPLO, QUEREMOS EL RESULTADO DEL

"SELECT" ORDENADO POR "PRECIO":

SELECT TITULO,AUTOR,PRECIO FROM LIBROS ORDER BY 3;

POR DEFECTO, SI NO ACLARAMOS EN LA SENTENCIA, LOS ORDENA DE MANERA ASCENDENTE (DE MENOR A MAYOR). PODEMOS ORDENARLOS DE MAYOR A MENOR, PARA ELLO AGREGAMOS LA PALABRA CLAVE "DESC":

SELECT *LIBROS ORDER BY EDITORIAL DESC;

TAMBIÉN PODEMOS ORDENAR POR VARIOS CAMPOS, POR EJEMPLO, POR "TITULO" Y "EDITORIAL":

SELECT *FROM LIBROS

Page 30: Base de Datos SQL

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 SELECCIÓN.

SE PERMITE ORDENAR POR VALORES CALCULADOS O EXPRESIONES.

LA CLÁUSULA "ORDER BY" NO PUEDE EMPLEARSE PARA CAMPOS TEXT, NTEXT E IMAGE.

29 - OPERADORES LÓGICOS ( AND - OR - NOT)

HASTA EL MOMENTO, HEMOS APRENDIDO A ESTABLECER UNA CONDICIÓN CON "WHERE" UTILIZANDO OPERADORES RELACIONALES.

PODEMOS ESTABLECER MÁS DE UNA CONDICIÓN CON LA CLÁUSULA "WHERE", PARA ELLO APRENDEREMOS LOS OPERADORES

LÓGICOS.

SON LOS SIGUIENTES:

- AND, SIGNIFICA "Y", - OR, SIGNIFICA "Y/O", - NOT, SIGNIFICA "NO", INVIERTE EL RESULTADO - (), PARÉNTESIS

LOS OPERADORES LÓGICOS SE USAN PARA COMBINAR CONDICIONES.

SI QUEREMOS RECUPERAR TODOS LOS LIBROS CUYO AUTOR SEA IGUAL A "BORGES" Y CUYO PRECIO NO SUPERE 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 CONDICIÓN, CON LA SEGUNDA CONDICIÓN O CON AMBAS CONDICIONES.

Page 31: Base de Datos SQL

LOS REGISTROS RECUPERADOS CON UNA SENTENCIA QUE UNE 2 CONDICIONES CON EL OPERADOR "OR", CUMPLEN 1 DE LAS

CONDICIONES O AMBAS.

QUEREMOS RECUPERAR LOS LIBROS QUE NO CUMPLAN LA CONDICIÓN DADA, POR EJEMPLO, AQUELLOS CUYA EDITORIAL NO SEA

"PLANETA":

SELECT *FROM LIBROS WHERE NOT EDITORIAL='PLANETA';

EL OPERADOR "NOT" INVIERTE EL RESULTADO DE LA CONDICIÓN A LA CUAL ANTECEDE.

LOS REGISTROS RECUPERADOS EN UNA SENTENCIA EN LA CUAL APARECE EL OPERADOR "NOT", NO CUMPLEN CON LA CONDICIÓN A LA

CUAL AFECTA EL "NOT".

LOS PARÉNTESIS SE USAN PARA ENCERRAR CONDICIONES, PARA QUE SE EVALÚEN COMO UNA SOLA EXPRESIÓN. CUANDO EXPLICITAMOS VARIAS CONDICIONES CON DIFERENTES OPERADORES LÓGICOS (COMBINAMOS "AND", "OR") PERMITE

ESTABLECER EL ORDEN DE PRIORIDAD DE LA EVALUACIÓN; ADEMÁS PERMITE DIFERENCIAR LAS EXPRESIONES MÁS CLARAMENTE.

POR EJEMPLO, LAS SIGUIENTES EXPRESIONES DEVUELVEN UN RESULTADO DIFERENTE:

SELECT*FROM LIBROS WHERE (AUTOR='BORGES') OR (EDITORIAL='PAIDOS' AND PRECIO<20); SELECT *FROM LIBROS WHERE (AUTOR='BORGES' OR EDITORIAL='PAIDOS') AND (PRECIO<20);

SI BIEN LOS PARÉNTESIS NO SON OBLIGATORIOS EN TODOS LOS CASOS, SE RECOMIENDA UTILIZARLOS PARA EVITAR CONFUSIONES.

EL ORDEN DE PRIORIDAD DE LOS OPERADORES LÓGICOS ES EL SIGUIENTE: "NOT" SE APLICA ANTES QUE "AND" Y "AND" ANTES QUE

"OR", SI NO SE ESPECIFICA UN ORDEN DE EVALUACIÓN MEDIANTE EL USO DE PARÉNTESIS. EL ORDEN EN EL QUE SE EVALÚAN LOS OPERADORES CON IGUAL NIVEL DE PRECEDENCIA ES INDEFINIDO, POR ELLO SE RECOMIENDA

USAR LOS PARÉNTESIS.

ENTONCES, PARA ESTABLECER MÁS DE UNA CONDICIÓN EN UN "WHERE" ES NECESARIO EMPLEAR OPERADORES LÓGICOS. "AND"

SIGNIFICA "Y", INDICA QUE SE CUMPLAN AMBAS CONDICIONES; "OR" SIGNIFICA "Y/O", INDICA QUE SE CUMPLA UNA U OTRA

CONDICIÓN (O AMBAS); "NOT" SIGNIFICA "NO", INDICA QUE NO SE CUMPLA LA CONDICIÓN ESPECIFICADA.

30 - OTROS OPERADORES RELACIONALES (IS NULL)

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 ESPECÍFICO:

Page 32: Base de Datos SQL

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 BÚSQUEDA POSITIVAS ("IS NULL"), EVITE LAS

NEGATIVAS ("IS NOT NULL") PORQUE CON ELLAS SE EVALÚAN TODOS LOS REGISTROS Y ESTO HACE MÁS

LENTA LA RECUPERACIÓN DE LOS DATOS.

31 - OTROS OPERADORES RELACIONALES (BETWEEN)

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 LÓGICO "AND":

SELECT *FROM LIBROS

WHERE PRECIO>=20 AND

PRECIO<=40;

PODEMOS USAR "BETWEEN" Y ASÍ SIMPLIFICAR LA CONSULTA:

SELECT *FROM LIBROS

WHERE PRECIO BETWEEN 20 AND 40;

AVERIGUAMOS SI EL VALOR DE UN CAMPO DADO (PRECIO) ESTÁ ENTRE LOS VALORES MÍNIMO Y MÁXIMO

ESPECIFICADOS (20 Y 40 RESPECTIVAMENTE).

"BETWEEN" SIGNIFICA "ENTRE". TRABAJA CON INTERVALO DE VALORES.

ESTE OPERADOR SE PUEDE EMPLEAR CON TIPOS DE DATOS NUMÉRICOS Y MONEY (EN TALES CASOS

INCLUYEN LOS VALORES MÍNIMO Y MÁXIMO) Y TIPOS DE DATOS FECHA Y HORA (INCLUYE SÓLO EL

VALOR MÍNIMO).

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 ESTÁN 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 BÚSQUEDA POSITIVAS ("BETWEEN"), EVITE LAS

NEGATIVAS ("NOT BETWEEN") PORQUE HACE MÁS LENTA LA RECUPERACIÓN DE LOS DATOS.

Page 33: Base de Datos SQL

ENTONCES, SE PUEDE USAR EL OPERADOR "BETWEEN" PARA REDUCIR LAS CONDICIONES "WHERE".

32 - OTROS OPERADORES RELACIONALES (IN)

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' USÁBAMOS 2

CONDICIONES:

SELECT *FROM LIBROS

WHERE AUTOR='BORGES' OR AUTOR='PAENZA';

PODEMOS USAR "IN" Y SIMPLIFICAR LA CONSULTA:

SELECT *FROM LIBROS

WHERE AUTOR IN('BORGES','PAENZA');

PARA RECUPERAR LOS LIBROS CUYO AUTOR NO SEA 'PAENZA' NI 'BORGES' USÁBAMOS:

SELECT *FROM LIBROS

WHERE AUTOR<>'BORGES' AND

AUTOR<>'PAENZA';

TAMBIÉN PODEMOS USAR "IN" ANTEPONIENDO "NOT":

SELECT *FROM LIBROS

WHERE AUTOR NOT IN ('BORGES','PAENZA');

EMPLEANDO "IN" AVERIGUAMOS SI EL VALOR DEL CAMPO ESTÁ INCLUIDO EN LA LISTA DE VALORES

ESPECIFICADA; CON "NOT" ANTECEDIENDO LA CONDICIÓN, INVERTIMOS EL RESULTADO, ES DECIR,

RECUPERAMOS LOS VALORES QUE NO SE ENCUENTRAN (COINDICEN) CON LA LISTA DE VALORES.

LOS VALORES "NULL" NO SE CONSIDERAN.

RECUERDE: SIEMPRE QUE SEA POSIBLE, EMPLEE CONDICIONES DE BÚSQUEDA POSITIVAS ("IN"), EVITE

LAS NEGATIVAS ("NOT IN") PORQUE CON ELLAS SE EVALÚN TODOS LOS REGISTROS Y ESTO HACE MÁS

LENTA LA RECUPERACIÓN DE LOS DATOS.

33 - BÚSQUEDA DE PATRONES (LIKE - NOT LIKE)

EXISTE UN OPERADOR RELACIONAL QUE SE USA PARA REALIZAR COMPARACIONES EXCLUSIVAMENTE DE

CADENAS, "LIKE" Y "NOT LIKE".

Page 34: Base de Datos SQL

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

COMPARACIÓN, BUSCA COINCIDENCIAS DE CADENAS COMPLETAS, REALIZA UNA BÚSQUEDA EXACTA.

IMAGINEMOS QUE TENEMOS REGISTRADOS ESTOS 2 LIBROS:

"EL ALEPH", "BORGES";

"ANTOLOGIA POETICA", "J.L. BORGES";

SI QUEREMOS RECUPERAR TODOS LOS LIBROS DE "BORGES" Y ESPECIFICAMOS LA SIGUIENTE

CONDICIÓN:

SELECT *FROM LIBROS

WHERE AUTOR='BORGES';

SÓLO APARECERÁ EL PRIMER REGISTRO, YA QUE LA CADENA "BORGES" NO ES IGUAL A LA CADENA "J.L.

BORGES".

ESTO SUCEDE PORQUE EL OPERADOR "=" (IGUAL), TAMBIÉN EL OPERADOR "<>" (DISTINTO) COMPARAN

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 SÍMBOLO "%" (PORCENTAJE) REEMPLAZA CUALQUIER CANTIDAD DE CARACTERES (INCLUYENDO

NINGÚN CARACTER). ES UN CARACTER COMODÍN. "LIKE" Y "NOT LIKE" SON OPERADORES DE

COMPARACIÓN QUE SEÑALAN IGUALDAD O DIFERENCIA.

PARA SELECCIONAR TODOS LOS LIBROS QUE COMIENCEN CON "M":

SELECT *FROM LIBROS

WHERE TITULO LIKE 'M%';

NOTE QUE EL SÍMBOLO "%" YA NO ESTÁ AL COMIENZO, CON ESTO INDICAMOS QUE EL TÍTULO DEBE

TENER 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 GUIÓN BAJO "_" REEMPLAZA

UN CARACTER, ES OTRO CARACTER COMODÍN. POR EJEMPLO, QUEREMOS VER LOS LIBROS DE "LEWIS

Page 35: Base de Datos SQL

CARROLL" PERO NO RECORDAMOS SI SE ESCRIBE "CARROLL" O "CARROLT", ENTONCES TIPEAMOS

ESTA CONDICIÓN:

SELECT *FROM LIBROS

WHERE AUTOR LIKE "%CARROL_";

OTRO CARACTER COMODÍN ES [] REEMPLAZA CUALQUIER CARÁCTER CONTENIDO EN EL CONJUNTO

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 COMODÍN 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 BÚSQUEDAS 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 '[';

34 - CONTAR REGISTROS (COUNT)

Page 36: Base de Datos SQL

EXISTEN EN SQL SERVER FUNCIONES QUE NOS PERMITEN CONTAR REGISTROS, CALCULAR SUMAS,

PROMEDIOS, OBTENER VALORES MÁXIMOS Y MÍNIMOS. ESTAS FUNCIONES SE DENOMINAN FUNCIONES DE

AGREGADO 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 FUNCIÓN "COUNT()":

SELECT COUNT(*)

FROM LIBROS;

LA FUNCIÓN "COUNT()" CUENTA LA CANTIDAD DE REGISTROS DE UNA TABLA, INCLUYENDO LOS QUE

TIENEN VALOR NULO.

TAMBIÉN PODEMOS UTILIZAR ESTA FUNCIÓN JUNTO CON LA CLÁUSULA "WHERE" PARA UNA CONSULTA

MÁS ESPECÍFICA. QUEREMOS SABER LA CANTIDAD DE LIBROS DE LA EDITORIAL "PLANETA":

SELECT COUNT(*)

FROM LIBROS

WHERE EDITORIAL='PLANETA';

PARA CONTAR LOS REGISTROS QUE TIENEN PRECIO (SIN TENER EN CUENTA LOS QUE TIENEN VALOR

NULO), USAMOS LA FUNCIÓN "COUNT()" Y EN LOS PARÉNTESIS COLOCAMOS EL NOMBRE DEL CAMPO QUE

NECESITAMOS CONTAR:

SELECT COUNT(PRECIO)

FROM LIBROS;

NOTE QUE "COUNT(*)" RETORNA LA CANTIDAD DE REGISTROS DE UNA TABLA (INCLUYENDO LOS QUE

TIENEN VALOR "NULL") MIENTRAS QUE "COUNT(PRECIO)" RETORNA LA CANTIDAD DE REGISTROS EN

LOS CUALES EL CAMPO "PRECIO" NO ES NULO. NO ES LO MISMO. "COUNT(*)" CUENTA REGISTROS, SI EN

LUGAR DE UN ASTERISCO COLOCAMOS COMO ARGUMENTO EL NOMBRE DE UN CAMPO, SE CONTABILIZAN

LOS REGISTROS CUYO VALOR EN ESE CAMPO NO ES NULO.

35 - CONTAR REGISTROS (COUNT_BIG)

RETORNA LA CANTIDAD DE REGISTROS. ES SIMILAR A LA FUNCIÓN "COUNT(*)", LA DIFERENCIA ES QUE

"COUNT_BIG" RETORNA UN VALOR "BIGINT" Y "COUNT", UN "INT".

"COUNT_BIG(*)" CUENTA LA CANTIDAD DE REGISTROS DE UNA TABLA, INCLUYENDO LOS VALORES

NULOS Y DUPLICADOS.

"COUNT_BIG(CAMPO)" RETORNA LA CANTIDAD DE REGISTROS CUYO VALOR EN EL CAMPO

ESPECIFICADO ENTRE PARÉNTESIS 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.

Page 37: Base de Datos SQL

AVERIGUEMOS LA CANTIDAD DE LIBROS USANDO LA FUNCIÓN "COUNT_BIG()":

SELECT COUNT_BIG(*)

FROM LIBROS;

NOTE QUE INCLUYE TODOS LOS LIBROS AUNQUE TENGAN VALOR NULO EN ALGÚN CAMPO.

CONTAMOS LOS LIBROS DE EDITORIAL "PLANETA":

SELECT COUNT_BIG(*)

FROM LIBROS

WHERE EDITORIAL='PLANETA';

CONTAMOS LOS REGISTROS QUE TIENEN PRECIO (SIN TENER EN CUENTA LOS QUE TIENEN VALOR NULO):

SELECT COUNT_BIG(PRECIO)

FROM LIBROS;

CONTAMOS LAS EDITORIALES (SIN REPETIR):

SELECT COUNT_BIG(DISTINCT EDITORIAL)

FROM LIBROS;

36 - FUNCIONES DE AGRUPAMIENTO (COUNT - SUM -

MIN - MAX - AVG)

HEMOS VISTO QUE SQL SERVER TIENE FUNCIONES QUE NOS PERMITEN CONTAR REGISTROS, CALCULAR

SUMAS, PROMEDIOS, OBTENER VALORES MÁXIMOS Y MÍNIMOS, LAS FUNCIONES DE AGREGADO.

YA HEMOS APRENDIDO UNA DE ELLAS, "COUNT()", VEAMOS OTRAS.

SE PUEDEN USAR EN UNA INSTRUCCIÓN "SELECT" Y COMBINARLAS CON LA CLÁUSULA "GROUP BY".

TODAS ESTAS FUNCIONES RETORNAN "NULL" SI NINGÚN REGISTRO CUMPLE CON LA CONDICIÓN DEL

"WHERE", EXCEPTO "COUNT" QUE EN TAL CASO RETORNA CERO.

EL TIPO DE DATO DEL CAMPO DETERMINA LAS FUNCIONES QUE SE PUEDEN EMPLEAR CON ELLAS.

LAS RELACIONES ENTRE LAS FUNCIONES DE AGRUPAMIENTO Y LOS TIPOS DE DATOS ES LA SIGUIENTE:

- COUNT: SE PUEDE EMPLEAR CON CUALQUIER TIPO DE DATO.

- MIN Y MAX: CON CUALQUIER TIPO DE DATO.

- SUM Y AVG: SÓLO EN CAMPOS DE TIPO NUMÉRICO.

LA FUNCIÓN "SUM()" RETORNA LA SUMA DE LOS VALORES QUE CONTIENE EL CAMPO ESPECIFICADO. SI

QUEREMOS SABER LA CANTIDAD TOTAL DE LIBROS QUE TENEMOS DISPONIBLES PARA LA VENTA,

DEBEMOS SUMAR TODOS LOS VALORES DEL CAMPO "CANTIDAD":

Page 38: Base de Datos SQL

SELECT SUM(CANTIDAD)

FROM LIBROS;

PARA AVERIGUAR EL VALOR MÁXIMO O MÍNIMO DE UN CAMPO USAMOS LAS FUNCIONES "MAX()" Y

"MIN()" RESPECTIVAMENTE.

QUEREMOS SABER CUÁL ES EL MAYOR PRECIO DE TODOS LOS LIBROS:

SELECT MAX(PRECIO)

FROM LIBROS;

ENTONCES, DENTRO DEL PARÉNTESIS DE LA FUNCIÓN COLOCAMOS EL NOMBRE DEL CAMPO DEL CUÁL

QUEREMOS EL MÁXIMO VALOR.

LA FUNCIÓN "AVG()" RETORNA EL VALOR PROMEDIO DE LOS VALORES DEL CAMPO ESPECIFICADO.

QUEREMOS SABER EL PROMEDIO DEL PRECIO DE LOS LIBROS REFERENTES A "PHP":

SELECT AVG(PRECIO)

FROM LIBROS

WHERE TITULO LIKE '%PHP%';

AHORA PODEMOS ENTENDER PORQUE ESTAS FUNCIONES SE DENOMINAN "FUNCIONES DE

AGRUPAMIENTO", PORQUE OPERAN SOBRE CONJUNTOS DE REGISTROS, NO CON DATOS INDIVIDUALES.

TRATAMIENTO DE LOS VALORES NULOS:

SI REALIZA UNA CONSULTA CON LA FUNCIÓN "COUNT" DE UN CAMPO QUE CONTIENE 18 REGISTROS, 2 DE

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

37 - AGRUPAR REGISTROS (GROUP BY)

HEMOS APRENDIDO QUE LAS FUNCIONES DE AGREGADO PERMITEN REALIZAR VARIOS CÁLCULOS

OPERANDO CON CONJUNTOS DE REGISTROS.

LAS FUNCIONES DE AGREGADO SOLAS PRODUCEN UN VALOR DE RESUMEN PARA TODOS LOS REGISTROS

DE UN CAMPO. PODEMOS GENERAR VALORES DE RESUMEN PARA UN SOLO CAMPO, COMBINANDO LAS

FUNCIONES DE AGREGADO CON LA CLÁUSULA "GROUP BY", QUE AGRUPA REGISTROS PARA CONSULTAS

DETALLADAS.

QUEREMOS SABER LA CANTIDAD DE LIBROS DE CADA EDITORIAL, PODEMOS TIPEAR LA SIGUIENTE

SENTENCIA:

SELECT COUNT(*) FROM LIBROS

WHERE EDITORIAL='PLANETA';

Y REPETIRLA CON CADA VALOR DE "EDITORIAL":

Page 39: Base de Datos SQL

SELECT COUNT(*) FROM LIBROS

WHERE EDITORIAL='EMECE';

SELECT COUNT(*) FROM LIBROS

WHERE EDITORIAL='PAIDOS';

...

PERO HAY OTRA MANERA, UTILIZANDO LA CLÁUSULA "GROUP BY":

SELECT EDITORIAL, COUNT(*)

FROM LIBROS

GROUP BY EDITORIAL;

LA INSTRUCCIÓN ANTERIOR SOLICITA QUE MUESTRE EL NOMBRE DE LA EDITORIAL Y CUENTE LA

CANTIDAD AGRUPANDO LOS REGISTROS POR EL CAMPO "EDITORIAL". COMO RESULTADO APARECEN LOS

NOMBRES DE LAS EDITORIALES Y LA CANTIDAD DE REGISTROS PARA CADA VALOR DEL CAMPO.

LOS VALORES NULOS SE PROCESAN COMO OTRO GRUPO.

ENTONCES, PARA SABER LA CANTIDAD DE LIBROS QUE TENEMOS DE CADA EDITORIAL, UTILIZAMOS LA

FUNCIÓN "COUNT()", AGREGAMOS "GROUP BY" (QUE AGRUPA REGISTROS) Y EL CAMPO POR EL QUE

DESEAMOS QUE SE REALICE EL AGRUPAMIENTO, TAMBIÉN COLOCAMOS EL NOMBRE DEL CAMPO A

RECUPERAR; LA SINTAXIS BÁSICA ES LA SIGUIENTE:

SELECT CAMPO, FUNCIONDEAGREGADO

FROM NOMBRETABLA

GROUP BY CAMPO;

TAMBIÉN SE PUEDE AGRUPAR POR MÁS DE UN CAMPO, EN TAL CASO, LUEGO DEL "GROUP BY" SE LISTAN

LOS CAMPOS, SEPARADOS POR COMAS. TODOS LOS CAMPOS QUE SE ESPECIFICAN EN LA CLÁUSULA

"GROUP BY" DEBEN ESTAR EN LA LISTA DE SELECCIÓN.

SELECT CAMPO1, CAMPO2, FUNCIONDEAGREGADO

FROM NOMBRETABLA

GROUP BY CAMPO1,CAMPO2;

PARA OBTENER LA CANTIDAD LIBROS CON PRECIO NO NULO, DE CADA EDITORIAL UTILIZAMOS LA

FUNCIÓN "COUNT()" ENVIÁNDOLE COMO ARGUMENTO EL CAMPO "PRECIO", AGREGAMOS "GROUP BY" Y

EL CAMPO POR EL QUE DESEAMOS QUE SE REALICE EL AGRUPAMIENTO (EDITORIAL):

SELECT EDITORIAL, COUNT(PRECIO)

FROM LIBROS

GROUP BY EDITORIAL;

COMO RESULTADO APARECEN LOS NOMBRES DE LAS EDITORIALES Y LA CANTIDAD DE REGISTROS DE

CADA UNA, SIN CONTAR LOS QUE TIENEN PRECIO NULO.

RECUERDE LA DIFERENCIA DE LOS VALORES QUE RETORNA LA FUNCIÓN "COUNT()" CUANDO ENVIAMOS

COMO ARGUMENTO UN ASTERISCO O EL NOMBRE DE UN CAMPO: EN EL PRIMER CASO CUENTA TODOS LOS

REGISTROS INCLUYENDO LOS QUE TIENEN VALOR NULO, EN EL SEGUNDO, LOS REGISTROS EN LOS CUALES

EL CAMPO ESPECIFICADO ES NO NULO.

PARA CONOCER EL TOTAL EN DINERO DE LOS LIBROS AGRUPADOS POR EDITORIAL:

SELECT EDITORIAL, SUM(PRECIO)

FROM LIBROS

Page 40: Base de Datos SQL

GROUP BY EDITORIAL;

PARA SABER EL MÁXIMO Y MÍNIMO VALOR DE LOS LIBROS AGRUPADOS POR EDITORIAL:

SELECT EDITORIAL,

MAX(PRECIO) AS MAYOR,

MIN(PRECIO) AS MENOR

FROM LIBROS

GROUP BY EDITORIAL;

PARA CALCULAR EL PROMEDIO DEL VALOR DE LOS LIBROS AGRUPADOS POR EDITORIAL:

SELECT EDITORIAL, AVG(PRECIO)

FROM LIBROS

GROUP BY EDITORIAL;

ES POSIBLE LIMITAR LA CONSULTA CON "WHERE".

SI INCLUYE UNA CLÁUSULA "WHERE", SÓLO SE AGRUPAN LOS REGISTROS QUE CUMPLEN LAS

CONDICIONES.

VAMOS A CONTAR Y AGRUPAR POR EDITORIAL CONSIDERANDO SOLAMENTE LOS LIBROS CUYO PRECIO

SEA MENOR A 30 PESOS:

SELECT EDITORIAL, COUNT(*)

FROM LIBROS

WHERE PRECIO<30

GROUP BY EDITORIAL;

NOTE QUE LAS EDITORIALES QUE NO TIENEN LIBROS QUE CUMPLAN LA CONDICIÓN, NO APARECEN EN LA

SALIDA. PARA QUE APAREZCAN TODOS LOS VALORES DE EDITORIAL, INCLUSO LOS QUE DEVUELVEN CERO

O "NULL" EN LA COLUMNA DE AGREGADO, DEBEMOS EMPLEAR LA PALABRA CLAVE "ALL" AL LADO DE

"GROUP BY":

SELECT EDITORIAL, COUNT(*)

FROM LIBROS

WHERE PRECIO<30

GROUP BY ALL EDITORIAL;

ENTONCES, USAMOS "GROUP BY" PARA ORGANIZAR REGISTROS EN GRUPOS Y OBTENER UN RESUMEN DE

DICHOS GRUPOS. SQL SERVER PRODUCE UNA COLUMNA DE VALORES POR CADA GRUPO, DEVOLVIENDO

FILAS POR CADA GRUPO ESPECIFICADO.

38 - SELECCIONAR GRUPOS (HAVING)

ASÍ COMO LA CLÁUSULA "WHERE" PERMITE SELECCIONAR (O RECHAZAR) REGISTROS INDIVIDUALES; LA

CLÁUSULA "HAVING" PERMITE SELECCIONAR (O RECHAZAR) UN GRUPO DE REGISTROS.

SI QUEREMOS SABER LA CANTIDAD DE LIBROS AGRUPADOS POR EDITORIAL USAMOS LA SIGUIENTE

INSTRUCCIÓN YA APRENDIDA:

Page 41: Base de Datos SQL

SELECT EDITORIAL, COUNT(*)

FROM LIBROS

GROUP BY EDITORIAL;

SI QUEREMOS SABER LA CANTIDAD DE LIBROS AGRUPADOS POR EDITORIAL PERO CONSIDERANDO SÓLO

ALGUNOS GRUPOS, POR EJEMPLO, LOS QUE DEVUELVAN UN VALOR MAYOR A 2, USAMOS LA SIGUIENTE

INSTRUCCIÓN:

SELECT EDITORIAL, COUNT(*) FROM LIBROS

GROUP BY EDITORIAL

HAVING COUNT(*)>2;

SE UTILIZA "HAVING", SEGUIDO DE LA CONDICIÓN DE BÚSQUEDA, PARA SELECCIONAR CIERTAS FILAS

RETORNADAS POR LA CLÁUSULA "GROUP BY".

VEAMOS OTROS EJEMPLOS. QUEREMOS EL PROMEDIO DE LOS PRECIOS DE LOS LIBROS AGRUPADOS POR

EDITORIAL, PERO SOLAMENTE DE AQUELLOS GRUPOS CUYO PROMEDIO SUPERE LOS 25 PESOS:

SELECT EDITORIAL, AVG(PRECIO) FROM LIBROS

GROUP BY EDITORIAL

HAVING AVG(PRECIO)>25;

EN ALGUNOS CASOS ES POSIBLE CONFUNDIR LAS CLÁUSULAS "WHERE" Y "HAVING". QUEREMOS

CONTAR 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 CLÁUSULA "WHERE" CON LA CLÁUSULA "HAVING"; LA PRIMERA

ESTABLECE CONDICIONES PARA LA SELECCIÓN DE REGISTROS DE UN "SELECT"; LA SEGUNDA ESTABLECE

CONDICIONES PARA LA SELECCIÓN 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 CONDICIÓN DADA EN

"WHERE", LUEGO LOS AGRUPA POR "EDITORIAL" Y FINALMENTE RECHAZA LOS GRUPOS QUE NO

CUMPLAN CON LA CONDICIÓN DADA EN EL "HAVING".

Page 42: Base de Datos SQL

SE EMPLEA LA CLÁUSULA "HAVING" CON FUNCIONES DE AGRUPAMIENTO, ESTO NO PUEDE HACERLO LA

CLÁUSULA "WHERE". POR EJEMPLO QUEREMOS EL PROMEDIO DE LOS PRECIOS AGRUPADOS POR

EDITORIAL, DE AQUELLAS EDITORIALES QUE TIENEN MÁS DE 2 LIBROS:

SELECT EDITORIAL, AVG(PRECIO) FROM LIBROS

GROUP BY EDITORIAL

HAVING COUNT(*) > 2;

EN UNA CLÁUSULA "HAVING" PUEDE HABER HASTA 128 CONDICIONES. CUANDO UTILICE VARIAS

CONDICIONES, TIENE QUE COMBINARLAS CON OPERADORES LÓGICOS (AND, OR, NOT).

PODEMOS ENCONTRAR EL MAYOR VALOR DE LOS LIBROS AGRUPADOS Y ORDENADOS POR EDITORIAL Y

SELECCIONAR LAS FILAS QUE TENGAN UN VALOR MENOR A 100 Y MAYOR A 30:

SELECT EDITORIAL, MAX(PRECIO) AS 'MAYOR'

FROM LIBROS

GROUP BY EDITORIAL

HAVING MIN(PRECIO)<100 AND

MIN(PRECIO)>30

ORDER BY EDITORIAL;

ENTONCES, USAMOS LA CLAÚSULA "HAVING" PARA RESTRINGIR LAS FILAS QUE DEVUELVE UNA SALIDA

"GROUP BY". VA SIEMPRE DESPUÉS DE LA CLÁUSULA "GROUP BY" Y ANTES DE LA CLÁUSULA "ORDER

BY" SI LA HUBIERE.

39 - MODIFICADOR DEL GROUP BY (WITH ROLLUP)

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

ADEMÁS 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:

Page 43: Base de Datos SQL

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 CLÁUSULA "GROUP BY" PERMITE AGREGAR EL MODIFICADOR "WITH ROLLUP", EL CUAL AGREGA

REGISTROS EXTRAS AL RESULTADO DE UNA CONSULTA, QUE MUESTRAN OPERACIONES DE RESUMEN.

SI AGRUPAMOS POR 2 CAMPOS, "CIUDAD" Y "SEXO":

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 AGRUPACIÓN, APARECE UNA FILA EXTRA CON EL/ LOS CAMPOS QUE NO SE

CONSIDERAN, SETEADOS A "NULL".

CON "ROLLUP" SE PUEDE AGRUPAR HASTA POR 10 CAMPOS.

ES POSIBLE INCLUIR VARIAS FUNCIONES DE AGRUPAMIENTO, POR EJEMPLO, QUEREMOS LA CANTIDAD 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".

40 - MODIFICADOR DEL GROUP BY (WITH CUBE)

HEMOS APRENDIDO EL MODIFICADOR "ROLLUP", QUE AGREGA FILAS EXTRAS MOSTRANDO RESULTADOS

DE RESUMEN POR CADA GRUPO Y SUBGRUPO.

Page 44: Base de Datos SQL

POR EJEMPLO, TENEMOS UNA TABLA LLAMADA "EMPLEADOS" QUE CONTIENE, ENTRE OTROS, LOS

CAMPOS "SEXO", "ESTADOCIVIL" Y "SECCION".

SI SE AGRUPA POR ESOS TRES CAMPOS (EN ESE ORDEN) Y SE EMPLEA "ROLLUP":

SELECT SEXO,ESTADOCIVIL,SECCION,

COUNT(*) FROM EMPLEADOS

GROUP BY SEXO,ESTADOCIVIL,SECCION

WITH ROLLUP;

SQL SERVER GENERA VARIAS FILAS EXTRAS CON INFORMACIÓN DE RESUMEN PARA LOS SIGUIENTES

SUBGRUPOS:

- SEXO Y ESTADOCIVIL (SECCION SETEADO A "NULL"),

- SEXO (ESTADOCIVIL Y SECCION SETEADOS A "NULL") Y

- TOTAL (TODOS LOS CAMPOS SETEADOS A "NULL").

SI SE EMPLEA "CUBE":

SELECT SEXO,ESTADOCIVIL,SECCION,

COUNT(*) FROM EMPLEADOS

GROUP BY SEXO,ESTADOCIVIL,SECCION

WITH CUBE;

RETORNA MÁS FILAS EXTRAS ADEMÁS DE LAS ANTERIORES:

- SEXO Y SECCION (ESTADOCIVIL SETEADO A "NULL"),

- ESTADOCIVIL Y SECCION (SEXO SETEADO A "NULL"),

- SECCION (SEXO Y ESTADOCIVIL SETEADOS A "NULL") Y

- ESTADOCIVIL (SEXO Y SECCION SETEADOS A "NULL"),

ES DECIR, "CUBE" GENERA FILAS DE RESUMEN DE SUBGRUPOS PARA TODAS LAS COMBINACIONES

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

41 - FUNCIÓN GROUPING

LA FUNCIÓN "GROUPING" SE EMPLEA CON LOS OPERADORES "ROLLUP" Y "CUBE" PARA DISTINGUIR LOS

VALORES DE DETALLE Y DE RESUMEN EN EL RESULTADO. ES DECIR, PERMITE DIFERENCIAR SI LOS

VALORES "NULL" QUE APARECEN EN EL RESULTADO SON VALORES NULOS DE LAS TABLAS O SI SON UNA

FILA GENERADA POR LOS OPERADORES "ROLLUP" O "CUBE".

CON ESTA FUNCIÓN APARECE UNA NUEVA COLUMNA EN LA SALIDA, UNA POR CADA "GROUPING";

RETORNA EL VALOR 1 PARA INDICAR QUE LA FILA REPRESENTA LOS VALORES DE RESUMEN DE "ROLLUP"

O "CUBE" Y EL VALOR 0 PARA REPRESENTAR LOS VALORES DE CAMPO.

SÓLO SE PUEDE EMPLEAR LA FUNCIÓN "GROUPING" EN LOS CAMPOS QUE APARECEN EN LA CLÁUSULA

"GROUP BY".

Page 45: Base de Datos SQL

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 FUNCIÓN "GROUPING" PARA DISTINGUIR LOS VALORES DE

DETALLE Y DE RESUMEN EN EL RESULTADO.

Page 46: Base de Datos SQL

42 - CLÁUSULAS COMPUTE Y COMPUTE BY

LAS CLÁUSULAS "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 BÁSICA Y GENERAL ES LA SIGUIENTE:

SELECT CAMPOS

FROM TABLA

COMPUTE FUNCION(CAMPO);

EL CAMPO QUE SE COLOQUE EN LA CLÁUSULA "COMPUTE" DEBE ESTAR INCLUIDA EN LA LISTA DE

CAMPOS DEL "SELECT".

PARA VER TODOS LOS DATOS DE LOS VISITANTES Y EL PROMEDIO DEL MONTO DE COMPRA DE NUESTRA

TABLA "VISITANTES":

SELECT *FROM VISITANTES

COMPUTE AVG(MONTOCOMPRA);

PRODUCE LA MISMA SALIDA QUE LAS SIGUIENTES 2 SENTENCIAS:

SELECT *FROM VISITANTES;

SELECT AVG(MONTOCOMPRA) FROM VISITANTES;

EN UNA MISMA INSTRUCCIÓN SE PUEDEN COLOCAR VARIAS CLÁUSULAS "COMPUTE":

SELECT EDAD,CIUDAD,MONTOCOMPRA

FROM VISITANTES

COMPUTE AVG(EDAD),SUM(MONTOCOMPRA);

"COMPUTE BY" GENERA CORTES DE CONTROL Y SUBTOTALES. SE GENERAN FILAS DE DETALLE Y VARIOS

VALORES DE RESUMEN CUANDO CAMBIAN LOS VALORES DEL CAMPO.

CON "COMPUTE BY" SE DEBE USAR TAMBIÉN LA CLÁUSULA "ORDER BY" Y LOS CAMPOS QUE SE

INCLUYAN LUEGO DE "BY" DEBEN ESTAR EN EL "ORDER BY". LISTANDO VARIOS CAMPOS LUEGO DEL

"BY" CORTA UN GRUPO EN SUBGRUPOS Y APLICA LA FUNCIÓN DE AGREGADO EN CADA NIVEL DE

AGRUPAMIENTO:

SELECT NOMBRE,CIUDAD,PROVINCIA

FROM VISITANTES

ORDER BY PROVINCIA

COMPUTE COUNT(PROVINCIA)

BY PROVINCIA;

SELECT NOMBRE,CIUDAD,PROVINCIA

FROM VISITANTES

Page 47: Base de Datos SQL

ORDER BY PROVINCIA,CIUDAD

COMPUTE COUNT(PROVINCIA)

BY PROVINCIA,CIUDAD;

LOS CAMPOS QUE APARECEN LUEGO DE LA CLÁUSULA "COMPUTE BY" DEBEN SER IDÉNTICOS A UN

SUBCONJUNTO DE LOS CAMPOS QUE APARECEN DESPUÉS DE "ORDER BY" Y ESTAR EN EL MISMO ORDEN.

SI LA CLÁUSULA "ORDER BY" TIENE LOS SIGUIENTES CAMPOS:

... ORDER BY A,B,C...

LA CLÁUSULA "COMPUTE BY" PUEDE INCLUIR LOS SIGUIENTES SUBCONJUNTOS DE CAMPOS:

... COMPUTE ...

BY A...

O

... COMPUTE ...

BY A,B...

O

... COMPUTE ...

BY A,B,C...

EN UNA MISMA INSTRUCCIÓN SE PUEDEN COLOCAR VARIAS CLÁUSULAS "COMPUTE" COMBINADAS CON

VARIAS CLÁUSULAS "COMPUTE BY":

SELECT *FROM VISITANTES

ORDER BY PROVINCIA,CIUDAD

COMPUTE AVG(EDAD), SUM(MONTOCOMPRA)

COMPUTE AVG(MONTOCOMPRA),COUNT(PROVINCIA)

BY PROVINCIA,CIUDAD;

EL RESULTADO DE LA CONSULTA ANTERIOR MUESTRA EL PROMEDIO DE LA COMPRA Y LA CANTIDAD AL

FINAL DE 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 CLÁUSULA "COMPUTE" O

"COMPUTE BY".

43 - REGISTROS DUPLICADOS (DISTINCT)

CON LA CLÁUSULA "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 REPETICIÓN USAMOS:

SELECT DISTINCT AUTOR FROM LIBROS;

TAMBIÉN PODEMOS TIPEAR:

SELECT AUTOR FROM LIBROS

Page 48: Base de Datos SQL

GROUP BY AUTOR;

NOTE QUE EN LOS TRES CASOS ANTERIORES APARECE "NULL" COMO UN VALOR PARA "AUTOR"· SI SÓLO

QUEREMOS LA LISTA DE AUTORES CONOCIDOS, ES DECIR, NO QUEREMOS INCLUIR "NULL" EN LA LISTA,

PODEMOS UTILIZAR LA SENTENCIA SIGUIENTE:

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

TAMBIÉN PUEDE UTILIZARSE CON "GROUP BY" PARA CONTAR LOS DIFERENTES AUTORES POR

EDITORIAL:

SELECT EDITORIAL, COUNT(DISTINCT AUTOR)

FROM LIBROS

GROUP BY EDITORIAL;

LA CLÁUSULA "DISTINCT" AFECTA A TODOS LOS CAMPOS PRESENTADOS. PARA MOSTRAR LOS TÍTULOS Y

EDITORIALES DE LOS LIBROS SIN REPETIR TÍTULOS NI EDITORIALES, USAMOS:

SELECT DISTINCT TITULO,EDITORIAL

FROM LIBROS

ORDER BY TITULO;

NOTE QUE LOS REGISTROS NO ESTÁN DUPLICADOS, APARECEN TÍTULOS IGUALES PERO CON EDITORIAL

DIFERENTE, CADA REGISTRO ES DIFERENTE.

LA PALABRA CLAVE "DISTINCT" NO ESTÁ PERMITIDA CON LAS CLÁUSULAS "COMPUTE" Y "COMPUTE

BY".

ENTONCES, "DISTINCT" ELIMINA REGISTROS DUPLICADOS.

44 - CLÁUSULA TOP

Page 49: Base de Datos SQL

LA PALABRA CLAVE "TOP" SE EMPLEA PARA OBTENER SÓLO UNA CANTIDAD LIMITADA DE REGISTROS,

LOS PRIMEROS N REGISTROS DE UNA CONSULTA.

CON LA SIGUIENTE CONSULTA OBTENEMOS TODOS LOS DATOS DE LOS PRIMEROS 2 LIBROS DE LA TABLA:

SELECT TOP 2 *FROM LIBROS;

ES DECIR, LUEGO DEL "SELECT" SE COLOCA "TOP" SEGUIDO DE UN NÚMERO ENTERO POSITIVO Y LUEGO

SE CONTINÚA CON LA CONSULTA.

SE PUEDE COMBINAR CON "ORDER BY":

SELECT TOP 3 TITULO,AUTOR

FROM LIBROS

ORDER BY AUTOR;

EN LA CONSULTA ANTERIOR SOLICITAMOS LOS TÍTULOS Y AUTORES DE LOS 3 PRIMEROS LIBROS,

ORDENADOS POR AUTOR.

CUANDO SE COMBINA CON "ORDER BY" ES POSIBLE EMPLEAR TAMBIÉN LA CLÁUSULA "WITH TIES".

ESTA CLÁUSULA PERMITE INCLUIR EN LA SELECCION, TODOS LOS REGISTROS QUE TENGAN EL MISMO

VALOR DEL CAMPO POR EL QUE SE ORDENA, QUE EL ÚLTIMO REGISTRO RETORNADO SI EL ÚLTIMO

REGISTRO RETORNADO (ES DECIR, EL NÚMERO N) TIENE UN VALOR REPETIDO EN EL REGISTRO N+1. ES

DECIR, SI EL VALOR DEL CAMPO POR EL CUAL SE ORDENA DEL ÚLTIMO REGISTRO RETORNADO (EL

NÚMERO N) ESTÁ REPETIDO EN LOS SIGUIENTES REGISTROS (ES DECIR, EL N+1 TIENE EL MISMO VALOR

QUE N, Y EL N+2, ETC.), LO INCLUYE EN LA SELECCIÓN.

VEAMOS UN EJEMPLO:

SELECT TOP 3 WITH TIES

*FROM LIBROS

ORDER BY AUTOR;

ESTA CONSULTA SOLICITA EL RETORNO DE LOS PRIMEROS 3 REGISTROS; EN CASO QUE EL REGISTRO

NÚMERO 4 (Y LOS POSTERIORES), TENGAN EL MISMO VALOR EN "AUTOR" QUE EL ÚLTIMO REGISTRO

RETORNADO (NÚMERO 3), TAMBIÉN APARECERÁN EN LA SELECCIÓN.

SI COLOCAMOS UN VALOR PARA "TOP" QUE SUPERA LA CANTIDAD DE REGISTROS DE LA TABLA, SQL

SERVER MUESTRA TODOS LOS REGISTROS.

45 - CLAVE PRIMARIA COMPUESTA

LAS CLAVES PRIMARIAS PUEDEN SER SIMPLES, FORMADAS POR UN SOLO CAMPO O COMPUESTAS, MÁS DE

UN CAMPO.

RECORDEMOS QUE UNA CLAVE PRIMARIA IDENTIFICA 1 SOLO REGISTRO EN UNA TABLA.

Page 50: Base de Datos SQL

PARA UN VALOR DEL CAMPO CLAVE EXISTE SOLAMENTE 1 REGISTRO. LOS VALORES NO SE REPITEN NI

PUEDEN SER NULOS.

EXISTE UNA PLAYA DE ESTACIONAMIENTO QUE ALMACENA CADA DÍA LOS DATOS DE LOS VEHÍCULOS QUE

INGRESAN EN LA TABLA LLAMADA "VEHICULOS" CON LOS SIGUIENTES CAMPOS:

- 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 MÁS DE UNA VEZ EN

EL DÍA A LA PLAYA; TAMPOCO PODEMOS USAR LA HORA DE ENTRADA PORQUE VARIOS AUTOS PUEDEN

INGRESAR A UNA MISMA HORA.

TAMPOCO SIRVEN LOS OTROS CAMPOS.

COMO NINGÚN CAMPO, POR SI SÓLO CUMPLE CON LA CONDICIÓN PARA SER CLAVE, ES DECIR, DEBE

IDENTIFICAR UN SOLO REGISTRO, EL VALOR NO PUEDE REPETIRSE, DEBEMOS USAR 2 CAMPOS.

DEFINIMOS UNA CLAVE COMPUESTA CUANDO NINGÚN CAMPO POR SI SOLO CUMPLE CON LA CONDICIÓN

PARA SER CLAVE.

EN ESTE EJEMPLO, UN AUTO PUEDE INGRESAR VARIAS VECES EN UN DÍA A LA PLAYA, PERO SIEMPRE SERÁ

A DISTINTA HORA.

USAMOS 2 CAMPOS COMO CLAVE, LA PATENTE JUNTO CON LA HORA DE LLEGADA, ASÍ IDENTIFICAMOS

UNÍVOCAMENTE CADA REGISTRO.

PARA ESTABLECER MÁS DE UN CAMPO COMO CLAVE PRIMARIA USAMOS LA SIGUIENTE SINTAXIS:

CREATE TABLE VEHICULOS(

PATENTE CHAR(6) NOT NULL,

TIPO CHAR(1),--'A'=AUTO, 'M'=MOTO

HORALLEGADA DATETIME,

HORASALIDA DATETIME,

PRIMARY KEY(PATENTE,HORALLEGADA)

);

NOMBRAMOS LOS CAMPOS QUE FORMARÁN PARTE DE LA CLAVE SEPARADOS POR COMAS.

AL INGRESAR LOS REGISTROS, SQL SERVER CONTROLA QUE LOS VALORES PARA LOS CAMPOS

ESTABLECIDOS COMO CLAVE PRIMARIA NO ESTÉN REPETIDOS EN LA TABLA; SI ESTUVIESEN REPETIDOS,

MUESTRA UN MENSAJE Y LA INSERCIÓN NO SE REALIZA. LO MISMO SUCEDE SI REALIZAMOS UNA

ACTUALIZACIÓN.

ENTONCES, SI UN SOLO CAMPO NO IDENTIFICA UNÍVOCAMENTE UN REGISTRO PODEMOS DEFINIR UNA

CLAVE PRIMARIA COMPUESTA, ES DECIR FORMADA POR MÁS DE UN CAMPO.

46 - INTEGRIDAD DE LOS DATOS

Page 51: Base de Datos SQL

ES IMPORTANTE, AL DISEÑAR UNA BASE DE DATOS Y LAS TABLAS QUE CONTIENE, TENER EN CUENTA LA

INTEGRIDAD DE LOS DATOS, ESTO SIGNIFICA QUE LA INFORMACIÓN ALMACENADA EN LAS TABLAS DEBE

SER VÁLIDA, 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, NUMÉRICOS, ETC.), LA ACEPTACIÓN O NO DE

VALORES NULOS, EL VALOR POR DEFECTO. TAMBIÉN HEMOS ASEGURADO QUE CADA REGISTRO DE UNA

TABLA SEA ÚNICO DEFINIENDO UNA CLAVE PRIMARIA Y EMPLEANDO LA PROPIEDAD IDENTITY.

SQL SERVER OFRECE MÁS ALTERNATIVAS, ADEMÁS DE LAS APRENDIDAS, PARA RESTRINGIR Y VALIDAR

LOS DATOS, LAS VEREMOS ORDENADAMENTE Y AL FINALIZAR HAREMOS UN RESUMEN DE LAS MISMAS.

COMENZAMOS POR LAS RESTRICCIONES.

LAS RESTRICCIONES (CONSTRAINTS) SON UN MÉTODO PARA MANTENER LA INTEGRIDAD DE LOS DATOS,

ASEGURANDO QUE LOS VALORES INGRESADOS SEAN VÁLIDOS Y QUE LAS RELACIONES ENTRE LAS TABLAS

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 INFORMACIÓN ACERCA DE LAS RESTRICCIONES DE DICHA TABLA.

CUANDO SE AGREGA UNA RESTRICCIÓN A UNA TABLA, SQL SERVER COMPRUEBA LOS DATOS

EXISTENTES.

HAY VARIOS TIPOS DE RESTRICCIONES.

47 - RESTRICCIÓN DEFAULT

LA RESTRICCIÓN "DEFAULT" ESPECIFICA UN VALOR POR DEFECTO PARA UN CAMPO CUANDO NO SE

INSERTA EXPLÍCITAMENTE EN UN COMANDO "INSERT".

ANTERIORMENTE, PARA ESTABLECER UN VALOR POR DEFECTO PARA UN CAMPO EMPLEÁBAMOS LA

CLÁUSULA "DEFAULT" AL CREAR LA TABLA, POR EJEMPLO:

CREATE TABLE LIBROS(

...

AUTOR VARCHAR(30) DEFAULT 'DESCONOCIDO',

...

);

CADA VEZ QUE ESTABLECÍAMOS UN VALOR POR DEFECTO PARA UN CAMPO DE UNA TABLA, SQL SERVER

CREABA AUTOMÁTICAMENTE UNA RESTRICCIÓN "DEFAULT" PARA ESE CAMPO DE ESA TABLA.

Page 52: Base de Datos SQL

DICHA RESTRICCIÓN, A LA CUAL NO LE DÁBAMOS UN NOMBRE, RECIBÍA UN NOMBRE DADO POR SQL

SERVER QUE CONSISTE "DF" (POR DEFAULT), SEGUIDO DEL NOMBRE DE LA TABLA, EL NOMBRE DEL

CAMPO Y LETRAS Y NÚMEROS ALEATORIOS.

PODEMOS AGREGAR UNA RESTRICCIÓN "DEFAULT" A UNA TABLA EXISTENTE CON LA SINTAXIS BÁSICA

SIGUIENTE:

ALTER TABLE NOMBRETABLA

ADD CONSTRAINT NOMBRECONSTRAINT

DEFAULT VALORPORDEFECTO

FOR CAMPO;

EN LA SENTENCIA SIGUIENTE AGREGAMOS UNA RESTRICCIÓN "DEFAULT" AL CAMPO AUTOR DE LA

TABLA EXISTENTE "LIBROS", QUE ALMACENA EL VALOR "DESCONOCIDO" EN DICHO CAMPO SI NO

INGRESAMOS UN VALOR EN UN "INSERT":

ALTER TABLE LIBROS

ADD CONSTRAINT DF_LIBROS_AUTOR

DEFAULT 'DESCONOCIDO'

FOR AUTOR;

POR CONVENCIÓN, CUANDO DEMOS EL NOMBRE A LAS RESTRICCIONES "DEFAULT" EMPLEAREMOS UN

FORMATO SIMILAR AL QUE LE DA SQL SERVER: "DF_NOMBRETABLA_NOMBRECAMPO".

SOLAMENTE SE PERMITE UNA RESTRICCIÓN "DEFAULT" POR CAMPO Y NO SE PUEDE EMPLEAR JUNTO

CON LA PROPIEDAD "IDENTITY". UNA TABLA PUEDE TENER VARIAS RESTRICCIONES "DEFAULT" PARA

SUS DISTINTOS CAMPOS.

LA RESTRICCIÓN "DEFAULT" ACEPTA VALORES TOMADOS DE FUNCIONES DEL SISTEMA, POR EJEMPLO,

PODEMOS ESTABLECER QUE EL VALOR POR DEFECTO DE UN CAMPO DE TIPO DATETIME SEA

"GETDATE()".

PODEMOS VER INFORMACIÓN REFERENTE A LAS RESTRICIONES DE UNA TABLA CON EL PROCEDIMIENTO

ALMACENADO "SP_HELPCONTRAINT":

SP_HELPCONSTRAINT LIBROS;

APARECEN VARIAS COLUMNAS CON LA SIGUIENTE INFORMACIÓN:

- CONSTRAINT_TYPE: EL TIPO DE RESTRICCIÓN Y SOBRE QUÉ CAMPO ESTÁ ESTABLECIDA

(DEFAULT ON COLUMN AUTOR),

- CONSTRAINT_NAME: EL NOMBRE DE LA RESTRICCIÓN (DF_LIBROS_AUTOR),

- DELETE_ACTION Y UPDATE_ACTION: NO TIENEN VALORES PARA ESTE TIPO DE RESTRICCIÓN.

- STATUS_ENABLED Y STATUS_FOR_REPLICATION: NO TIENEN VALORES PARA ESTE TIPO

DE RESTRICCIÓN.

- CONSTRAINT_KEYS: EL VALOR POR DEFECTO (DESCONOCIDO).

ENTONCES, LA RESTRICCIÓN "DEFAULT" ESPECIFICA UN VALOR POR DEFECTO PARA UN CAMPO CUANDO

NO SE INSERTA EXPLÍCITAMENTE EN UN "INSERT", SE PUEDE ESTABLECER UNO POR CAMPO Y NO SE

PUEDE EMPLEAR JUNTO CON LA PROPIEDAD "IDENTITY".

48 - RESTRICCIÓN CHECK

Page 53: Base de Datos SQL

LA RESTRICCIÓN "CHECK" ESPECIFICA LOS VALORES QUE ACEPTA UN CAMPO, EVITANDO QUE SE

INGRESEN VALORES INAPROPIADOS.

LA SINTAXIS BÁSICA ES LA SIGUIENTE:

ALTER TABLE NOMBRETABLA

ADD CONSTRAINT NOMBRECONSTRAINT

CHECK CONDICION;

TRABAJAMOS CON LA TABLA "LIBROS" DE UNA LIBRERÍA QUE TIENE LOS SIGUIENTES CAMPOS: CODIGO,

TITULO, AUTOR, EDITORIAL, PRECIOMIN (QUE INDICA EL PRECIO PARA LOS MINORISTAS) Y PRECIOMAY

(QUE INDICA 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 RESTRICCIÓN "CHECK":

ALTER TABLE LIBROS

ADD CONSTRAINT CK_LIBROS_PRECIO_POSITIVO

CHECK (PRECIOMIN>=0 AND PRECIOMAY>=0);

ESTE TIPO DE RESTRICCIÓN VERIFICA LOS DATOS CADA VEZ QUE SE EJECUTA UNA SENTENCIA "INSERT"

O "UPDATE", ES DECIR, ACTÚA EN INSERCIONES Y ACTUALIZACIONES.

SI LA TABLA CONTIENE REGISTROS QUE NO CUMPLEN CON LA RESTRICCIÓN QUE SE VA A ESTABLECER,

LA RESTRICCIÓN NO SE PUEDE ESTABLECER, HASTA QUE TODOS LOS REGISTROS CUMPLAN CON DICHA

RESTRICCIÓN.

LA CONDICIÓN PUEDE HACER REFERENCIA A OTROS CAMPOS DE LA MISMA TABLA. POR EJEMPLO,

PODEMOS CONTROLAR QUE EL PRECIO MAYORISTA NO SEA MAYOR AL PRECIO MINORISTA:

ALTER TABLE LIBROS

ADD CONSTRAINT CK_LIBROS_PRECIOMINMAY

CHECK (PRECIOMAY<=PRECIOMIN);

POR CONVENCIÓN, CUANDO DEMOS EL NOMBRE A LAS RESTRICCIONES "CHECK" SEGUIREMOS LA MISMA

ESTRUCTURA: COMENZAMOS CON "CK", SEGUIDO DEL NOMBRE DE LA TABLA, DEL CAMPO Y ALGUNA

PALABRA CON LA CUAL PODAMOS IDENTIFICAR FÁCILMENTE DE QUÉ SE TRATA LA RESTRICCIÓN, POR SI

TENEMOS VARIAS RESTRICCIONES "CHECK" PARA EL MISMO CAMPO.

UN CAMPO PUEDE TENER VARIAS RESTRICCIONES RESTRICCIONES "CHECK" Y UNA RESTRICCIÓN

"CHECK" PUEDE INCLUIR VARIOS CAMPOS.

LAS CONDICIONES PARA RESTRICCIONES "CHECK" TAMBIÉN PUEDEN PUEDEN INCLUIR UN PATRÓN O UNA

LISTA DE VALORES. POR EJEMPLO ESTABLECER QUE CIERTO CAMPO CONSTE DE 4 CARACTERES, 2

LETRAS Y 2 DÍGITOS:

...

CHECK (CAMPO LIKE '[A-Z][A-Z][0-9][0-9]');

O ESTABLECER QUE CIERTO CAMPO ASUMA SÓLO LOS VALORES QUE SE LISTAN:

Page 54: Base de Datos SQL

...

CHECK (CAMPO IN ('LUNES','MIERCOLES','VIERNES'));

NO SE PUEDE APLICAR ESTA RESTRICCIÓN JUNTO CON LA PROPIEDAD "IDENTITY".

SI UN CAMPO PERMITE VALORES NULOS, "NULL" ES UN VALOR ACEPTADO AUNQUE NO ESTÉ INCLUIDO EN

LA CONDICIÓN DE RESTRICCIÓN.

SI INTENTAMOS ESTABLECER UNA RESTRICCIÓN "CHECK" PARA UN CAMPO QUE ENTRA EN CONFLICTO

CON OTRA RESTRICCIÓN "CHECK" ESTABLECIDA AL MISMO CAMPO, SQL SERVER NO LO PERMITE.

PERO SI ESTABLECEMOS UNA RESTRICCIÓN "CHECK" PARA UN CAMPO QUE ENTRA EN CONFLICTO CON

UNA RESTRICCIÓN "DEFAULT" ESTABLECIDA PARA EL MISMO CAMPO, SQL SERVER LO PERMITE; PERO

AL INTENTAR INGRESAR UN REGISTRO, APARECE UN MENSAJE DE ERROR.

49 - DESHABILITAR RESTRICCIONES (WITH CHECK -

NOCHECK)

SABEMOS QUE SI AGREGAMOS UNA RESTRICCIÓN A UNA TABLA QUE CONTIENE DATOS, SQL SERVER LOS

CONTROLA PARA ASEGURARSE QUE CUMPLEN CON LA CONDICIÓN DE LA RESTRICCIÓN, SI ALGÚN

REGISTRO NO LA CUMPLE, LA RESTRICCIÓN NO SE ESTABLECECE.

ES POSIBLE DESHABILITAR ESTA COMPROBACIÓN EN CASO DE RESTRICCIONES "CHECK".

PODEMOS HACERLO CUANDO AGREGAMOS LA RESTRICCIÓN "CHECK" A UNA TABLA PARA QUE SQL

SERVER ACEPTE LOS VALORES YA ALMACENADOS QUE INFRINGEN LA RESTRICCIÓN. PARA ELLO

DEBEMOS INCLUIR LA OPCIÓN "WITH NOCHECK" EN LA INSTRUCCIÓN "ALTER TABLE":

ALTER TABLE LIBROS

WITH NOCHECK

ADD CONSTRAINT CK_LIBROS_PRECIO

CHECK (PRECIO>=0);

LA RESTRICCIÓN NO SE APLICA EN LOS DATOS EXISTENTES, PERO SI INTENTAMOS INGRESAR UN NUEVO

VALOR QUE NO CUMPLA LA RESTRICCIÓN, SQL SERVER NO LO PERMITE.

ENTONCES, PARA EVITAR LA COMPROBACIÓN DE DATOS EXISTENTES AL CREAR LA RESTRICCIÓN, LA

SINTAXIS BÁSICA ES LA SIGUIENTE:

ALTER TABLE TABLA

WITH NOCHECK

ADD CONSTRAINT NOMBRERESTRICCION

CHECK (CONDICION);

POR DEFECTO, SI NO ESPECIFICAMOS, LA OPCIÓN ES "WITH CHECK".

Page 55: Base de Datos SQL

TAMBIÉN PODEMOS DESHABILITAR LAS RESTRICCIONES PARA AGREGAR O ACTUALIZAR DATOS SIN

COMPROBARLA:

ALTER TABLE LIBROS

NOCHECK CONSTRAINT CK_LIBROS_PRECIO;

EN EL EJEMPLO ANTERIOR DESHABILITAMOS LA RESTRICCIÓN "CK_LIBROS_PRECIO" PARA PODER

INGRESAR UN VALOR NEGATIVO PARA "PRECIO".

PARA HABILITAR UNA RESTRICCIÓN DESHABILITADA SE EJECUTA LA MISMA INSTRUCCIÓN PERO CON LA

CLÁUSULA "CHECK" O "CHECK ALL":

ALTER TABLE LIBROS

CHECK CONSTRAINT CK_LIBROS_PRECIO;

SI SE EMPLEA "CHECK CONSTRAINT ALL" NO SE COLOCA NOMBRE DE RESTRICCIONES, HABILITA TODAS

LAS RESTRICCIONES QUE TIENE LA TABLA NOMBRADA.

PARA HABILITAR O DESHABILITAR RESTRICCIONES LA COMPROBACIÓN DE DATOS EN INSERCIONES O

ACTUALIZACIONES, LA SINTAXIS BÁSICA ES:

ALTER TABLE NOMBRETABLA

OPCIONDERESTRICCION CONSTRAINT NOMBRERESTRICCION;

PARA SABER SI UNA RESTRICCIÓN ESTÁ HABILITADA O NO, PODEMOS EJECUTAR EL PROCEDIMIENTO

ALMACENADO "SP_HELPCONSTRAINT" Y FIJARNOS LO QUE INFORMA LA COLUMNA "STATUS_ENABLED".

ENTONCES, LAS CLÁUSULAS "CHECK" Y "NOCHECK" PERMITEN HABILITAR O DESHABILITAR

RESTRICCIONES "CHECK" (TAMBIÉN LAS RESTRICCIONES "FOREIGN KEY" QUE VEREMOS MÁS

ADELANTE), A LAS DEMÁS SE LAS DEBE ELIMINAR ("DEFAULT" Y LAS QUE VEREMOS POSTERIORMENTE).

50 - RESTRICCIÓN PRIMARY KEY

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 EMPLEÁBAMOS 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)

);

Page 56: Base de Datos SQL

CADA VEZ QUE ESTABLECÍAMOS LA CLAVE PRIMARIA PARA LA TABLA, SQL SERVER CREABA

AUTOMÁTICAMENTE UNA RESTRICCIÓN "PRIMARY KEY" PARA DICHA TABLA. DICHA RESTRICCIÓN, A LA

CUAL NO LE DÁBAMOS UN NOMBRE, RECIBÍA UN NOMBRE DADO POR SQL SERVER QUE COMIENZA CON

"PK" (POR PRIMARY KEY), SEGUIDO DEL NOMBRE DE LA TABLA Y UNA SERIE DE LETRAS Y NÚMEROS

ALEATORIOS.

PODEMOS AGREGAR UNA RESTRICCIÓN "PRIMARY KEY" A UNA TABLA EXISTENTE CON LA SINTAXIS

BÁSICA SIGUIENTE:

ALTER TABLE NOMBRETABLA

ADD CONSTRAINT NOMBRECONSTRAINT

PRIMARY KEY (CAMPO,...);

EN EL SIGUIENTE EJEMPLO DEFINIMOS UNA RESTRICCIÓN "PRIMARY KEY" PARA NUESTRA TABLA

"LIBROS" PARA ASEGURARNOS QUE CADA LIBRO TENDRÁ UN CÓDIGO DIFERENTE Y ÚNICO:

ALTER TABLE LIBROS

ADD CONSTRAINT PK_LIBROS_CODIGO

PRIMARY KEY(CODIGO);

CON ESTA RESTRICCIÓN, SI INTENTAMOS INGRESAR UN REGISTRO CON UN VALOR PARA EL CAMPO

"CODIGO" QUE YA EXISTE O EL VALOR "NULL", APARECE UN MENSAJE DE ERROR, PORQUE NO SE

PERMITEN VALORES DUPLICADOS NI NULOS. IGUALMENTE, SI ACTUALIZAMOS.

POR CONVENCIÓN, CUANDO DEMOS EL NOMBRE A LAS RESTRICCIONES "PRIMARY KEY" SEGUIREMOS EL

FORMATO "PK_NOMBRETABLA_NOMBRECAMPO".

SABEMOS QUE CUANDO AGREGAMOS UNA RESTRICCIÓN A UNA TABLA QUE CONTIENE INFORMACIÓN,

SQL SERVER CONTROLA LOS DATOS EXISTENTES PARA CONFIRMAR QUE CUMPLEN LAS EXIGENCIAS DE

LA RESTRICCIÓN, SI NO LOS CUMPLE, LA RESTRICCIÓN NO SE APLICA Y APARECE UN MENSAJE DE ERROR.

POR EJEMPLO, SI INTENTAMOS DEFINIR LA RESTRICCIÓN "PRIMARY KEY" PARA "LIBROS" Y HAY

REGISTROS CON CÓDIGOS REPETIDOS O CON UN VALOR "NULL", LA RESTRICCIÓN NO SE ESTABLECE.

CUANDO ESTABLECÍAMOS UNA CLAVE PRIMARIA AL DEFINIR LA TABLA, AUTOMÁTICAMENTE SQL

SERVER REDEFINÍA EL CAMPO COMO "NOT NULL"; PERO AL AGREGAR UNA RESTRICCIÓN "PRIMARY

KEY", LOS CAMPOS QUE SON CLAVE PRIMARIA DEBEN HABER SIDO DEFINIDOS "NOT NULL" (O SER

IMPLÍCITAMENTE "NOT NULL" SI SE DEFINEN IDENTITY).

SQL SERVER PERMITE DEFINIR SOLAMENTE UNA RESTRICCIÓN "PRIMARY KEY" POR TABLA, QUE

ASEGURA LA UNICIDAD DE CADA REGISTRO DE UNA TABLA.

SI EJECUTAMOS EL PROCEDIMIENTO ALMACENADO "SP_HELPCONSTRAINT" JUNTO AL NOMBRE DE LA

TABLA, PODEMOS VER LAS RESTRICCIONES "PRIMARY KEY" (Y TODOS LOS TIPOS DE RESTRICCIONES) DE

DICHA TABLA.

UN CAMPO CON UNA RESTRICCIÓN "PRIMARY KEY" PUEDE TENER UNA RESTRICCIÓN "CHECK".

UN CAMPO "PRIMARY KEY" TAMBIÉN ACEPTA UNA RESTRICCIÓN "DEFAULT" (EXCEPTO SI ES IDENTITY),

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

Page 57: Base de Datos SQL

51 - RESTRICCIÓN UNIQUE

HEMOS VISTO QUE LAS RESTRICCIONES APLICADAS A TABLAS ASEGURAN VALORES ÚNICOS PARA CADA

REGISTRO.

ANTERIORMENTE APRENDIMOS LA RESTRICCIÓN "PRIMARY KEY", OTRA RESTRICCIÓN PARA LAS TABLAS

ES "UNIQUE".

LA RESTRICCIÓN "UNIQUE" IMPIDE LA DUPLICACIÓN 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 NÚMERO DE LEGAJO) PERO SE

NECESITA ASEGURAR QUE OTROS DATOS TAMBIÉN SEAN ÚNICOS Y NO SE REPITAN (COMO NÚMERO DE

DOCUMENTO).

LA SINTAXIS GENERAL ES LA SIGUIENTE:

ALTER TABLE NOMBRETABLA

ADD CONSTRAINT NOMBRERESTRICCION

UNIQUE (CAMPO);

EJEMPLO:

ALTER TABLE ALUMNOS

ADD CONSTRAINT UQ_ALUMNOS_DOCUMENTO

UNIQUE (DOCUMENTO);

EN EL EJEMPLO ANTERIOR SE AGREGA UNA RESTRICCIÓN "UNIQUE" SOBRE EL CAMPO "DOCUMENTO"

DE LA TABLA "ALUMNOS", ESTO ASEGURA QUE NO SE PUEDA INGRESAR UN DOCUMENTO SI YA EXISTE.

ESTA RESTRICCIÓN PERMITE VALORES NULOS, ASI QUE SI SE INGRESA EL VALOR "NULL" PARA EL CAMPO

"DOCUMENTO", SE ACEPTA.

POR CONVENCIÓN, CUANDO DEMOS EL NOMBRE A LAS RESTRICCIONES "UNIQUE" SEGUIREMOS LA MISMA

ESTRUCTURA: "UQ_NOMBRETABLA_NOMBRECAMPO". QUIZÁ PAREZCA INNECESARIO COLOCAR

EL NOMBRE DE LA TABLA, PERO CUANDO EMPLEEMOS VARIAS TABLAS VERÁ QUE ES ÚTIL IDENTIFICAR

LAS RESTRICCIONES POR TIPO, TABLA Y CAMPO.

RECUERDE QUE CUANDO AGREGAMOS UNA RESTRICCIÓN A UNA TABLA QUE CONTIENE INFORMACIÓN,

SQL SERVER CONTROLA LOS DATOS EXISTENTES PARA CONFIRMAR QUE CUMPLEN LA CONDICIÓN DE LA

RESTRICCIÓN, SI NO LOS CUMPLE, LA RESTRICCIÓN NO SE APLICA Y APARECE UN MENSAJE DE ERROR. EN

EL CASO DEL EJEMPLO ANTERIOR, SI LA TABLA CONTIENE NÚMEROS DE DOCUMENTO DUPLICADOS, LA

RESTRICCIÓN NO PODRÁ ESTABLECERSE; SI PODRÁ ESTABLECERSE SI TIENE VALORES NULOS.

SQL SERVER CONTROLA LA ENTRADA DE DATOS EN INSERCIONES Y ACTUALIZACIONES EVITANDO QUE

SE INGRESEN VALORES DUPLICADOS.

52 - INFORMACIÓN DE RESTRICCIONES

Page 58: Base de Datos SQL

(SP_HELPCONSTRAINT)

EL PROCEDIMIENTO ALMACENADO "SP_HELPCONSTRAINT" SEGUIDO DEL NOMBRE DE UNA TABLA

MUESTRA LA INFORMACIÓN REFERENTE A TODAS LAS RESTRICCIONES ESTABLECIDAS EN DICHA TABLA,

DEVUELVE LAS SIGUIENTES COLUMNAS:

- CONSTRAINT_TYPE: TIPO DE RESTRICCIÓN. SI ES UNA RESTRICCIÓN 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 RESTRICCIÓN.

- DELETE_ACTION: SOLAMENTE ES APLICABLE PARA RESTRICCIONES DE TIPO "FOREIGN KEY" (LA

VEREMOS POSTERIORMENTE).

- UPDATE_ACTION: SÓLO ES APLICABLE PARA RESTRICCIONES DE TIPO "FOREIGN KEY" (LA VEREMOS

POSTERIORMENTE).

- 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

RESTRICCIÓN 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 RESTRICCIÓN PARA LA QUE NO SE APLIQUE.

- CONSTRAINT_KEYS: SI ES UNA RESTRICCIÓN "CHECK" MUESTRA LA CONDICIÓN DE CHEQUEO; SI ES

UNA RESTRICCIÓN "DEFAULT", EL VALOR POR DEFECTO; SI ES UNA "PRIMARY KEY" O "UNIQUE"

MUESTRA EL/ LOS CAMPOS A LOS QUE SE APLICARON LA RESTRICCIÓN.

53 - ELIMINAR RESTRICCIONES (ALTER TABLE - DROP)

PARA ELIMINAR UNA RESTRICCIÓN, LA SINTAXIS BÁSICA ES LA SIGUIENTE:

ALTER TABLE NOMBRETABLA

DROP NOMBRERESTRICCION;

PARA ELIMINAR LA RESTRICCIÓN "DF_LIBROS_AUTOR" DE LA TABLA LIBROS TIPEAMOS:

ALTER TABLE LIBROS

DROP DF_LIBROS_AUTOR;

PUEDEN ELIMINARSE VARIAS RESTRICCIONES CON UNA SOLA INSTRUCCIÓN SEPARÁNDOLAS POR COMAS.

CUANDO ELIMINAMOS UNA TABLA, TODAS LAS RESTRICCIONES QUE FUERON ESTABLECIDAS EN ELLA, SE

ELIMINAN TAMBIÉN.

Page 59: Base de Datos SQL

54 - CREAR Y ASOCIAR REGLAS (CREATE RULE - SP_BINDRULE)

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 AUTOMÁTICAMENTE

POR SQL SERVER. HAY 3 TIPOS:

I) DE LOS CAMPOS (HACE REFERENCIA A LOS VALORES VÁLIDOS PARA UN CAMPO DETERMINADO). PUEDEN SER:

A) DEFAULT: ESPECIFICA UN VALOR POR DEFECTO PARA UN CAMPO CUANDO NO SE INSERTA EXPLÍCITAMENTE 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 UNÍVOCAMENTE CADA UNO DE LOS REGISTROS; ASEGURA QUE NO HAYA VALORES

DUPLICADOS NI VALORES NULOS. SE CREA UN ÍNDICE AUTOMÁTICAMENTE.

B) UNIQUE: IMPIDE LA DUPLICACIÓN DE CLAVES ALTERNAS (NO PRIMARIAS). SE PERMITEN VALORES NULOS. SE CREA UN

ÍNDICE AUTOMÁTICAMENTE.

III) REFERENCIAL: LO VEREMOS MÁS ADELANTE.

2. REGLAS (RULES) Y 3. VALORES PREDETERMINADOS (DEFAULTS).

VEAMOS LAS REGLAS.

LAS REGLAS ESPECIFICAN LOS VALORES QUE SE PUEDEN INGRESAR EN UN CAMPO, ASEGURANDO QUE LOS DATOS SE ENCUENTREN EN

UN INTERVALO DE VALORES ESPECÍFICO, COINCIDAN CON UNA LISTA DE VALORES O SIGAN UN PATRÓN.

UNA REGLA SE ASOCIA A UN CAMPO DE UNA TABLA (O A UN TIPO DE DATO DEFINIDO POR EL USUARIO, TEMA QUE VEREMOS

POSTERIORMENTE).

UN CAMPO PUEDE TENER SOLAMENTE UNA REGLA ASOCIADO A ÉL.

SINTAXIS BÁSICA 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 CONDICIÓN.

POR CONVENCIÓN, NOMBRAREMOS LAS REGLAS COMENZANDO CON "RG", EL NOMBRE DEL CAMPO AL QUE SE ASOCIA Y ALGUNA

PALABRA QUE HAGA REFERENCIA A LA CONDICIÓN.

Page 60: Base de Datos SQL

LA VARIABLE PUEDE TENER CUALQUIER NOMBRE, PERO DEBE ESTAR PRECEDIDO POR EL SIGNO ARROBA (@), DICHA VARIABLE SERÁ

REEMPLAZADA POR EL VALOR DEL CAMPO CUANDO SE ASOCIE.

LA CONDICIÓN SE REFIERE A LOS VALORES PERMITIDOS PARA INSERCIONES Y ACTUALIZACIONES Y PUEDE CONTENER CUALQUIER

EXPRESIÓN VÁLIDA PARA UNA CLÁUSULA "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 BÁSICA:

EXEC SP_BINDRULE NOMBREREGLA, 'TABLA.CAMPO';

ASOCIAMOS LA REGLA CREADA ANTERIORMENTE AL CAMPO "SUELDO" DE LA TABLA "EMPLEADOS":

EXEC SP_BINDRULE RG_SUELDO_INTERVALO, 'EMPLEADOS.SUELDO';

SI INTENTAMOS AGREGAR (O ACTUALIZAR) UN REGISTRO CON VALOR PARA EL CAMPO "SUELDO" QUE NO ESTÉ EN EL INTERVALO DE

VALORES ESPECIFICADO EN LA REGLA, APARECE UN MENSAJE DE ERROR INDICANDO QUE HAY CONFLICTO CON LA REGLA Y LA

INSERCIÓN (O ACTUALIZACIÓN) NO SE REALIZA.

SQL SERVER NO CONTROLA LOS DATOS EXISTENTES PARA CONFIRMAR QUE CUMPLEN CON LA REGLA COMO LO HACE AL APLICAR

RESTRICCIONES; SI NO LOS CUMPLE, LA REGLA SE ASOCIA IGUALMENTE; PERO AL EJECUTAR UNA INSTRUCCIÓN "INSERT" O "UPDATE"

MUESTRA UN MENSAJE DE ERROR, ES DECIR, ACTÚA EN INSERCIONES Y ACTUALIZACIONES.

LA REGLA DEBE SER COMPATIBLE CON EL TIPO DE DATOS DEL CAMPO AL CUAL SE ASOCIA; SI ESTO NO SUCEDE, SQL SERVER NO LO

INFORMA AL CREAR LA REGLA NI AL ASOCIARLA, PERO AL EJECUTAR UNA INSTRUCCIÓN "INSERT" O "UPDATE" MUESTRA UN MENSAJE

DE ERROR.

NO SE PUEDE CREAR UNA REGLA PARA CAMPOS DE TIPO TEXT, IMAGE, O TIMESTAMP.

SI ASOCIA UNA NUEVA REGLA A UN CAMPO QUE YA TIENE ASOCIADA OTRA REGLA, LA NUEVA REGLA REEEMPLAZA LA ASOCIACIÓN

ANTERIOR; PERO LA PRIMERA REGLA NO DESAPARECE, SOLAMENTE SE DESHACE LA ASOCIACIÓN.

LA SENTENCIA "CREATE RULE" NO PUEDE COMBINARSE CON OTRAS SENTENCIAS EN UN LOTE.

LA FUNCIÓN QUE CUMPLE UNA REGLA ES BÁSICAMENTE LA MISMA QUE UNA RESTRICCIÓN "CHECK", LAS SIGUIENTES

CARACTERÍSTICAS EXPLICAN ALGUNAS DIFERENCIAS ENTRE ELLAS:

- PODEMOS DEFINIR VARIAS RESTRICCIONES "CHECK" SOBRE UN CAMPO, UN CAMPO SOLAMENTE PUEDE TENER UNA REGLA ASOCIADA

A ÉL;

- UNA RESTRICCIÓN "CHECK" SE ALMACENA CON LA TABLA, CUANDO ÉSTA SE ELIMINA, LAS RESTRICCIONES TAMBIÉN SE BORRAN. LAS

REGLAS SON OBJETOS DIFERENTES E INDEPENDIENTES DE LAS TABLAS, SI ELIMINAMOS UNA TABLA, LAS ASOCIACIONES DESAPARECEN, PERO LAS REGLAS SIGUEN EXISTIENDO EN LA BASE DE DATOS;

- UNA RESTRICCIÓN "CHECK" PUEDE INCLUIR VARIOS CAMPOS; UNA REGLA PUEDE ASOCIARSE A DISTINTOS CAMPOS (INCLUSO DE

DISTINTAS TABLAS);

Page 61: Base de Datos SQL

- UNA RESTRICCIÓN "CHECK" PUEDE HACER REFERENCIA A OTROS CAMPOS DE LA MISMA TABLA, UNA REGLA NO.

UN CAMPO PUEDE TENER REGLAS ASOCIADAS A ÉL Y RESTRICCIONES "CHECK". SI HAY CONFLICTO ENTRE ELLAS, SQL SERVER NO LO

INFORMA AL CREARLAS Y/O ASOCIARLAS, PERO AL INTENTAR INGRESAR UN VALOR QUE ALGUNA DE ELLAS NO PERMITA, APARECE UN

MENSAJE DE ERROR.

CON "SP_HELPCONSTRAINT" PODEMOS VER LAS REGLAS ASOCIADAS A LOS CAMPOS DE UNA TABLA.

CON "SP_HELP" PODEMOS VER TODOS LOS OBJETOS DE LA BASE DE DATOS ACTIVA, INCLUYENDO LAS REGLAS, EN TAL CASO EN LA

COLUMNA "OBJECT_TYPE" APARECE "RULE".

55 - ELIMINAR Y DASASOCIAR REGLAS

(SP_UNBINDRULE - DROP RULE)

PARA ELIMINAR UNA REGLA, PRIMERO SE DEBE DESHACER LA ASOCIACIÓN, EJECUTANDO EL

PROCEDIMIENTO ALMACENADO DEL SISTEMA "SP_UNBINDRULE":

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 ELIMINACIÓN NO SE REALIZA.

CON LA INSTRUCCIÓN "DROP RULE" ELIMINAMOS LA REGLA:

DROP RULE NOMBREREGLA;

QUITAMOS LA ASOCIACIÓN DE LA REGLA "RG_SUELDO_INTERVALO" CON EL CAMPO "SUELDO" DE LA

TABLA "EMPLEADOS" TIPEANDO:

EXEC SP_UNBINDRULE 'EMPLEADOS.SUELDO';

LUEGO DE QUITAR LA ASOCIACIÓN LA ELIMINAMOS:

DROP RULE RG_SUELDO_100A1000;

SI ELIMINAMOS UNA TABLA, LAS ASOCIACIONES DE REGLAS DE SUS CAMPOS DESAPARECEN, PERO LAS

REGLAS SIGUEN EXISTIENDO.

56 - INFORMACIÓN DE REGLAS (SP_HELP -

SP_HELPCONSTRAINT)

PODEMOS UTILIZAR EL PROCEDIMIENTO ALMACENADO "SP_HELP" CON EL NOMBRE DEL OBJETO DEL

CUAL QUEREMOS INFORMACIÓN, EN ESTE CASO EL NOMBRE DE UNA REGLA:

Page 62: Base de Datos SQL

SP_HELP NOMBREREGLA;

MUESTRA NOMBRE, PROPIETARIO, TIPO Y FECHA DE CREACIÓN.

CON "SP_HELP", NO SABEMOS SI LAS REGLAS EXISTENTES ESTÁN O NO ASOCIADAS A ALGÚN CAMPO.

"SP_HELPCONSTRAINT" RETORNA UNA LISTA DE TODAS LAS RESTRICCIONES QUE TIENE UNA TABLA.

PODEMOS VER LAS REGLAS ASOCIADAS A UNA TABLA CON ESTE PROCEDIMIENTO ALMACENADO:

SP_HELPCONSTRAINT NOMBRETABLA;

MUESTRA LA SIGUIENTE INFORMACIÓN:

- CONSTRAINT_TYPE: INDICA QUE ES UNA REGLA CON "RULE", NOMBRANDO EL CAMPO AL QUE ESTÁ

ASOCIADA.

- CONSTRAINT_NAME: NOMBRE DE LA REGLA.

- CONSTRAINT_KEYS: MUESTRA EL TEXTO DE LA REGLA.

PARA VER EL TEXTO DE UNA REGLA EMPLEAMOS EL PROCEDIMIENTO ALMACENADO "SP_HELPTEXT"

SEGUIDO DEL NOMBRE DE LA REGLA:

SP_HELPTEXT NOMBREREGLA;

TAMBIÉN SE PUEDE CONSULTAR LA TABLA DEL SISTEMA "SYSOBJECTS", QUE NOS MUESTRA EL NOMBRE

Y VARIOS DATOS DE TODOS LOS OBJETOS DE LA BASE DE DATOS ACTUAL. LA COLUMNA "XTYPE" INDICA

EL TIPO DE OBJETO, EN CASO DE SER UNA REGLA APARECE EL VALOR "R":

SELECT *FROM SYSOBJECTS;

SI QUEREMOS VER TODAS LAS REGLAS CREADAS POR NOSOTROS, PODEMOS TIPEAR:

SELECT *FROM SYSOBJECTS

WHERE XTYPE='R' AND-- TIPO REGLA

NAME LIKE 'RG%';--BÚSQUEDA CON COMODÍN

57 - VALORES PREDETERMINADOS (CREATE DEFAULT)

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.

Page 63: Base de Datos SQL

SINTAXIS BÁSICA:

CREATE DEFAULT NOMBREVALORPREDETERMINADO

AS VALORPREDETERMINADO;

"VALORPREDETERMINADO" NO PUEDE HACER REFERENCIA A CAMPOS DE UNA TABLA (U OTROS

OBJETOS) Y DEBE SER COMPATIBLE CON EL TIPO DE DATOS Y LONGITUD DEL CAMPO AL CUAL SE ASOCIA;

SI ESTO NO SUCEDE, SQL SERVER NO LO INFORMA AL CREAR EL VALOR PREDETERMINADO NI AL

ASOCIARLO, PERO AL EJECUTAR UNA INSTRUCCIÓN "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 FUNCIÓN QUE CUMPLE UN VALOR PREDETERMINADO ES BÁSICAMENTE LA MISMA QUE UNA

RESTRICCIÓN "DEFAULT", LAS SIGUIENTES CARACTERÍSTICAS EXPLICAN ALGUNAS SEMEJANZAS Y

DIFERENCIAS ENTRE ELLAS:

- UN CAMPO SOLAMENTE PUEDE TENER DEFINIDA UNA RESTRICCIÓN "DEFAULT", UN CAMPO

SOLAMENTE PUEDE TENER UN VALOR PREDETERMINADO ASOCIADO A ÉL,

- UNA RESTRICCIÓN "DEFAULT" SE ALMACENA CON LA TABLA, CUANDO ÉSTA SE ELIMINA, LAS

RESTRICCIONES TAMBIÉN. LOS VALORES PREDETERMINADOS SON OBJETOS DIFERENTES E

INDEPENDIENTES DE LAS TABLAS, SI ELIMINAMOS UNA TABLA, LAS ASOCIACIONES DESAPARECEN, PERO

LOS VALORES PREDETERMINADOS SIGUEN EXISTIENDO EN LA BASE DE DATOS.

- UNA RESTRICCIÓN "DEFAULT" SE ESTABLECE PARA UN SOLO CAMPO; UN VALOR PREDETERMINADO

PUEDE ASOCIARSE A DISTINTOS CAMPOS (INCLUSIVE, DE DIFERENTES TABLAS).

- UNA RESTRICCIÓN "DEFAULT" NO PUEDE ESTABLECERSE SOBRE UN CAMPO "IDENTITY", TAMPOCO UN

VALOR PREDETERMINADO.

NO SE PUEDE ASOCIAR UN VALOR PREDETERMINADO A UN CAMPO QUE TIENE UNA RESTRICCIÓN

"DEFAULT".

Page 64: Base de Datos SQL

UN CAMPO CON UN VALOR PREDETERMINADO ASOCIADO PUEDE TENER REGLAS ASOCIADAS A ÉL Y

RESTRICCIONES "CHECK". SI HAY CONFLICTO ENTRE ELLAS, SQL SERVER NO LO INFORMA AL

CREARLAS Y/O ASOCIARLAS, PERO AL INTENTAR INGRESAR UN VALOR QUE ALGUNA DE ELLAS NO

PERMITA, APARECE UN MENSAJE DE ERROR.

LA SENTENCIA "CREATE DEFAULT" NO PUEDE COMBINARSE CON OTRA SENTENCIA EN UN MISMO LOTE.

SI ASOCIA A UN CAMPO QUE YA TIENE ASOCIADO UN VALOR PREDETERMINADO OTRO VALOR

PREDETERMINADO, LA NUEVA ASOCIACIÓN REEMPLAZA A LA ANTERIOR.

VEAMOS OTROS EJEMPLOS.

CREAMOS UN VALOR PREDETERMINADO QUE INSERTA EL VALOR "0" EN UN CAMPO DE TIPO NUMÉRICO:

CREATE DEFAULT VP_CERO

AS 0;

EN EL SIGUIENTE CREAMOS UN VALOR PREDETERMINADO QUE INSERTA CEROS CON EL FORMATO VÁLIDO

PARA UN NÚMERO DE TELÉFONO:

CREATE DEFAULT VP_TELEFONO

AS '(0000)0-000000';

CON "SP_HELPCONSTRAINT" PODEMOS VER LOS VALORES PREDETERMINADOS ASOCIADOS A LOS

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

58 - DESASOCIAR Y ELIMINAR VALORES

PREDETERMINADOS

UN VALOR PREDETERMINADO NO PUEDE ELIMINARSE SI NO SE HA DESASOCIADO PREVIAMENTE.

PARA DESHACER UNA ASOCIACIÓN EMPLEAMOS EL PROCEDIMIENTO ALMACENADO "SP_UNBINDEFAULT"

SEGUIDO DE LA TABLA Y CAMPO AL QUE ESTÁ ASOCIADO:

SP_UNBINDEFAULT 'TABLA.CAMPO';

QUITAMOS LA ASOCIACIÓN AL CAMPO "SUELDO" DE LA TABLA "EMPLEADOS":

SP_UNBINDEFAULT 'EMPLEADOS.SUELDO';

CON LA INSTRUCCIÓN "DROP DEFAULT" PODEMOS ELIMINAR UN VALOR PREDETERMINADO:

DROP DEFAULT NOMBREVALORPREDETERMINADO;

ELIMINAMOS EL VALOR PREDETERMINADO LLAMADO "VP_CERO":

Page 65: Base de Datos SQL

DROP DEFAULT VP_CERO;

SI ELIMINAMOS UNA TABLA, LAS ASOCIACIONES DE VALORES PREDETERMINADOS DE SUS CAMPOS

DESAPARECEN, PERO LOS VALORES PREDETERMINADOS SIGUEN EXISTIENDO.

59 - INFORMACIÓN DE VALORES PREDETERMINADOS

PARA OBTENER INFORMACIÓN DE LOS VALORES PREDETERMINADOS PODEMOS EMPLEAR LOS MISMOS

PROCEDIMIENTOS ALMACENADOS QUE USAMOS PARA LAS REGLAS.

SI EMPLEAMOS "SP_HELP", VEMOS TODOS LOS OBJETOS DE LA BASE DE DATOS ACTIVA (INCLUYENDO

LOS VALORES PREDETERMINADOS); EN LA COLUMNA "OBJECT_TYPE" (TIPO DE OBJETO) MUESTRA

"DEFAULT".

SI AL PROCEDIMIENTO ALMACENADO "SP_HELP" LE AGREGAMOS EL NOMBRE DE UN VALOR

PREDETERMINADO, NOS MUESTRA EL NOMBRE, PROPIETARIO, TIPO Y FECHA DE CREACIÓN:

SP_HELP NOMBREVALORPREDETERMINADO;

CON "SP_HELP", NO SABEMOS SI LOS VALORES PREDETERMINADOS EXISTENTES ESTÁN O NO ASOCIADAS

A ALGÚN CAMPO.

"SP_HELPCONSTRAINT" RETORNA UNA LISTA DE TODAS LAS RESTRICCIONES QUE TIENE UNA TABLA.

TAMBIÉN LOS VALORES PREDETERMINADOS ASOCIADOS; MUESTRA LA SIGUIENTE INFORMACIÓN:

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

TAMBIÉN SE PUEDE CONSULTAR LA TABLA DEL SISTEMA "SYSOBJECTS", QUE NOS MUESTRA EL NOMBRE

Y VARIOS DATOS DE TODOS LOS OBJETOS DE LA BASE DE DATOS ACTUAL. LA COLUMNA "XTYPE" INDICA

EL TIPO DE OBJETO, EN CASO DE SER UN VALOR PREDETERMINADO APARECE EL VALOR "D":

SELECT *FROM SYSOBJECTS;

SI QUEREMOS VER TODOS LOS VALORES PREDETERMINADOS CREADOS POR NOSOTROS, PODEMOS TIPEAR:

SELECT *FROM SYSOBJECTS

WHERE XTYPE='D' AND-- TIPO VALOR PREDETERMINADO

NAME LIKE 'VP%';--BÚSQUEDA CON COMODÍN

60 - INDICES

Page 66: Base de Datos SQL

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 OBTENCIÓN DE INFORMACIÓN DE UNA TABLA. EL INDICE DE UNA TABLA DESEMPEÑA LA

MISMA FUNCIÓN QUE EL ÍNDICE DE UN LIBRO: PERMITE ENCONTRAR DATOS RÁPIDAMENTE; EN EL CASO DE LAS TABLAS, LOCALIZA

REGISTROS.

UNA TABLA SE INDEXA POR UN CAMPO (O VARIOS).

UN ÍNDICE POSIBILITA EL ACCESO DIRECTO Y RÁPIDO HACIENDO MÁS EFICIENTE LAS BÚSQUEDAS. SIN ÍNDICE, SQL SERVER DEBE

RECORRER SECUENCIALMENTE TODA LA TABLA PARA ENCONTRAR UN REGISTRO.

EL OBJETIVO DE UN INDICE ES ACELERAR LA RECUPERACIÓN DE INFORMACIÓN. LA INDEXACIÓN ES UNA TÉCNICA 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 MÁS ADELANTE).

LA DESVENTAJA ES QUE CONSUME ESPACIO EN EL DISCO EN DISCO Y GENERA COSTO DE MANTENIMIENTO (TIEMPO Y RECURSOS).

LOS ÍNDICES MÁS ADECUADOS SON AQUELLOS CREADOS CON CAMPOS QUE CONTIENEN VALORES ÚNICOS.

ES IMPORTANTE IDENTIFICAR EL O LOS CAMPOS POR LOS QUE SERÍA ÚTIL CREAR UN ÍNDICE, AQUELLOS CAMPOS POR LOS CUALES SE

REALIZAN BÚSQUEDA CON FRECUENCIA: CLAVES PRIMARIAS, CLAVES EXTERNAS O CAMPOS QUE COMBINAN TABLAS.

NO SE RECOMIENDA CREAR ÍNDICES POR CAMPOS QUE NO SE USAN CON FRECUENCIA EN CONSULTAS O NO CONTIENEN VALORES

ÚNICOS.

SQL SERVER PERMITE CREAR DOS TIPOS DE ÍNDICES: 1) AGRUPADOS Y 2) NO AGRUPADOS.

61 - INDICES AGRUPADOS Y NO AGRUPADOS

(CLUSTERED Y NONCLUSTERED)

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 GUÍA TELEFÓNICA, LOS REGISTROS CON EL MISMO

VALOR DE CAMPO SE AGRUPAN JUNTOS. UN ÍNDICE AGRUPADO DETERMINA LA SECUENCIA DE

ALMACENAMIENTO DE LOS REGISTROS EN UNA TABLA.

SE UTILIZAN PARA CAMPOS POR LOS QUE SE REALIZAN BUSQUEDAS CON FRECUENCIA O SE ACCEDE

SIGUIENDO UN ORDEN.

Page 67: Base de Datos SQL

UNA TABLA SÓLO PUEDE TENER UN ÍNDICE AGRUPADO.

EL TAMAÑO MEDIO DE UN ÍNDICE AGRUPADO ES APROXIMADAMENTE EL 5% DEL TAMAÑO DE LA TABLA.

2) UN INDICE NO AGRUPADO ES COMO EL ÍNDICE DE UN LIBRO, LOS DATOS SE ALMACENAN EN UN

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 FÍSICO DE LOS REGISTROS, ORDENÁNDOLOS SECUENCIALMENTE.

LA DIFERENCIA BÁSICA ENTRE ÍNDICES AGRUPADOS Y NO AGRUPADOS ES QUE LOS REGISTROS DE UN

ÍNDICE AGRUPADO ESTÁN ORDENADOS Y ALMACENADOS DE FORMA SECUENCIAL EN FUNCIÓN DE SU

CLAVE.

SQL SERVER CREA AUTOMATICAMENTE ÍNDICES CUANDO SE CREA UNA RESTRICCIÓN "PRIMARY KEY" O

"UNIQUE" EN UNA TABLA.

ES POSIBLE CREAR ÍNDICES EN LAS VISTAS.

RESUMIENDO, LOS ÍNDICES FACILITAN LA RECUPERACIÓN DE DATOS, PERMITIENDO EL ACCESO DIRECTO

Y ACELERANDO LAS BÚSQUEDAS, CONSULTAS Y OTRAS OPERACIONES QUE OPTIMIZAN EL RENDIMIENTO

GENERAL.

62 - CREACIÓN DE ÍNDICES

PARA CREAR ÍNDICES EMPLEAMOS LA INSTRUCCIÓN "CREATE INDEX".

LA SINTAXIS BÁSICA ES LA SIGUIENTE:

CREATE TIPODEINDICE INDEX NOMBREINDICE

ON TABLA(CAMPO);

"TIPODEINDICE" INDICA SI ES AGRUPADO (CLUSTERED) O NO AGRUPADO (NONCLUSTERED). SI NO

ESPECIFICAMOS CREA UNO NO AGRUPADO. INDEPENDIENTEMENTE DE SI ES AGRUPADO O NO, TAMBIÉN 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);

Page 68: Base de Datos SQL

PARA IDENTIFICAR LOS ÍNDICES FÁCILMENTE, PODEMOS AGREGAR UN PREFIJO AL NOMBRE DEL ÍNDICE,

POR EJEMPLO "I" Y LUEGO EL NOMBRE DE LA TABLA Y/O CAMPO.

EN ESTE EJEMPLO SE CREA UN ÍNDICE NO AGRUPADO PARA EL CAMPO "TITULO" DE LA TABLA "LIBROS":

CREATE NONCLUSTERED INDEX I_LIBROS_TITULO

ON LIBROS(TITULO);

UN ÍNDICE PUEDE TENER MÁS DE UN CAMPO COMO CLAVE, SON ÍNDICES COMPUESTOS. LOS CAMPOS DE

UN ÍNDICE COMPUESTO TIENEN QUE SER DE LA MISMA TABLA (EXCEPTO CUANDO SE CREA EN UNA VISTA -

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 AUTOMÁTICAMENTE ÍNDICES CUANDO SE ESTABLECE UNA RESTRICCIÓN "PRIMARY

KEY" O "UNIQUE" EN UNA TABLA. AL CREAR UNA RESTRICCIÓN "PRIMARY KEY", SI NO SE ESPECIFICA,

EL ÍNDICE SERÁ AGRUPADO (CLUSTERED) A MENOS QUE YA EXISTA UN ÍNDICE AGRUPADO PARA DICHA

TABLA. AL CREAR UNA RESTRICCIÓN "UNIQUE", SI NO SE ESPECIFICA, EL ÍNDICE SERÁ NO AGRUPADO

(NON-CLUSTERED).

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 RESTRICCIÓN "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_%';

Page 69: Base de Datos SQL

63 - REGENERAR ÍNDICES

VIMOS QUE PARA CREAR ÍNDICES EMPLEAMOS LA INSTRUCCIÓN "CREATE INDEX".

EMPLEANDO LA OPCIÓN "DROP_EXISTING" JUNTO CON "CREATE INDEX" PERMITE REGENERAR UN

ÍNDICE, CON ELLO EVITAMOS ELIMINARLO Y VOLVER A CREARLO. LA SINTAXIS ES LA SIGUIENTE:

CREATE TIPODEINDICE INDEX NOMBREINDICE

ON TABLA(CAMPO)

WITH DROP_EXISTING;

TAMBIÉN PODEMOS MODIFICAR ALGUNA DE LAS CARACTERÍSTICAS DE UN ÍNDICE CON ESTA OPCIÓN, A

SABER:

- TIPO: CAMBIÁNDOLO DE NO AGRUPADO A AGRUPADO (SIEMPRE QUE NO EXISTA UNO AGRUPADO PARA

LA MISMA TABLA). NO SE PUEDE CONVERTIR UN ÍNDICE AGRUPADO EN NO AGRUPADO.

- CAMPO: SE PUEDE CAMBIAR EL CAMPO POR EL CUAL SE INDEXA, AGREGAR CAMPOS, ELIMINAR ALGÚN

CAMPO DE UN ÍNDICE COMPUESTO.

- ÚNICO: SE PUEDE MODIFICAR UN ÍNDICE PARA QUE LOS VALORES SEAN ÚNICOS O DEJEN DE SERLO.

EN ESTE EJEMPLO SE CREA UN ÍNDICE NO AGRUPADO PARA EL CAMPO "TITULO" DE LA TABLA "LIBROS":

CREATE NONCLUSTERED INDEX I_LIBROS

ON LIBROS(TITULO);

REGENERAMOS EL ÍNDICE "I_LIBROS" Y LO CONVERTIMOS A AGRUPADO:

CREATE CLUSTERED INDEX I_LIBROS

ON LIBROS(TITULO)

WITH DROP_EXISTING;

AGREGAMOS UN CAMPO AL ÍNDICE "I_LIBROS":

CREATE CLUSTERED INDEX I_LIBROS

ON LIBROS(TITULO,EDITORIAL)

WITH DROP_EXISTING;

ESTA OPCIÓN NO PUEDE EMPLEARSE CON ÍNDICES CREADOS A PARTIR DE UNA RESTRICCIÓN "PRIMARY

KEY" O "UNIQUE".

64 - ELIMINAR ÍNDICES

LOS ÍNDICES CREADOS CON "CREATE INDEX" SE ELIMINAN CON "DROP INDEX"; LA SIGUIENTE ES LA

SINTAXIS BÁSICA:

Page 70: Base de Datos SQL

DROP INDEX NOMBRETABLA.NOMBREINDICE;

ELIMINAMOS EL ÍNDICE "I_LIBROS_TITULO":

DROP INDEX LIBROS.I_LIBROS_TITULO;

LOS ÍNDICES QUE SQL SERVER CREA AUTOMÁTICAMENTE AL ESTABLECER UNA RESTRICCIÓN "PRIMARY

KEY" O "UNIQUE" NO PUEDEN ELIMINARSE CON "DROP INDEX", SE ELIMINAN AUTOMÁTICAMENTE

CUANDO QUITAMOS LA RESTRICCIÓN.

PODEMOS AVERIGUAR SI EXISTE UN ÍNDICE PARA ELIMINARLO, CONSULTANDO LA TABLA DEL SISTEMA

"SYSINDEXES":

IF EXISTS (SELECT NAME FROM SYSINDEXES

WHERE NAME = 'NOMBREINDICE')

DROP INDEX NOMBRETABLA.NOMBREINDICE;

ELIMINAMOS EL ÍNDICE "I_LIBROS_TITULO" SI EXISTE:

IF EXISTS (SELECT *FROM SYSINDEXES

WHERE NAME = 'I_LIBROS_TITULO')

DROP INDEX LIBROS.I_LIBROS_TITULO;

65 - TRABAJAR CON VARIAS TABLAS

HASTA EL MOMENTO HEMOS TRABAJADO CON UNA SOLA TABLA, PERO GENERALMENTE, SE TRABAJA CON

MÁS DE UNA.

PARA EVITAR LA REPETICIÓN DE DATOS Y OCUPAR MENOS ESPACIO, SE SEPARA LA INFORMACIÓN EN

VARIAS TABLAS. CADA TABLA ALMACENA PARTE DE LA INFORMACIÓN QUE NECESITAMOS REGISTRAR.

POR EJEMPLO, LOS DATOS DE NUESTRA TABLA "LIBROS" PODRÍAN SEPARARSE EN 2 TABLAS, UNA

LLAMADA "LIBROS" Y OTRA "EDITORIALES" QUE GUARDARÁ LA INFORMACIÓN DE LAS EDITORIALES.

EN NUESTRA TABLA "LIBROS" HAREMOS REFERENCIA A LA EDITORIAL COLOCANDO UN CÓDIGO QUE LA

IDENTIFIQUE.

VEAMOS:

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)

);

Page 71: Base de Datos SQL

DE ESTA MANERA, EVITAMOS ALMACENAR TANTAS VECES LOS NOMBRES DE LAS EDITORIALES EN LA

TABLA "LIBROS" Y GUARDAMOS EL NOMBRE EN LA TABLA "EDITORIALES"; PARA INDICAR LA EDITORIAL

DE CADA LIBRO AGREGAMOS UN CAMPO QUE HACE REFERENCIA AL CÓDIGO DE LA EDITORIAL EN LA

TABLA "LIBROS" Y EN "EDITORIALES".

AL RECUPERAR LOS DATOS DE LOS LIBROS CON LA SIGUIENTE INSTRUCCIÓN:

SELECT* FROM LIBROS;

VEMOS QUE EN EL CAMPO "EDITORIAL" APARECE EL CÓDIGO, PERO NO SABEMOS EL NOMBRE DE LA

EDITORIAL.

PARA OBTENER LOS DATOS DE CADA LIBRO, INCLUYENDO EL NOMBRE DE LA EDITORIAL, NECESITAMOS

CONSULTAR AMBAS TABLAS, TRAER INFORMACIÓN DE LAS DOS.

CUANDO OBTENEMOS INFORMACIÓN DE MÁS DE UNA TABLA DECIMOS QUE HACEMOS UN "JOIN"

(COMBINACIÓN).

VEAMOS UN EJEMPLO:

SELECT *FROM LIBROS

JOIN EDITORIALES

ON LIBROS.CODIGOEDITORIAL=EDITORIALES.CODIGO;

RESUMIENDO: SI DISTRIBUIMOS LA INFORMACIÓN EN VARIAS TABLAS EVITAMOS LA REDUNDANCIA DE

DATOS Y OCUPAMOS MENOS ESPACIO FÍSICO EN EL DISCO. UN JOIN ES UNA OPERACIÓN QUE RELACIONA

DOS O MÁS TABLAS PARA OBTENER UN RESULTADO QUE INCLUYA DATOS (CAMPOS Y REGISTROS) DE

AMBAS; LAS TABLAS PARTICIPANTES SE COMBINAN SEGÚN LOS CAMPOS COMUNES A AMBAS TABLAS.

HAY HAY TRES TIPOS DE COMBINACIONES. EN LOS SIGUIENTES CAPÍTULOS EXPLICAMOS CADA UNA DE

ELLAS.

66 - COMBINACIÓN INTERNA (INNER JOIN)

UN JOIN ES UNA OPERACIÓN QUE RELACIONA DOS O MÁS TABLAS PARA OBTENER UN RESULTADO QUE INCLUYA DATOS (CAMPOS Y

REGISTROS) DE AMBAS; LAS TABLAS PARTICIPANTES SE COMBINAN SEGÚN 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.

TAMBIÉN ES POSIBLE EMPLEAR VARIAS COMBINACIONES EN UNA CONSULTA "SELECT", INCLUSO PUEDE COMBINARSE UNA TABLA

CONSIGO MISMA.

LA COMBINACIÓN INTERNA EMPLEA "JOIN", QUE ES LA FORMA ABREVIADA DE "INNER JOIN". SE EMPLEA PARA OBTENER

INFORMACIÓN DE DOS TABLAS Y COMBINAR DICHA INFORMACIÓN EN UNA SALIDA.

LA SINTAXIS BÁSICA ES LA SIGUIENTE:

SELECT CAMPOS

Page 72: Base de Datos SQL

FROM TABLA1 JOIN TABLA2 ON CONDICIONDECOMBINACION;

EJEMPLO:

SELECT *FROM LIBROS JOIN EDITORIALES ON CODIGOEDITORIAL=EDITORIALES.CODIGO;

ANALICEMOS LA CONSULTA ANTERIOR.

- ESPECIFICAMOS LOS CAMPOS QUE APARECERÁN EN EL RESULTADO EN LA LISTA DE SELECCIÓN;

- INDICAMOS EL NOMBRE DE LA TABLA LUEGO DEL "FROM" ("LIBROS");

- COMBINAMOS ESA TABLA CON "JOIN" Y EL NOMBRE DE LA OTRA TABLA ("EDITORIALES"); SE ESPECIFICA QUÉ TABLAS SE VAN A

COMBINAR Y CÓMO;

- CUANDO SE COMBINA INFORMACIÓN DE VARIAS TABLAS, ES NECESARIO ESPECIFICAR QUÉ REGISTRO DE UNA TABLA SE COMBINARÁ

CON QUÉ REGISTRO DE LA OTRA TABLA, CON "ON". SE DEBE ESPECIFICAR LA CONDICIÓN PARA ENLAZARLAS, ES DECIR, EL CAMPO POR

EL CUAL SE COMBINARÁN, QUE TIENEN EN COMÚN. "ON" HACE COINCIDIR REGISTROS DE AMBAS TABLAS BASÁNDOSE EN EL VALOR DE TAL CAMPO, EN EL EJEMPLO, EL CAMPO

"CODIGOEDITORIAL" DE "LIBROS" Y EL CAMPO "CODIGO" DE "EDITORIALES" SON LOS QUE ENLAZARÁN AMBAS TABLAS. SE EMPLEAN

CAMPOS COMUNES, QUE DEBEN TENER TIPOS DE DATOS IGUALES O SIMILARES.

LA CONDICION DE COMBINACIÓN, ES DECIR, EL O LOS CAMPOS POR LOS QUE SE VAN A COMBINAR (PARTE "ON"), SE ESPECIFICA

SEGÚN LAS CLAVES PRIMARIAS Y EXTERNAS.

NOTE QUE EN LA CONSULTA, AL NOMBRAR EL CAMPO USAMOS EL NOMBRE DE LA TABLA TAMBIÉN. CUANDO LAS TABLAS

REFERENCIADAS TIENEN CAMPOS CON IGUAL NOMBRE, ESTO ES NECESARIO PARA EVITAR CONFUSIONES Y AMBIGUEDADES AL

MOMENTO DE REFERENCIAR UN CAMPO. EN EL EJEMPLO, SI NO ESPECIFICAMOS "EDITORIALES.CODIGO" Y SOLAMENTE TIPEAMOS

"CODIGO", SQL SERVER NO SABRÁ SI NOS REFERIMOS AL CAMPO "CODIGO" DE "LIBROS" O DE "EDITORIALES" Y MOSTRARÁ UN

MENSAJE DE ERROR INDICANDO QUE "CODIGO" ES AMBIGUO.

ENTONCES, SI LAS TABLAS QUE COMBINAMOS TIENEN NOMBRES DE CAMPOS IGUALES, DEBE ESPECIFICARSE A QUÉ TABLA PERTENECE

ANTEPONIENDO EL NOMBRE DE LA TABLA AL NOMBRE DEL CAMPO, SEPARADO POR UN PUNTO (.).

SI UNA DE LAS TABLAS TIENE CLAVE PRIMARIA COMPUESTA, AL COMBINARLA CON LA OTRA, EN LA CLÁUSULA "ON" SE DEBE HACER

REFERENCIA A LA CLAVE COMPLETA, ES DECIR, LA CONDICIÓN REFERENCIARÁ A TODOS LOS CAMPOS CLAVE QUE IDENTIFICAN AL

REGISTRO.

SE PUEDE INCLUIR EN LA CONSULTA JOIN LA CLÁUSULA "WHERE" PARA RESTRINGIR LOS REGISTROS QUE RETORNA EL RESULTADO;

TAMBIÉN "ORDER BY", "DISTINCT", ETC..

SE EMPLEA ESTE TIPO DE COMBINACIÓN PARA ENCONTRAR REGISTROS DE LA PRIMERA TABLA QUE SE CORRESPONDAN CON LOS

REGISTROS DE LA OTRA, ES DECIR, QUE CUMPLAN LA CONDICIÓN DEL "ON". SI UN VALOR DE LA PRIMERA TABLA NO SE ENCUENTRA

EN LA SEGUNDA TABLA, EL REGISTRO NO APARECE.

PARA SIMPLIFICAR LA SENTENCIA PODEMOS USAR UN ALIAS PARA CADA TABLA:

SELECT L.CODIGO,TITULO,AUTOR,NOMBRE

Page 73: Base de Datos SQL

FROM LIBROS AS L JOIN EDITORIALES AS E ON L.CODIGOEDITORIAL=E.CODIGO;

EN ALGUNOS CASOS (COMO EN ESTE EJEMPLO) EL USO DE ALIAS ES PARA FINES DE SIMPLIFICACIÓN Y HACE MÁS LEGIBLE LA CONSULTA

SI ES LARGA Y COMPLEJA, PERO EN ALGUNAS CONSULTAS ES ABSOLUTAMENTE NECESARIO.

67 - COMBINACIÓN EXTERNA IZQUIERDA (LEFT JOIN)

VIMOS QUE UNA COMBINACIÓN INTERNA (JOIN) ENCUENTRA REGISTROS DE LA PRIMERA TABLA QUE SE

CORRESPONDAN CON LOS REGISTROS DE LA SEGUNDA, ES DECIR, QUE CUMPLAN LA CONDICIÓN 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 COMBINACIÓN,

"OUTER JOIN" (COMBINACIÓN EXTERNA).

LAS COMBINACIONES EXTERNAS COMBINAN REGISTROS DE DOS TABLAS QUE CUMPLEN LA CONDICIÓN,

MÁS LOS REGISTROS DE LA SEGUNDA TABLA QUE NO LA CUMPLEN; ES DECIR, MUESTRAN TODOS LOS

REGISTROS DE LAS TABLAS RELACIONADAS, AÚN CUANDO NO HAYA VALORES COINCIDENTES ENTRE

ELLAS.

ESTE TIPO DE COMBINACIÓN SE EMPLEA CUANDO SE NECESITA UNA LISTA COMPLETA DE LOS DATOS DE

UNA DE LAS TABLAS Y LA INFORMACIÓN QUE CUMPLE CON LA CONDICIÓN. LAS COMBINACIONES

EXTERNAS SE REALIZAN SOLAMENTE ENTRE 2 TABLAS.

HAY TRES TIPOS DE COMBINACIONES EXTERNAS: "LEFT OUTER JOIN", "RIGHT OUTER JOIN" Y "FULL

OUTER JOIN"; SE PUEDEN ABREVIAR CON "LEFT JOIN", "RIGHT JOIN" Y "FULL JOIN"

RESPECTIVAMENTE.

VAMOS A ESTUDIAR LAS PRIMERAS.

SE EMPLEA UNA COMBINACIÓN EXTERNA IZQUIERDA PARA MOSTRAR TODOS LOS REGISTROS DE LA

TABLA DE LA IZQUIERDA. SI NO ENCUENTRA COINCIDENCIA CON LA TABLA DE LA DERECHA, EL REGISTRO

MUESTRA LOS CAMPOS DE LA SEGUNDA TABLA SETEADOS A "NULL".

EN EL SIGUIENTE EJEMPLO SOLICITAMOS EL TÍTULO Y NOMBRE DE LA EDITORIAL DE LOS LIBROS:

SELECT TITULO,NOMBRE

FROM EDITORIALES AS E

LEFT JOIN LIBROS AS L

ON CODIGOEDITORIAL = E.CODIGO;

EL RESULTADO MOSTRARÁ EL TÍTULO Y NOMBRE DE LA EDITORIAL; LAS EDITORIALES DE LAS CUALES NO

HAY LIBROS, ES DECIR, CUYO CÓDIGO DE EDITORIAL NO ESTÁ PRESENTE EN "LIBROS" APARECE EN EL

RESULTADO, PERO CON EL VALOR "NULL" EN EL CAMPO "TITULO".

Page 74: Base de Datos SQL

ES IMPORTANTE LA POSICIÓN EN QUE SE COLOCAN LAS TABLAS EN UN "LEFT JOIN", LA TABLA DE LA

IZQUIERDA ES LA QUE SE USA PARA LOCALIZAR REGISTROS EN LA TABLA DE LA DERECHA.

ENTONCES, UN "LEFT JOIN" SE USA PARA HACER COINCIDIR REGISTROS EN UNA TABLA (IZQUIERDA) CON

OTRA TABLA (DERECHA); SI UN VALOR DE LA TABLA DE LA IZQUIERDA NO ENCUENTRA COINCIDENCIA EN

LA TABLA DE LA DERECHA, SE GENERA UNA FILA EXTRA (UNA POR CADA VALOR NO ENCONTRADO) CON

TODOS LOS CAMPOS CORRESPONDIENTES A LA TABLA DERECHA SETEADOS A "NULL". LA SINTAXIS

BÁSICA ES LA SIGUIENTE:

SELECT CAMPOS

FROM TABLAIZQUIERDA

LEFT JOIN TABLADERECHA

ON CONDICION;

EN EL SIGUIENTE EJEMPLO SOLICITAMOS EL TÍTULO 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 TÍTULO DEL LIBRO Y EL NOMBRE DE LA EDITORIAL; LOS TÍTULOS CUYO

CÓDIGO DE EDITORIAL NO ESTÁ PRESENTE EN "EDITORIALES" APARECEN EN EL RESULTADO, PERO CON

EL VALOR "NULL" EN EL CAMPO "NOMBRE".

UN "LEFT JOIN" PUEDE TENER CLAUSULA "WHERE" QUE RESTRINGA EL RESULTADO DE LA CONSULTA

CONSIDERANDO SOLAMENTE LOS REGISTROS QUE ENCUENTRAN COINCIDENCIA EN LA TABLA DE LA

DERECHA, ES DECIR, CUYO VALOR DE CÓDIGO ESTÁ PRESENTE EN "LIBROS":

SELECT TITULO,NOMBRE

FROM EDITORIALES AS E

LEFT JOIN LIBROS AS L

ON E.CODIGO=CODIGOEDITORIAL

WHERE CODIGOEDITORIAL IS NOT NULL;

TAMBIÉN PODEMOS MOSTRAR LAS EDITORIALES QUE NO ESTÁN PRESENTES EN "LIBROS", ES DECIR, QUE

NO ENCUENTRAN COINCIDENCIA EN LA TABLA DE LA DERECHA:

SELECT TITULO,NOMBRE

FROM EDITORIALES AS E

LEFT JOIN LIBROS AS L

ON E.CODIGO=CODIGOEDITORIAL

WHERE CODIGOEDITORIAL IS NULL;

68 - COMBINACIÓN EXTERNA DERECHA (RIGHT JOIN)

VIMOS QUE UNA COMBINACIÓN 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".

Page 75: Base de Datos SQL

UNA COMBINACIÓN EXTERNA DERECHA ("RIGHT OUTER JOIN" O "RIGHT JOIN") OPERA DEL MISMO

MODO SÓLO QUE LA TABLA DERECHA ES LA QUE LOCALIZA LOS REGISTROS EN LA TABLA IZQUIERDA.

EN EL SIGUIENTE EJEMPLO SOLICITAMOS EL TÍTULO Y NOMBRE DE LA EDITORIAL DE LOS LIBROS

EMPLEANDO UN "RIGHT JOIN":

SELECT TITULO,NOMBRE

FROM LIBROS AS L

RIGHT JOIN EDITORIALES AS E

ON CODIGOEDITORIAL = E.CODIGO;

EL RESULTADO MOSTRARÁ EL TÍTULO Y NOMBRE DE LA EDITORIAL; LAS EDITORIALES DE LAS CUALES NO

HAY LIBROS, ES DECIR, CUYO CÓDIGO DE EDITORIAL NO ESTÁ PRESENTE EN "LIBROS" APARECE EN EL

RESULTADO, PERO CON EL VALOR "NULL" EN EL CAMPO "TITULO".

ES FUNDAMENTAL TENER EN CUENTA LA POSICIÓN EN QUE SE COLOCAN LAS TABLAS EN LOS "OUTER

JOIN". EN UN "LEFT JOIN" LA PRIMERA TABLA (IZQUIERDA) ES LA QUE BUSCA COINCIDENCIAS EN LA

SEGUNDA TABLA (DERECHA); EN EL "RIGHT JOIN" LA SEGUNDA TABLA (DERECHA) ES LA QUE BUSCA

COINCIDENCIAS EN LA PRIMERA TABLA (IZQUIERDA).

EN LA SIGUIENTE CONSULTA EMPLEAMOS UN "LEFT JOIN" PARA CONSEGUIR EL MISMO RESULTADO QUE

EL "RIGHT JOIN" ANTERIOR":

SELECT TITULO,NOMBRE

FROM EDITORIALES AS E

LEFT JOIN LIBROS AS L

ON CODIGOEDITORIAL = E.CODIGO;

NOTE QUE LA TABLA QUE BUSCA COINCIDENCIAS ("EDITORIALES") ESTÁ EN PRIMER LUGAR PORQUE ES

UN "LEFT JOIN"; EN EL "RIGHT JOIN" PRECEDENTE, ESTABA EN SEGUNDO LUGAR.

UN "RIGHT JOIN" HACE COINCIDIR REGISTROS EN UNA TABLA (DERECHA) CON OTRA TABLA

(IZQUIERDA); SI UN VALOR DE LA TABLA DE LA DERECHA NO ENCUENTRA COINCIDENCIA EN LA TABLA

IZQUIERDA, SE GENERA UNA FILA EXTRA (UNA POR CADA VALOR NO ENCONTRADO) CON TODOS LOS

CAMPOS CORRESPONDIENTES A LA TABLA IZQUIERDA SETEADOS A "NULL". LA SINTAXIS BÁSICA ES LA

SIGUIENTE:

SELECT CAMPOS

FROM TABLAIZQUIERDA

RIGHT JOIN TABLADERECHA

ON CONDICION;

UN "RIGHT JOIN" TAMBIÉN PUEDE TENER CLÁUSULA "WHERE" QUE RESTRINGA EL RESULTADO DE LA

CONSULTA CONSIDERANDO SOLAMENTE LOS REGISTROS QUE ENCUENTRAN COINCIDENCIA EN LA TABLA

IZQUIERDA:

SELECT TITULO,NOMBRE

FROM LIBROS AS L

RIGHT JOIN EDITORIALES AS E

ON E.CODIGO=CODIGOEDITORIAL

WHERE CODIGOEDITORIAL IS NOT NULL;

MOSTRAMOS LAS EDITORIALES QUE NO ESTÁN PRESENTES EN "LIBROS", ES DECIR, QUE NO

ENCUENTRAN COINCIDENCIA EN LA TABLA DE LA DERECHA EMPLEANDO UN "RIGHT JOIN":

Page 76: Base de Datos SQL

SELECT TITULO,NOMBRE

FROM LIBROS AS L

RIGHTJOIN EDITORIALES AS E

ON E.CODIGO=CODIGOEDITORIAL

WHERE CODIGOEDITORIAL IS NULL;

69 - COMBINACIÓN EXTERNA COMPLETA (FULL JOIN)

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 TAMBIÉN QUE UN "RIGHT JOIN" OPERA DEL MISMO MODO

SÓLO QUE LA TABLA DERECHA ES LA QUE LOCALIZA LOS REGISTROS EN LA TABLA IZQUIERDA.

UNA COMBINACIÓN EXTERNA COMPLETA ("FULL OUTER JOIN" O "FULL JOIN") RETORNA TODOS LOS

REGISTROS DE AMBAS TABLAS. SI UN REGISTRO DE UNA TABLA IZQUIERDA NO ENCUENTRA

COINCIDENCIA EN LA TABLA DERECHA, LAS COLUMNAS CORRESPONDIENTES A CAMPOS DE LA TABLA

DERECHA APARECEN SETEADAS A "NULL", Y SI LA TABLA DE LA DERECHA NO ENCUENTRA

CORRESPONDENCIA EN LA TABLA IZQUIERDA, LOS CAMPOS DE ESTA ÚLTIMA APARECEN CONTENIENDO

"NULL".

VEAMOS UN EJEMPLO:

SELECT TITULO,NOMBRE

FROM EDITORIALES AS E

FULL JOIN LIBROS AS L

ON CODIGOEDITORIAL = E.CODIGO;

LA SALIDA DEL "FULL JOIN" PRECEDENTE MUESTRA TODOS LOS REGISTROS DE AMBAS TABLAS,

INCLUYENDO LOS LIBROS CUYO CÓDIGO DE EDITORIAL NO EXISTE EN LA TABLA "EDITORIALES" Y LAS

EDITORIALES DE LAS CUALES NO HAY CORRESPONDENCIA EN "LIBROS".

70 - COMBINACIONES CRUZADAS (CROSS JOIN)

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 CONDICIÓN DE

ENLACE. SE GENERA EL PRODUCTO CARTESIANO EN EL QUE EL NÚMERO DE FILAS DEL RESULTADO ES

IGUAL AL NÚMERO DE REGISTROS DE LA PRIMERA TABLA MULTIPLICADO POR EL NÚMERO 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 BÁSICA ES ÉSTA:

SELECT CAMPOS

FROM TABLA1

Page 77: Base de Datos SQL

CROSS JOIN TABLA2;

VEAMOS UN EJEMPLO. UN PEQUEÑO RESTAURANTE ALMACENA LOS NOMBRES Y PRECIOS DE SUS

COMIDAS EN UNA TABLA LLAMADA "COMIDAS" Y EN UNA TABLA DENOMINADA "POSTRES" LOS MISMOS

DATOS DE SUS POSTRES.

SI NECESITAMOS CONOCER TODAS LAS COMBINACIONES POSIBLES PARA UN MENÚ, CADA COMIDA CON

CADA POSTRE, EMPLEAMOS UN "CROSS JOIN":

SELECT C.NOMBRE AS 'PLATO PRINCIPAL', P.NOMBRE AS 'POSTRE'

FROM COMIDAS AS C

CROSS JOIN POSTRES AS P;

LA SALIDA MUESTRA CADA PLATO COMBINADO CON CADA UNO DE LOS POSTRES.

COMO CUALQUIER TIPO DE "JOIN", PUEDE EMPLEARSE UNA CLÁUSULA "WHERE" QUE CONDICIONE LA

SALIDA.

71 - AUTOCOMBINACIÓN

DIJIMOS QUE ES POSIBLE COMBINAR UNA TABLA CONSIGO MISMA.

UN PEQUEÑO RESTAURANTE TIENE ALMACENADAS SUS COMIDAS EN UNA TABLA LLAMADA "COMIDAS"

QUE CONSTA DE LOS SIGUIENTES CAMPOS:

- NOMBRE VARCHAR(20),

- PRECIO DECIMAL (4,2) Y

- RUBRO CHAR(6)-- QUE INDICA CON 'PLATO' SI ES UN PLATO PRINCIPAL Y 'POSTRE' SI ES POSTRE.

PODEMOS OBTENER LA COMBINACIÓN DE PLATOS EMPLEANDO UN "CROSS JOIN" CON UNA SOLA TABLA:

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

Page 78: Base de Datos SQL

EN UNA AUTOCOMBINACIÓN SE COMBINA UNA TABLA CON UNA COPIA DE SI MISMA. PARA ELLO DEBEMOS

UTILIZAR 2 ALIAS PARA LA TABLA. PARA EVITAR QUE APAREZCAN FILAS DUPLICADAS, DEBEMOS

EMPLEAR UN "WHERE".

TAMBIÉN SE PUEDE REALIZAR UNA AUTOCOMBINACIÓN CON "JOIN":

SELECT C1.NOMBRE AS 'PLATO PRINCIPAL',

C2.NOMBRE AS POSTRE,

C1.PRECIO+C2.PRECIO AS TOTAL

FROM COMIDAS AS C1

JOIN COMIDAS AS C2

ON C1.CODIGO<>C2.CODIGO

WHERE C1.RUBRO='PLATO' AND

C2.RUBRO='POSTRE';

PARA QUE NO APAREZCAN FILAS DUPLICADAS SE AGREGA UN "WHERE".

72 - COMBINACIONES Y FUNCIONES DE

AGRUPAMIENTO

PODEMOS USAR "GROUP BY" Y LAS FUNCIONES DE AGRUPAMIENTO CON COMBINACIONES DE TABLAS.

PARA VER LA CANTIDAD DE LIBROS DE CADA EDITORIAL CONSULTANDO LA TABLA "LIBROS" Y

"EDITORIALES", TIPEAMOS:

SELECT NOMBRE AS EDITORIAL,

COUNT(*) AS CANTIDAD

FROM EDITORIALES AS E

JOIN LIBROS AS L

ON CODIGOEDITORIAL=E.CODIGO

GROUP BY E.NOMBRE;

NOTE QUE LAS EDITORIALES QUE NO TIENEN LIBROS NO APARECEN EN LA SALIDA PORQUE EMPLEAMOS

UN "JOIN".

EMPLEAMOS OTRA FUNCIÓN DE AGRUPAMIENTO CON "LEFT JOIN". PARA CONOCER EL MAYOR PRECIO

DE LOS LIBROS DE CADA EDITORIAL USAMOS LA FUNCIÓN "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.

Page 79: Base de Datos SQL

73 - COMBINACIÓN DE MÁS DE DOS TABLAS

PODEMOS HACER UN "JOIN" CON MÁS DE DOS TABLAS.

CADA JOIN COMBINA 2 TABLAS. SE PUEDEN EMPLEAR VARIOS JOIN PARA ENLAZAR VARIAS TABLAS.

CADA RESULTADO DE UN JOIN ES UNA TABLA QUE PUEDE COMBINARSE CON OTRO JOIN.

LA LIBRERÍA ALMACENA LOS DATOS DE SUS LIBROS EN TRES TABLAS: LIBROS, EDITORIALES Y AUTORES.

EN LA TABLA "LIBROS" UN CAMPO "CODIGOAUTOR" HACE REFERENCIA AL AUTOR Y UN CAMPO

"CODIGOEDITORIAL" REFERENCIA LA EDITORIAL.

PARA RECUPERAR TODOS LOS DATOS DE LOS LIBROS EMPLEAMOS LA SIGUIENTE CONSULTA:

SELECT TITULO,A.NOMBRE,E.NOMBRE

FROM AUTORES AS A

JOIN LIBROS AS L

ON CODIGOAUTOR=A.CODIGO

JOIN EDITORIALES AS E ON CODIGOEDITORIAL=E.CODIGO;

ANALICEMOS LA CONSULTA ANTERIOR. INDICAMOS EL NOMBRE DE LA TABLA LUEGO DEL "FROM"

("AUTORES"), COMBINAMOS ESA TABLA CON LA TABLA "LIBROS" ESPECIFICANDO CON "ON" EL CAMPO

POR EL CUAL SE COMBINARÁN; LUEGO DEBEMOS HACER COINCIDIR LOS VALORES PARA EL ENLACE CON

LA TABLA "EDITORIALES" ENLAZÁNDOLAS POR LOS CAMPOS CORRESPONDIENTES. UTILIZAMOS ALIAS

PARA UNA SENTENCIA MÁS SENCILLA Y COMPRENSIBLE.

NOTE QUE ESPECIFICAMOS A QUÉ TABLA PERTENECEN LOS CAMPOS CUYO NOMBRE SE REPITEN EN LAS

TABLAS, ESTO ES NECESARIO PARA EVITAR CONFUSIONES Y AMBIGUEDADES AL MOMENTO DE

REFERENCIAR UN CAMPO.

NOTE QUE NO APARECEN LOS LIBROS CUYO CÓDIGO DE AUTOR NO SE ENCUENTRA EN "AUTORES" Y CUYA

EDITORIAL NO EXISTE EN "EDITORIALES", ESTO ES PORQUE REALIZAMOS UNA COMBINACIÓN INTERNA.

PODEMOS COMBINAR VARIOS TIPOS DE JOIN EN UNA MISMA SENTENCIA:

SELECT TITULO,A.NOMBRE,E.NOMBRE

FROM AUTORES AS A

RIGHT JOIN LIBROS AS L

ON CODIGOAUTOR=A.CODIGO

LEFT JOIN EDITORIALES AS E ON CODIGOEDITORIAL=E.CODIGO;

EN LA CONSULTA ANTERIOR SOLICITAMOS EL TÍTULO, AUTOR Y EDITORIAL DE TODOS LOS LIBROS QUE

ENCUENTREN O NO COINCIDENCIA CON "AUTORES" ("RIGHT JOIN") Y A ESE RESULTADO LO

COMBINAMOS CON "EDITORIALES", ENCUENTREN O NO COINCIDENCIA.

ES POSIBLE REALIZAR VARIAS COMBINACIONES PARA OBTENER INFORMACIÓN DE VARIAS TABLAS. LAS

TABLAS DEBEN TENER CLAVES EXTERNAS RELACIONADAS CON LAS TABLAS A COMBINAR.

EN CONSULTAS EN LAS CUALES EMPLEAMOS VARIOS "JOIN" ES IMPORTANTE TENER EN CUENTA EL

ORDEN DE LAS TABLAS Y LOS TIPOS DE "JOIN"; RECUERDE QUE LA TABLA RESULTADO DEL PRIMER JOIN

ES LA QUE SE COMBINA CON EL SEGUNDO JOIN, NO LA SEGUNDA TABLA NOMBRADA. EN EL EJEMPLO

Page 80: Base de Datos SQL

ANTERIOR, EL "LEFT JOIN" NO SE REALIZA ENTRE LAS TABLAS "LIBROS" Y "EDITORIALES" SINO ENTRE

EL RESULTADO DEL "RIGHT JOIN" Y LA TABLA "EDITORIALES".

74 - COMBINACIONES CON UPDATE Y DELETE

LAS COMBINACIONES NO SÓLO SE UTILIZAN CON LA SENTENCIA "SELECT", TAMBIÉN PODEMOS

EMPLEARLAS CON "UPDATE" Y "DELETE".

PODEMOS EMPLEAR "UPDATE" O "DELETE" CON "JOIN" PARA ACTUALIZAR O ELIMINAR REGISTROS DE

UNA 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';

75 - CLAVE FORÁNEA

UN CAMPO QUE NO ES CLAVE PRIMARIA EN UNA TABLA Y SIRVE PARA ENLAZAR SUS VALORES CON OTRA

TABLA EN LA CUAL ES CLAVE PRIMARIA SE DENOMINA CLAVE FORÁNEA, EXTERNA O AJENA.

EN EL EJEMPLO DE LA LIBRERÍA EN QUE UTILIZAMOS LAS TABLAS "LIBROS" Y "EDITORIALES" CON

ESTOS CAMPOS:

LIBROS: CODIGO (CLAVE PRIMARIA), TITULO, AUTOR, CODIGOEDITORIAL, PRECIO Y

EDITORIALES: CODIGO (CLAVE PRIMARIA), NOMBRE.

EL CAMPO "CODIGOEDITORIAL" DE "LIBROS" ES UNA CLAVE FORÁNEA, SE EMPLEA PARA ENLAZAR LA

TABLA "LIBROS" CON "EDITORIALES" Y ES CLAVE PRIMARIA EN "EDITORIALES" CON EL NOMBRE

"CODIGO".

LAS CLAVES FORÁNEAS Y LAS CLAVES PRIMARIAS DEBEN SER DEL MISMO TIPO PARA PODER ENLAZARSE.

SI MODIFICAMOS UNA, DEBEMOS MODIFICAR LA OTRA PARA QUE LOS VALORES SE CORRESPONDAN.

Page 81: Base de Datos SQL

CUANDO ALTERAMOS UNA TABLA, DEBEMOS TENER CUIDADO CON LAS CLAVES FORÁNEAS. SI

MODIFICAMOS EL TIPO, LONGITUD O ATRIBUTOS DE UNA CLAVE FORÁNEA, ÉSTA PUEDE QUEDAR

INHABILITADA PARA HACER LOS ENLACES.

ENTONCES, UNA CLAVE FORÁNEA ES UN CAMPO (O VARIOS) EMPLEADOS PARA ENLAZAR DATOS DE 2

TABLAS, PARA ESTABLECER UN "JOIN" CON OTRA TABLA EN LA CUAL ES CLAVE PRIMARIA.

76 - RESTRICCIONES (FOREIGN KEY)

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 VÁLIDOS 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 RESTRICCIÓN "FOREIGN KEY" SE DEFINE UN CAMPO (O VARIOS) CUYOS VALORES COINCIDEN

CON LA CLAVE PRIMARIA DE LA MISMA TABLA O DE OTRA, ES DECIR, SE DEFINE UNA REFERENCIA A UN

CAMPO CON UNA RESTRICCIÓN "PRIMARY KEY" O "UNIQUE" DE LA MISMA TABLA O DE OTRA.

LA INTEGRIDAD REFERENCIAL ASEGURA QUE SE MANTENGAN LAS REFERENCIAS ENTRE LAS CLAVES

PRIMARIAS Y LAS EXTERNAS. POR EJEMPLO, CONTROLA QUE SI SE AGREGA UN CÓDIGO DE EDITORIAL EN

LA TABLA "LIBROS", TAL CÓDIGO EXISTA EN LA TABLA "EDITORIALES".

TAMBIÉN CONTROLA QUE NO PUEDA ELIMINARSE UN REGISTRO DE UNA TABLA NI MODIFICAR LA CLAVE

PRIMARIA SI UNA CLAVE EXTERNA HACE REFERENCIA AL REGISTRO. POR EJEMPLO, QUE NO SE PUEDA

ELIMINAR O MODIFICAR UN CÓDIGO DE "EDITORIALES" SI EXISTEN LIBROS CON DICHO CÓDIGO.

LA SIGUIENTE ES LA SINTAXIS PARCIAL GENERAL PARA AGREGAR UNA RESTRICCIÓN "FOREIGN KEY":

ALTER TABLE NOMBRETABLA1

ADD CONSTRAINT NOMBRERESTRICCION

FOREIGN KEY (CAMPOCLAVEFORANEA)

REFERENCES NOMBRETABLA2 (CAMPOCLAVEPRIMARIA);

ANALICÉMOSLA:

- NOMBRETABLA1 REFERENCIA EL NOMBRE DE LA TABLA A LA CUAL LE APLICAMOS LA RESTRICCIÓN,

- NOMBRERESTRICCION ES EL NOMBRE QUE LE DAMOS A LA MISMA,

- LUEGO DE "FOREIGN KEY", ENTRE PARÉNTESIS SE COLOCA EL CAMPO DE LA TABLA A LA QUE LE

APLICAMOS LA RESTRICCIÓN QUE SERÁ ESTABLECIDA COMO CLAVE FORÁNEA,

- 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 FORÁNEA. LA TABLA

Page 82: Base de Datos SQL

REFERENCIADA DEBE TENER DEFINIDA UNA RESTRICCIÓN "PRIMARY KEY" O "UNIQUE"; SI NO LA TIENE,

APARECE UN MENSAJE DE ERROR.

PARA AGREGAR UNA RESTRICCIÓN "FOREIGN KEY" AL CAMPO "CODIGOEDITORIAL" DE "LIBROS",

TIPEAMOS:

ALTER TABLE LIBROS

ADD CONSTRAINT FK_LIBROS_CODIGOEDITORIAL

FOREIGN KEY (CODIGOEDITORIAL)

REFERENCES EDITORIALES(CODIGO);

EN EL EJEMPLO IMPLEMENTAMOS UNA RESTRICCIÓN "FOREIGN KEY" PARA ASEGURARNOS QUE EL

CÓDIGO DE LA EDITORIAL DE LA DE LA TABLA "LIBROS" ("CODIGOEDITORIAL") ESTÉ ASOCIADA CON UN

CÓDIGO VÁLIDO EN LA TABLA "EDITORIALES" ("CODIGO").

CUANDO AGREGAMOS CUALQUIER RESTRICCIÓN A UNA TABLA QUE CONTIENE INFORMACIÓN, SQL

SERVER CONTROLA LOS DATOS EXISTENTES PARA CONFIRMAR QUE CUMPLEN CON LA RESTRICCIÓN, SI

NO LOS CUMPLE, LA RESTRICCIÓN NO SE APLICA Y APARECE UN MENSAJE DE ERROR. POR EJEMPLO, SI

INTENTAMOS AGREGAR UNA RESTRICCIÓN "FOREIGN KEY" A LA TABLA "LIBROS" Y EXISTE UN LIBRO

CON UN VALOR DE CÓDIGO PARA EDITORIAL QUE NO EXISTE EN LA TABLA "EDITORIALES", LA

RESTRICCIÓN NO SE AGREGA.

ACTÚA EN INSERCIONES. SI INTENTAMOS INGRESAR UN REGISTRO (UN LIBRO) CON UN VALOR DE CLAVE

FORÁNEA (CODIGOEDITORIAL) QUE NO EXISTE EN LA TABLA REFERENCIADA (EDITORIALES), SQL

SERVER MUESTRA UN MENSAJE DE ERROR. SI AL INGRESAR UN REGISTRO (UN LIBRO), NO COLOCAMOS EL

VALOR PARA EL CAMPO CLAVE FORÁNEA (CODIGOEDITORIAL), ALMACENARÁ "NULL", PORQUE ESTA

RESTRICCIÓN PERMITE VALORES NULOS (A MENOS QUE SE HAYA ESPECIFICADO LO CONTRARIO AL

DEFINIR EL CAMPO).

ACTÚA EN ELIMINACIONES Y ACTUALIZACIONES. SI INTENTAMOS ELIMINAR UN REGISTRO O MODIFICAR

UN VALOR DE CLAVE PRIMARIA DE UNA TABLA SI UNA CLAVE FORÁNEA HACE REFERENCIA A DICHO

REGISTRO, SQL SERVER NO LO PERMITE (EXCEPTO SI SE PERMITE LA ACCIÓN EN CASCADA, TEMA QUE

VEREMOS POSTERIORMENTE). POR EJEMPLO, SI INTENTAMOS ELIMINAR UNA EDITORIAL A LA QUE SE

HACE REFERENCIA EN "LIBROS", APARECE UN MENSAJE DE ERROR.

ESTA RESTRICCIÓN (A DIFERENCIA DE "PRIMARY KEY" Y "UNIQUE") NO CREA ÍNDICE

AUTOMATICAMENTE.

LA CANTIDAD Y TIPO DE DATOS DE LOS CAMPOS ESPECIFICADOS LUEGO DE "FOREIGN KEY" DEBEN

COINCIDIR CON LA CANTIDAD Y TIPO DE DATOS DE LOS CAMPOS DE LA CLÁUSULA "REFERENCES".

ESTA RESTRICCIÓN SE PUEDE DEFINIR DENTRO DE LA MISMA TABLA (LO VEREMOS MÁS ADELANTE) O

ENTRE DISTINTAS TABLAS.

UNA TABLA PUEDE TENER VARIAS RESTRICCIONES "FOREIGN KEY".

NO SE PUEDE ELIMINAR UNA TABLA REFERENCIADA EN UNA RESTRICCIÓN "FOREIGN KEY", APARECE UN

MENSAJE DE ERROR.

UNA RESTRICCION "FOREIGN KEY" NO PUEDE MODIFICARSE, DEBE ELIMINARSE Y VOLVERSE A CREAR.

Page 83: Base de Datos SQL

PARA VER INFORMACIÓN ACERCA DE ESTA RESTRICCIÓN PODEMOS EJECUTAR EL PROCEDIMIENTO

ALMACENADO "SP_HELPCONSTRAINT" JUNTO AL NOMBRE DE LA TABLA. NOS MUESTRA EL TIPO,

NOMBRE, LA OPCIÓN PARA ELIMINACIONES Y ACTUALIZACIONES, EL ESTADO (TEMAS QUE VEREMOS MÁS

ADELANTE), EL NOMBRE DEL CAMPO Y LA TABLA Y CAMPO QUE REFERENCIA.

TAMBIÉN INFORMA SI LA TABLA ES REFERENCIADA POR UNA CLAVE FORÁNEA.

77 - RESTRICCIONES FOREIGN KEY EN LA MISMA

TABLA

LA RESTRICCIÓN "FOREIGN KEY", QUE DEFINE UNA REFERENCIA A UN CAMPO CON UNA RESTRICCIÓN

"PRIMARY KEY" O "UNIQUE" SE PUEDE DEFINIR ENTRE DISTINTAS TABLAS (COMO HEMOS APRENDIDO) O

DENTRO DE LA MISMA TABLA.

VEAMOS UN EJEMPLO EN EL CUAL DEFINIMOS ESTA RESTRICCIÓN DENTRO DE LA MISMA TABLA.

UNA MUTUAL ALMACENA LOS DATOS DE SUS AFILIADOS EN UNA TABLA LLAMADA "AFILIADOS".

ALGUNOS 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 RESTRICCIÓN "FOREIGN KEY" PARA ASEGURARNOS QUE EL NÚMERO 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 RESTRICCIÓN, CADA VEZ QUE SE INGRESE UN VALOR EN EL CAMPO

"AFILIADOTITULAR", SQL SERVER CONTROLARÁ QUE DICHO NÚMERO EXISTA EN LA TABLA, SI NO

EXISTE, MOSTRARÁ UN MENSAJE DE ERROR.

Page 84: Base de Datos SQL

SI INTENTAMOS ELIMINAR UN AFILIADO QUE ES TITULAR DE OTROS AFILIADOS, NO SE PODRÁ HACER, A

MENOS QUE SE HAYA ESPECIFICADO LA ACCIÓN EN CASCADA (PRÓXIMO TEMA).

78 - RESTRICCIONES FOREIGN KEY (ACCIONES)

CONTINUAMOS CON LA RESTRICCIÓN "FOREIGN KEY".

SI INTENTAMOS ELIMINAR UN REGISTRO DE LA TABLA REFERENCIADA POR UNA RESTRICCIÓN "FOREIGN

KEY" CUYO VALOR DE CLAVE PRIMARIA EXISTE REFERENCIADA EN LA TABLA QUE TIENE DICHA

RESTRICCIÓN, LA ACCIÓN NO SE EJECUTA Y APARECE UN MENSAJE DE ERROR. ESTO SUCEDE PORQUE,

POR DEFECTO, PARA ELIMINACIONES, LA OPCIÓN DE LA RESTRICCIÓN "FOREIGN KEY" ES "NO ACTION".

LO MISMO SUCEDE SI INTENTAMOS ACTUALIZAR UN VALOR DE CLAVE PRIMARIA DE UNA TABLA

REFERENCIADA POR UNA "FOREIGN KEY" EXISTENTE EN LA TABLA PRINCIPAL.

LA RESTRICCIÓN "FOREIGN KEY" TIENE LAS CLÁUSULAS "ON DELETE" Y "ON UPDATE" QUE SON

OPCIONALES.

ESTAS CLÁUSULAS ESPECIFICAN CÓMO DEBE ACTUAR SQL SERVER FRENTE A ELIMINACIONES Y

MODIFICACIONES DE LAS TABLAS REFERENCIADAS EN LA RESTRICCIÓN.

LAS OPCIONES PARA ESTAS CLÁUSULAS SON LAS SIGUIENTES:

- "NO ACTION": INDICA QUE SI INTENTAMOS ELIMINAR O ACTUALIZAR UN VALOR DE LA CLAVE PRIMARIA

DE LA TABLA REFERENCIADA (TABLA2) QUE TENGAN REFERENCIA EN LA TABLA PRINCIPAL (TABLA1),

SE GENERE UN ERROR Y LA ACCIÓN NO SE REALICE; ES LA OPCIÓN PREDETERMINADA.

- "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),

TAMBIÉN SE ELIMINEN O MODIFIQUEN; ES DECIR, SI ELIMINAMOS O MODIFICAMOS UN VALOR DE CAMPO

DEFINIDO CON UNA RESTRICCIÓN "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 RESTRICCIÓN A UNA TABLA ES LA SIGUIENTE:

ALTER TABLE TABLA1

ADD CONSTRAINT NOMBRERESTRICCION

FOREIGN KEY (CAMPOCLAVEFORANEA)

REFERENCES TABLA2(CAMPOCLAVEPRIMARIA)

ON DELETE OPCION

ON UPDATE OPCION;

SINTETIZANDO, SI AL AGREGAR UNA RESTRICCIÓN FOREIGN KEY:

- NO SE ESPECIFICA ACCIÓN PARA ELIMINACIONES (O SE ESPECIFICA "NO_ACTION"), Y SE INTENTA

ELIMINAR UN REGISTRO DE LA TABLA REFERENCIADA (EDITORIALES) CUYO VALOR DE CLAVE PRIMARIA

(CODIGO) EXISTE EN LA TABLA PRINCIPAL (LIBROS), LA ACCIÓN 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 ELIMINACIÓN DE LA TABLA REFERENCIADA (EDITORIALES) SE REALIZA Y

Page 85: Base de Datos SQL

SE ELIMINAN DE LA TABLA PRINCIPAL (LIBROS) TODOS LOS REGISTROS CUYO VALOR COINCIDE CON EL

REGISTRO ELIMINADO DE LA TABLA REFERENCIADA (EDITORIALES).

- NO SE ESPECIFICA ACCIÓN PARA ACTUALIZACIONES (O SE ESPECIFICA "NO_ACTION"), Y SE INTENTA

MODIFICAR UN VALOR DE CLAVE PRIMARIA (CODIGO) DE LA TABLA REFERENCIADA (EDITORIALES) QUE

EXISTE EN EL CAMPO CLAVE FORÁNEA (CODIGOEDITORIAL) DE LA TABLA PRINCIPAL (LIBROS), LA

ACCIÓN NO SE REALIZA.

- SE ESPECIFICA "CASCADE" PARA ACTUALIZACIONES ("ON UPDATE CASCADE") Y SE MODIFICA UN

VALOR 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 RESTRICCIÓN "FOREIGN KEY" A LA TABLA "LIBROS"

ESTABLECIENDO EL CAMPO "CODIGOEDITORIAL" COMO CLAVE FORÁNEA QUE REFERENCIA AL CAMPO

"CODIGO" DE LA TABLA "EDITORIALES". LA TABLA "EDITORIALES" TIENE COMO CLAVE PRIMARIA EL

CAMPO "CODIGO". ESPECIFICAMOS LA ACCIÓN EN CASCADA PARA LAS ACTUALIZACIONES Y

ELIMINACIONES:

ALTER TABLE LIBROS

ADD CONSTRAINT FK_LIBROS_CODIGOEDITORIAL

FOREIGN KEY (CODIGOEDITORIAL)

REFERENCES EDITORIALES(CODIGO)

ON UPDATE CASCADE

ON DELETE CASCADE;

SI LUEGO DE ESTABLECER LA RESTRICCIÓN ANTERIOR, ELIMINAMOS UNA EDITORIAL DE "EDITORIALES"

DE LAS CUALES HAY LIBROS, SE ELIMINA DICHA EDITORIAL Y TODOS LOS LIBROS DE TAL EDITORIAL. Y SI

MODIFICAMOS EL VALOR DE CÓDIGO DE UNA EDITORIAL DE "EDITORIALES", SE MODIFICA EN

"EDITORIALES" Y TODOS LOS VALORES IGUALES DE "CODIGOEDITORIAL" DE LIBROS TAMBIÉN SE

MODIFICAN.

79 - RESTRICCIONES FOREIGN KEY DESHABILITAR Y

ELIMINAR (WITH CHECK - NOCHECK)

SABEMOS QUE SI AGREGAMOS UNA RESTRICCIÓN A UNA TABLA QUE CONTIENE DATOS, SQL SERVER LOS

CONTROLA PARA ASEGURARSE QUE CUMPLEN CON LA RESTRICCIÓN; ES POSIBLE DESHABILITAR ESTA

COMPROBACIÓN.

PODEMOS HACERLO AL MOMENTO DE AGREGAR LA RESTRICCIÓN A UNA TABLA CON DATOS, INCLUYENDO

LA OPCIÓN "WITH NOCHECK" EN LA INSTRUCCIÓN "ALTER TABLE"; SI SE EMPLEA ESTA OPCIÓN, LOS

DATOS NO VAN A CUMPLIR LA RESTRICCIÓN.

SE PUEDEN DESHABILITAR LAS RESTRICCIONES "CHECK" Y "FOREIGN KEY", A LAS DEMÁS SE LAS DEBE

ELIMINAR.

LA SINTAXIS BÁSICA AL AGREGAR LA RESTRICCCIÓN "FOREIGN KEY" ES LA SIGUIENTE:

Page 86: Base de Datos SQL

ALTER TABLE NOMBRETABLA1

WITH OPCIONDECHEQUEO

ADD CONSTRAINT NOMBRECONSTRAINT

FOREIGN KEY (CAMPOCLAVEFORANEA)

REFERENCES NOMBRETABLA2 (CAMPOCLAVEPRIMARIA)

ON UPDATE OPCION

ON DELETE OPCION;

LA OPCIÓN "WITH OPCIONDECHEQUEO" ESPECIFICA SI SE CONTROLAN LOS DATOS EXISTENTES O

NO CON "CHECK" Y "NOCHECK" RESPECTIVAMENTE. POR DEFECTO, SI NO SE ESPECIFICA, LA OPCIÓN ES

"CHECK".

EN EL SIGUIENTE EJEMPLO AGREGAMOS UNA RESTRICCIÓN "FOREIGN KEY" QUE CONTROLA QUE TODOS

LOS CÓDIGOS DE EDITORIAL TENGAN UN CÓDIGO VÁLIDO, ES DECIR, DICHO CÓDIGO EXISTA EN

"EDITORIALES". LA RESTRICCIÓN NO SE APLICA EN LOS DATOS EXISTENTES PERO SI EN LOS SIGUIENTES

INGRESOS, MODIFICACIONES Y ACTUALIZACIONES:

ALTER TABLE LIBROS

WITH NOCHECK

ADD CONSTRAINT FK_LIBROS_CODIGOEDITORIAL

FOREING KEY (CODIGOEDITORIAL)

REFERENCES EDITORIALES(CODIGO);

LA COMPROBACIÓN DE RESTRICCIONES SE PUEDE DESHABILITAR PARA MODIFICAR, ELIMINAR O

AGREGAR DATOS A UNA TABLA SIN COMPROBAR LA RESTRICCIÓN. LA SINTAXIS GENERAL ES:

ALTER TABLE NOMBRETABLA

OPCIONDECHEQUEO CONSTRAINT NOMBRERESTRICCION;

EN EL SIGUIENTE EJEMPLO DESHABILITAMOS LA RESTRICCIÓN CREADA ANTERIORMENTE:

ALTER TABLE LIBROS

NOCHECK CONSTRAINT FK_LIBROS_CODIGOEDITORIAL;

PARA HABILITAR UNA RESTRICCIÓN DESHABILITADA SE EJECUTA LA MISMA INSTRUCCIÓN PERO CON LA

CLÁUSULA "CHECK" O "CHECK ALL":

ALTER TABLE LIBROS

CHECK CONSTRAINT FK_LIBROS_CODIGOEDITORIAL;

SI SE EMPLEA "CHECK CONSTRAINT ALL" NO SE COLOCA NOMBRE DE RESTRICCIONES, HABILITA TODAS

LAS RESTRICCIONES QUE TIENE LA TABLA NOMBRADA ("CHECK" Y "FOREIGN KEY").

PARA SABER SI UNA RESTRICCIÓN ESTÁ HABILITADA O NO, PODEMOS EJECUTAR EL PROCEDIMIENTO

ALMACENADO "SP_HELPCONSTRAINT" Y ENTENDEREMOS LO QUE INFORMA LA COLUMNA

"STATUS_ENABLED".

ENTONCES, LAS CLÁUSULAS "CHECK" Y "NOCHECK" PERMITEN HABILITAR O DESHABILITAR

RESTRICCIONES "FOREIGN KEY" (Y "CHECK"). PUEDEN EMPLEARSE PARA EVITAR LA COMPROBACIÓN

DE DATOS EXISTENTES AL CREAR LA RESTRICCIÓN O PARA DESHABILITAR LA COMPROBACIÓN DE DATOS

AL INGRESAR, ACTUALIZAR Y ELIMINAR ALGÚN REGISTRO QUE INFRINJA LA RESTRICCIÓN.

PODEMOS ELIMINAR UNA RESTRICCIÓN "FOREIGN KEY" CON "ALTER TABLE". LA SINTAXIS BÁSICA ES

LA MISMA QUE PARA CUALQUIER OTRA RESTRICCIÓN:

Page 87: Base de Datos SQL

ALTER TABLE TABLA

DROP CONSTRAINT NOMBRERESTRICCION;

ELIMINAMOS LA RESTRICCIÓN DE "LIBROS":

ALTER TABLE LIBROS

DROP CONSTRAINT FK_LIBROS_CODIGOEDITORIAL;

NO SE PUEDE ELIMINAR UNA TABLA SI UNA RESTRICCIÓN "FOREIGN KEY" HACE REFERENCIA A ELLA.

CUANDO ELIMINAMOS UNA TABLA QUE TIENE UNA RESTRICCIÓN "FOREIGN KEY", LA RESTRICCIÓN

TAMBIÉN SE ELIMINA.

80 - RESTRICCIONES FOREIGN KEY (INFORMACIÓN)

EL PROCEDIMIENTO ALMACENADO "SP_HELPCONSTRAINT" DEVUELVE LAS SIGUIENTES COLUMNAS:

- CONSTRAINT_TYPE: TIPO DE RESTRICCIÓN. SI ES UNA RESTRICCIÓN DE CAMPO (DEFAULT O CHECK)

INDICA 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 RESTRICCIÓN.

- DELETE_ACTION: SOLAMENTE ES APLICABLE PARA RESTRICCIONES DE TIPO "FOREIGN KEY". INDICA SI

LA ACCIÓN DE ELIMINACIÓN ACTÚA, NO ACTÚA O ES EN CASCADA. INDICA "N/A" EN CUALQUIER

RESTRICCIÓN PARA LA QUE NO SE APLIQUE; "NO ACTION" SI NO ACTÚA Y "CASCADE" SI ES EN

CASCADA.

- UPDATE_ACTION: SÓLO ES APLICABLE PARA RESTRICCIONES DE TIPO "FOREIGN KEY". INDICA SI LA

ACCIÓN DE ACTUALIZACIÓN ES: NO ACTION, CASCADE, OR N/A. INDICA "N/A" EN CUALQUIER

RESTRICCIÓN 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

RESTRICCIÓN 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 RESTRICCIÓN PARA LA QUE NO SE APLIQUE.

- CONSTRAINT_KEYS: SI ES UNA RESTRICCIÓN "DEFAULT" MUESTRA LA CONDICIÓN DE CHEQUEO; SI ES

UNA RESTRICCIÓN "DEFAULT", EL VALOR POR DEFECTO; SI ES UNA "PRIMARY KEY", "UNIQUE" O

"FOREIGN KEY" MUESTRA EL/ LOS CAMPOS A LOS QUE SE APLICARON LA RESTRICCIÓN. EN CASO DE

VALORES PREDETERMINADOS Y REGLAS, EL TEXTO QUE LO DEFINE.

81 - RESTRICCIONES AL CREAR LA TABLA

Page 88: Base de Datos SQL

HASTA EL MOMENTO HEMOS AGREGADO RESTRICCIONES A TABLAS EXISTENTES CON "ALTER TABLE"

(MANERA ACONSEJADA), TAMBIÉN PUEDEN ESTABLECERSE AL MOMENTO DE CREAR UNA TABLA (EN LA

INSTRUCCIÓN "CREATE TABLE").

PODEMOS APLICAR RESTRICCIONES A NIVEL DE CAMPO (RESTRICCIÓN DE CAMPO) O A NIVEL DE TABLA

(RESTRICCIÓN DE TABLA).

EN EL SIGUIENTE EJEMPLO CREAMOS LA TABLA "LIBROS" CON VARIAS RESTRICCIONES:

CREATE TABLE LIBROS(

CODIGO INT IDENTITY,

TITULO VARCHAR(40),

CODIGOAUTOR INT NOT NULL,

CODIGOEDITORIAL TINYINT NOT NULL,

PRECIO DECIMAL(5,2)

CONSTRAINT DF_PRECIO DEFAULT (0),

CONSTRAINT PK_LIBROS_CODIGO

PRIMARY KEY CLUSTERED (CODIGO),

CONSTRAINT UQ_LIBROS_TITULOAUTOR

UNIQUE (TITULO,CODIGOAUTOR),

CONSTRAINT FK_LIBROS_EDITORIAL

FOREIGN KEY (CODIGOEDITORIAL)

REFERENCES EDITORIALES(CODIGO)

ON UPDATE CASCADE,

CONSTRAINT FK_LIBROS_AUTORES

FOREIGN KEY (CODIGOAUTOR)

REFERENCES AUTORES(CODIGO)

ON UPDATE CASCADE,

CONSTRAINT CK_PRECIO_POSITIVO CHECK (PRECIO>=0)

);

EN EL EJEMPLO ANTERIOR CREAMOS:

- UNA RESTRICCIÓN "DEFAULT" PARA EL CAMPO "PRECIO" (RESTRICCIÓN A NIVEL DE CAMPO);

- UNA RESTRICCIÓN "PRIMARY KEY" CON ÍNDICE AGRUPADO PARA EL CAMPO "CODIGO" (A NIVEL DE

TABLA);

- UNA RESTRICCIÓN "UNIQUE" CON ÍNDICE NO AGRUPADO (POR DEFECTO) PARA LOS CAMPOS "TITULO"

Y "CODIGOAUTOR" (A NIVEL DE TABLA);

- UNA RESTRICCIÓN "FOREIGN KEY" PARA ESTABLECER EL CAMPO "CODIGOEDITORIAL" COMO CLAVE

EXTERNA QUE HAGA REFERENCIA AL CAMPO "CODIGO" DE "EDITORIALES Y PERMITA ACTUALIZACIONES

EN CASCADA Y NO ELIMINACIONES (POR DEFECTO "NO ACTION");

- UNA RESTRICCIÓN "FOREIGN KEY" PARA ESTABLECER EL CAMPO "CODIGOAUTOR" COMO CLAVE

EXTERNA QUE HAGA REFERENCIA AL CAMPO "CODIGO" DE "AUTORES" Y PERMITA ACTUALIZACIONES

EN CASCADA Y NO ELIMINACIONES;

- UNA RESTRICCIÓN "CHECK" PARA EL CAMPO "PRECIO" QUE NO ADMITA VALORES NEGATIVOS;

SI DEFINIMOS UNA RESTRICCIÓN "FOREIGN KEY" AL CREAR UNA TABLA, LA TABLA REFERENCIADA DEBE

EXISTIR.

Page 89: Base de Datos SQL

82 - UNIÓN

EL OPERADOR "UNION" COMBINA EL RESULTADO DE DOS O MÁS INSTRUCCIONES "SELECT" EN UN ÚNICO

RESULTADO.

SE USA CUANDO LOS DATOS QUE SE QUIEREN OBTENER PERTENECEN A DISTINTAS TABLAS Y NO SE PUEDE

ACCEDER A ELLOS CON UNA SOLA CONSULTA.

ES NECESARIO QUE LAS TABLAS REFERENCIADAS TENGAN TIPOS DE DATOS SIMILARES, LA MISMA

CANTIDAD DE CAMPOS Y EL MISMO ORDEN DE CAMPOS EN LA LISTA DE SELECCIÓN DE CADA CONSULTA.

NO SE INCLUYEN LAS FILAS DUPLICADAS EN EL RESULTADO, A MENOS QUE COLOQUE LA OPCIÓN "ALL".

SE DEBEN ESPECIFICAR LOS NOMBRES DE LOS CAMPOS EN LA PRIMERA INSTRUCCIÓN "SELECT".

PUEDE EMPLEAR LA CLÁUSULA "ORDER BY".

PUEDE DIVIDIR UNA CONSULTA COMPLEJA EN VARIAS CONSULTAS "SELECT" Y LUEGO EMPLEAR EL

OPERADOR "UNION" PARA COMBINARLAS.

UNA ACADEMIA DE ENSEÑANZA ALMACENA LOS DATOS DE LOS ALUMNOS EN UNA TABLA LLAMADA

"ALUMNOS" Y LOS DATOS DE LOS PROFESORES EN OTRA DENOMINADA "PROFESORES".

LA ACADEMIA NECESITA EL NOMBRE Y DOMICILIO DE PROFESORES Y ALUMNOS PARA ENVIARLES UNA

TARJETA DE INVITACIÓN.

PARA OBTENER LOS DATOS NECESARIOS DE AMBAS TABLAS EN UNA SOLA CONSULTA NECESITAMOS

REALIZAR UNA UNIÓN:

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 UNIÓN SON LOS QUE SE ESPECIFICAN EN EL PRIMER

"SELECT".

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 BÁSICA:

Page 90: Base de Datos SQL

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 ALTERACIÓN DE LA ESTRUCTURA DE LA TABLA EJECUTANDO EL PROCEDIMIENTO

ALMACENADO "SP_COLUMNS".

SQL SERVER NO PERMITE AGREGAR CAMPOS "NOT NULL" A MENOS QUE SE ESPECIFIQUE UN VALOR POR

DEFECTO:

ALTER TABLE LIBROS

ADD AUTOR VARCHAR(20) NOT NULL DEFAULT 'DESCONOCIDO';

EN EL EJEMPLO ANTERIOR, SE AGREGÓ UNA RESTRICCIÓN "DEFAULT" PARA EL NUEVO CAMPO, QUE

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 BÁSICA ES LA SIGUIENTE:

ALTER TABLE NOMBRETABLA

DROP COLUMN NOMBRECAMPO;

EN EL SIGUIENTE EJEMPLO ELIMINAMOS EL CAMPO "PRECIO" DE LA TABLA "LIBROS":

ALTER TABLE LIBROS

DROP COLUMN PRECIO;

NO PUEDEN ELIMINARSE LOS CAMPOS QUE SON USADOS POR UN ÍNDICE O TENGAN RESTRICCIONES. NO

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;

84 - ALTERAR CAMPOS (ALTER TABLE - ALTER)

HEMOS VISTO QUE "ALTER TABLE" PERMITE MODIFICAR LA ESTRUCTURA DE UNA TABLA. TAMBIÉN

PODEMOS UTILIZARLA PARA MODIFICAR CAMPOS DE UNA TABLA.

LA SINTAXIS BÁSICA PARA MODIFICAR UN CAMPO EXISTENTE ES LA SIGUIENTE:

ALTER TABLE NOMBRETABLA

ALTER COLUMN CAMPO NUEVADEFINICION;

Page 91: Base de Datos SQL

MODIFICAMOS EL CAMPO "TITULO" EXTENDIENDO SU LONGITUD Y PARA QUE NO ADMITA VALORES

NULOS:

ALTER TABLE LIBROS

ALTER COLUMN TITULO VARCHAR(40) NOT NULL;

EN EL SIGUIENTE EJEMPLO ALTERAMOS EL CAMPO "PRECIO" DE LA TABLA "LIBROS" QUE FUE DEFINIDO

"DECIMAL(6,2) NOT NULL" PARA QUE NO ACEPTE VALORES NULOS:

ALTER TABLE LIBROS

ALTER COLUMN PRECIO DECIMAL(6,2) NULL;

SQL SERVER TIENE ALGUNAS EXCEPCIONES AL MOMENTO DE MODIFICAR LOS CAMPOS. NO PERMITE

MODIFICAR:

- CAMPOS DE TIPO TEXT, IMAGE, NTEXT Y TIMESTAMP.

- UN CAMPO QUE ES USADO EN UN CAMPO CALCULADO.

- CAMPOS QUE SON PARTE DE ÍNDICES O TIENEN RESTRICCIONES, A MENOS QUE EL CAMBIO NO AFECTE

AL ÍNDICE O A LA RESTRICCIÓN, POR EJEMPLO, SE PUEDE AMPLIAR LA LONGITUD DE UN CAMPO DE TIPO

CARACTER.

- AGREGANDO O QUITANDO EL ATRIBUTO "IDENTITY".

- CAMPOS QUE AFECTEN A LOS DATOS EXISTENTES CUANDO UNA TABLA CONTIENE REGISTROS (EJEMPLO:

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

85 - AGREGAR CAMPOS Y RESTRICCIONES (ALTER

TABLE)

PODEMOS AGREGAR UN CAMPO A UNA TABLA Y EN EL MISMO MOMENTO APLICARLE UNA RESTRICCIÓN.

PARA AGREGAR UN CAMPO Y ESTABLECER UNA RESTRICCIÓN, LA SINTAXIS BÁSICA ES LA SIGUIENTE:

ALTER TABLE TABLA

ADD CAMPO DEFINICION

CONSTRAINT NOMBRERESTRICCION TIPO;

AGREGAMOS A LA TABLA "LIBROS", EL CAMPO "TITULO" DE TIPO VARCHAR(30) Y UNA RESTRICCIÓN

"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

RESTRICCIÓN "PRIMARY KEY" CON ÍNDICE NO AGRUPADO:

Page 92: Base de Datos SQL

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 RESTRICCIÓN

"CHECK":

ALTER TABLE LIBROS

ADD PRECIO DECIMAL(6,2)

CONSTRAINT CK_LIBROS_PRECIO CHECK (PRECIO>=0);

86 - CAMPOS CALCULADOS

UN CAMPO CALCULADO ES UN CAMPO QUE NO SE ALMACENA FÍSICAMENTE EN LA TABLA. SQL SERVER

EMPLEA UNA FÓRMULA QUE DETALLA EL USUARIO AL DEFINIR DICHO CAMPO PARA CALCULAR EL VALOR

SEGÚN OTROS CAMPOS DE LA MISMA TABLA.

UN CAMPO CALCULADO NO PUEDE:

- DEFINIRSE COMO "NOT NULL".

- SER UNA SUBCONSULTA.

- TENER RESTRICCIÓN "DEFAULT" O "FOREIGN KEY".

- INSERTARSE NI ACTUALIZARSE.

PUEDE SER EMPLEADO COMO LLAVE DE UN ÍNDICE O PARTE DE RESTRICCIONES "PRIMARY KEY" O

"UNIQUE" SI LA EXPRESIÓN QUE LA DEFINE NO CAMBIA EN CADA CONSULTA.

CREAMOS UN CAMPO CALCULADO DENOMINADO "SUELDOTOTAL" QUE SUMA AL SUELDO BÁSICO DE

CADA EMPLEADO LA CANTIDAD ABONADA POR LOS HIJOS (100 POR CADA HIJO):

CREATE TABLE EMPLEADOS(

DOCUMENTO CHAR(8),

NOMBRE VARCHAR(10),

DOMICILIO VARCHAR(30),

SUELDOBASICO DECIMAL(6,2),

CANTIDADHIJOS TINYINT DEFAULT 0,

SUELDOTOTAL AS SUELDOBASICO + (CANTIDADHIJOS*100)

);

TAMBIÉN SE PUEDE AGREGAR UN CAMPO CALCULADO A UNA TABLA EXISTENTE:

ALTER TABLE 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.

Page 93: Base de Datos SQL

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 INFORMACIÓN (CARACTERES, NÚMEROS, 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 BÁSICA:

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 INFORMACIÓN DEL MISMO (NOMBRE, EL TIPO DE DATO EN QUE SE

BASA, LA LONGITUD, SI ACEPTA VALORES NULOS, SI TIENE VALOR POR DEFECTO Y REGLAS ASOCIADAS).

TAMBIÉN PODEMOS CONSULTAR LA TABLA "SYSTYPES" EN LA CUAL SE ALMACENA INFORMACIÓN DE

TODOS LOS TIPOS DE DATOS:

SELECT NAME FROM SYSTYPES;

88 - TIPO DE DATO DEFINIDO POR EL USUARIO

(ASOCIACIÓN DE REGLAS)

SE PUEDE ASOCIAR UNA REGLA A UN TIPO DE DATOS DEFINIDO POR EL USUARIO. LUEGO DE CREAR LA

REGLA SE ESTABLECE LA ASOCIACIÓN; LA SINTAXIS ES LA SIGUIENTE:

EXEC SP_BINDRULE NOMBREREGLA, 'TIPODEDATODEFINIDOPORELUSUARIO', 'FUTUREONLY';

Page 94: Base de Datos SQL

EL PARÁMETRO "FUTUREONLY" ES OPCIONAL, ESPECIFICA QUE SI EXISTEN CAMPOS (DE CUALQUIER

TABLA) CON ESTE TIPO DE DATO, NO SE ASOCIEN A LA REGLA; SI CREAMOS UNA NUEVA TABLA CON ESTE

TIPO DE DATO, SI DEBERÁN CUMPLIR LA REGLA. SI NO SE ESPECIFICA ESTE PARÁMETRO, TODOS LOS

CAMPOS DE ESTE TIPO DE DATO, EXISTENTES O QUE SE CREEN POSTERIORMENTE (DE CUALQUIER TABLA),

QUEDAN ASOCIADOS A LA REGLA.

RECUERDE QUE SQL SERVER NO CONTROLA LOS DATOS EXISTENTES PARA CONFIRMAR QUE CUMPLEN

CON LA REGLA, SI NO LOS CUMPLE, LA REGLA SE ASOCIA IGUALMENTE; PERO AL EJECUTAR UNA

INSTRUCCIÓN "INSERT" O "UPDATE" MUESTRA UN MENSAJE DE ERROR.

SI ASOCIA UNA REGLA A UN TIPO DE DATO DEFINIDO POR EL USUARIO QUE TIENE OTRA REGLA ASOCIADA,

ESTA ÚLTIMA LA REEMPLAZA.

PARA QUITAR LA ASOCIACIÓN, 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 CONTINÚA ASOCIADO A LA

REGLA. LA REGLA ASOCIADA AL CAMPO PREVALECE SOBRE LA ASOCIADA AL TIPO DE DATO. POR

EJEMPLO, TENEMOS UN CAMPO "PRECIO" DE UN TIPO DE DATO DEFINIDO POR EL USUARIO

"TIPO_PRECIO", ESTE TIPO DE DATO TIENE ASOCIADA UNA REGLA "RG_PRECIO0A99" (PRECIO ENTRE 0

Y 99), LUEGO ASOCIAMOS AL CAMPO "PRECIO" LA REGLA "RG_PRECIO100A500" (PRECIO ENTRE 100 Y

500); AL EJECUTAR UNA INSTRUCCIÓN "INSERT" ADMITIRÁ VALORES ENTRE 100 Y 500, ES DECIR,

TENDRÁ EN CUENTA LA REGLA ASOCIADA AL CAMPO, AUNQUE VAYA CONTRA LA REGLA ASOCIADA AL

TIPO DE DATO.

UN TIPO DE DATO DEFINIDO POR EL USUARIO PUEDE TENER UNA SOLA REGLA ASOCIADA.

CUANDO OBTENEMOS INFORMACIÓN DEL TIPO DA DATO DEFINIDO POR EL USUARIO EJECUTANDO

"SP_HELP", EN LA COLUMNA "RULE_NAME" SE MUESTRA EL NOMBRE DE LA REGLA ASOCIADA A DICHO

TIPO DE DATO; MUESTRAN "NONE" CUANDO NO TIENE REGLA ASOCIADA.

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 PARÁMETRO "FUTUREONLY" ES OPCIONAL, ESPECIFICA QUE SI EXISTEN CAMPOS (DE CUALQUIER

TABLA) CON ESTE TIPO DE DATO, NO SE ASOCIEN AL VALOR PREDETERMINADO; SI CREAMOS UNA NUEVA

Page 95: Base de Datos SQL

TABLA CON ESTE TIPO DE DATO, SI ESTARÁ ASOCIADO AL VALOR PREDETERMINADO. SI NO SE ESPECIFICA

ESTE PARÁMETRO, TODOS LOS CAMPOS DE ESTE TIPO DE DATO, EXISTENTES O QUE SE CREEN

POSTERIORMENTE (DE CUALQUIER TABLA), QUEDAN ASOCIADOS AL VALOR PREDETERMINADO.

SI ASOCIA UN VALOR PREDETERMINADO A UN TIPO DE DATO DEFINIDO POR EL USUARIO QUE TIENE OTRO

VALOR PREDETERMINADO ASOCIADO, EL ÚLTIMO LO REEMPLAZA.

PARA QUITAR LA ASOCIACIÓN, 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 RESTRICCIÓN "DEFAULT" EN UN CAMPO CON

UN TIPO DE DATOS DEFINIDO POR EL USUARIO SI DICHO CAMPO O TIPO DE DATO TIENEN ASOCIADO UN

VALOR PREDETERMINADO.

SI UN CAMPO DE UN TIPO DE DATO DEFINIDO POR EL USUARIO TIENE UNA RESTRICCIÓN "DEFAULT" Y

LUEGO SE ASOCIA UN VALOR PREDETERMINADO AL TIPO DE DATO, EL VALOR PREDETERMINADO NO

QUEDA ASOCIADO EN EL CAMPO QUE TIENE LA RESTRICCIÓN "DEFAULT".

UN TIPO DE DATO DEFINIDO POR EL USUARIO PUEDE TENER UN SOLO VALOR PREDETERMINADO

ASOCIADO.

CUANDO OBTENEMOS INFORMACIÓN DEL TIPO DA DATO DEFINIDO POR EL USUARIO EJECUTANDO

"SP_HELP", EN LA COLUMNA "DEFAULT_NAME" SE MUESTRA EL NOMBRE DEL VALOR PREDETERMINADO

ASOCIADO A DICHO TIPO DE DATO; MUESTRA "NONE" CUANDO NO TIENE NINGÚN VALOR

PREDETERMINADO ASOCIADO.

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

Page 96: Base de Datos SQL

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.

91 - SUBCONSULTAS

UNA SUBCONSULTA (SUBQUERY) ES UNA SENTENCIA "SELECT" ANIDADA EN OTRA SENTENCIA "SELECT", "INSERT", "UPDATE" O

"DELETE" (O EN OTRA SUBCONSULTA).

LAS SUBCONSULTAS SE EMPLEAN CUANDO UNA CONSULTA ES MUY COMPLEJA, ENTONCES SE LA DIVIDE EN VARIOS PASOS LÓGICOS Y

SE OBTIENE EL RESULTADO CON UNA ÚNICA INSTRUCCIÓN Y CUANDO LA CONSULTA DEPENDE DE LOS RESULTADOS DE OTRA

CONSULTA.

GENERALMENTE, UNA SUBCONSULTA SE PUEDE REEMPLAZAR POR COMBINACIONES Y ESTAS ÚLTIMAS SON MÁS EFICIENTES.

LAS SUBCONSULTAS SE DEBEN INCLUIR ENTRE PARÉNTESIS.

PUEDE HABER SUBCONSULTAS DENTRO DE SUBCONSULTAS, SE ADMITEN HASTA 32 NIVELES DE ANIDACIÓN.

SE PUEDEN EMPLEAR SUBCONSULTAS:

- EN LUGAR DE UNA EXPRESIÓN, SIEMPRE QUE DEVUELVAN UN SOLO VALOR O UNA LISTA DE VALORES.

- QUE RETORNEN UN CONJUNTO DE REGISTROS DE VARIOS CAMPOS EN LUGAR DE UNA TABLA O PARA OBTENER EL MISMO RESULTADO

QUE UNA COMBINACIÓN (JOIN).

HAY TRES TIPOS BÁSICOS DE SUBCONSULTAS:

1. LAS QUE RETORNAN UN SOLO VALOR ESCALAR QUE SE UTILIZA CON UN OPERADOR DE COMPARACIÓN O EN LUGAR DE UNA

EXPRESIÓN. 2. LAS QUE RETORNAN UNA LISTA DE VALORES, SE COMBINAN CON "IN", O LOS OPERADORES "ANY", "SOME" Y "ALL". 3. LOS QUE TESTEAN LA EXISTENCIA CON "EXISTS".

REGLAS A TENER EN CUENTA AL EMPLEAR SUBCONSULTAS:

Page 97: Base de Datos SQL

- LA LISTA DE SELECCIÓN DE UNA SUBCONSULTA QUE VA LUEGO DE UN OPERADOR DE COMPARACIÓN PUEDE INCLUIR SÓLO UNA

EXPRESIÓN O CAMPO (EXCEPTO SI SE EMPLEA "EXISTS" Y "IN").

- SI EL "WHERE" DE LA CONSULTA EXTERIOR INCLUYE UN CAMPO, ESTE DEBE SER COMPATIBLE CON EL CAMPO EN LA LISTA DE

SELECCIÓN DE LA SUBCONSULTA.

- NO SE PUEDEN EMPLEAR SUBCONSULTAS QUE RECUPEREN CAMPOS DE TIPOS TEXT O IMAGE.

- LAS SUBCONSULTAS LUEGO DE UN OPERADOR DE COMPARACIÓN (QUE NO ES SEGUIDO POR "ANY" O "ALL") NO PUEDEN INCLUIR

CLÁUSULAS "GROUP BY" NI "HAVING".

- "DISTINCT" NO PUEDE USARSE CON SUBCONSULTAS QUE INCLUYAN "GROUP BY".

- NO PUEDEN EMPLEARSE LAS CLÁUSULAS "COMPUTE" Y "COMPUTE BY".

- "ORDER BY" PUEDE EMPLEARSE SOLAMENTE SI SE ESPECIFICA "TOP" TAMBIÉN.

- UNA VISTA CREADA CON UNA SUBCONSULTA NO PUEDE ACTUALIZARSE.

- UNA SUBCONSULTA PUEDE ESTAR ANIDADA DENTRO DEL "WHERE" O "HAVING" DE UNA CONSULTA EXTERNA O DENTRO DE OTRA

SUBCONSULTA.

- SI UNA TABLA SE NOMBRA SOLAMENTE EN UN SUBCONSULTA Y NO EN LA CONSULTA EXTERNA, LOS CAMPOS NO SERÁN INCLUIDOS

EN LA SALIDA (EN LA LISTA DE SELECCIÓN DE LA CONSULTA EXTERNA).

92 - SUBCONSULTAS COMO EXPRESIÓN

UNA SUBCONSULTA PUEDE REEMPLAZAR UNA EXPRESIÓN. DICHA SUBCONSULTA DEBE DEVOLVER UN

VALOR ESCALAR (O UNA LISTA DE VALORES DE UN CAMPO).

LAS SUBCONSULTAS QUE RETORNAN UN SOLO VALOR ESCALAR SE UTILIZA CON UN OPERADOR DE

COMPARACIÓN O EN LUGAR DE UNA EXPRESIÓN:

SELECT CAMPOS

FROM TABLA

WHERE CAMPO OPERADOR (SUBCONSULTA);

SELECT CAMPO OPERADOR (SUBCONSULTA)

FROM TABLA;

SI QUEREMOS SABER EL PRECIO DE UN DETERMINADO LIBRO Y LA DIFERENCIA CON EL PRECIO DEL LIBRO

MÁS COSTOSO, ANTERIORMENTE DEBÍAMOS AVERIGUAR EN UNA CONSULTA EL PRECIO DEL LIBRO MÁS

COSTOSO Y LUEGO, EN OTRA CONSULTA, CALCULAR LA DIFERENCIA CON EL VALOR DEL LIBRO QUE

SOLICITAMOS. PODEMOS CONSEGUIRLO EN UNA SOLA SENTENCIA COMBINANDO DOS CONSULTAS:

SELECT TITULO,PRECIO,

PRECIO-(SELECT MAX(PRECIO) FROM LIBROS) AS DIFERENCIA

FROM LIBROS

WHERE TITULO='UNO';

Page 98: Base de Datos SQL

EN EL EJEMPLO ANTERIOR SE MUESTRA EL TÍTULO, EL PRECIO DE UN LIBRO Y LA DIFERENCIA ENTRE EL

PRECIO DEL LIBRO Y EL MÁXIMO VALOR DE PRECIO.

QUEREMOS SABER EL TÍTULO, AUTOR Y PRECIO DEL LIBRO MÁS COSTOSO:

SELECT TITULO,AUTOR, PRECIO

FROM LIBROS

WHERE PRECIO=

(SELECT MAX(PRECIO) FROM LIBROS);

NOTE QUE EL CAMPO DEL "WHERE" DE LA CONSULTA EXTERIOR ES COMPATIBLE CON EL VALOR

RETORNADO POR LA EXPRESIÓN DE LA SUBCONSULTA.

SE PUEDEN EMPLEAR EN "SELECT", "INSERT", "UPDATE" Y "DELETE".

PARA ACTUALIZAR UN REGISTRO EMPLEANDO SUBCONSULTA LA SINTAXIS BÁSICA ES LA SIGUIENTE:

UPDATE TABLA SET CAMPO=NUEVOVALOR

WHERE CAMPO= (SUBCONSULTA);

PARA ELIMINAR REGISTROS EMPLEANDO SUBCONSULTA EMPLEAMOS LA SIGUIENTE SINTAXIS BÁSICA:

DELETE FROM TABLA

WHERE CAMPO=(SUBCONSULTA);

RECUERDE QUE LA LISTA DE SELECCIÓN DE UNA SUBCONSULTA QUE VA LUEGO DE UN OPERADOR DE

COMPARACIÓN PUEDE INCLUIR SÓLO UNA EXPRESIÓN O CAMPO (EXCEPTO SI SE EMPLEA "EXISTS" O

"IN").

NO OLVIDE QUE LAS SUBCONSULTAS LUEGO DE UN OPERADOR DE COMPARACIÓN (QUE NO ES SEGUIDO

POR "ANY" O "ALL") NO PUEDEN INCLUIR CLÁUSULAS "GROUP BY".

93 - SUBCONSULTAS CON IN

VIMOS QUE UNA SUBCONSULTA PUEDE REEMPLAZAR UNA EXPRESIÓN. DICHA SUBCONSULTA DEBE

DEVOLVER UN VALOR ESCALAR O UNA LISTA DE VALORES DE UN CAMPO; LAS SUBCONSULTAS QUE

RETORNAN UNA LISTA DE VALORES REEMPLAZAN A UNA EXPRESIÓN EN UNA CLÁUSULA "WHERE" QUE

CONTIENE LA PALABRA CLAVE "IN".

EL RESULTADO DE UNA SUBCONSULTA CON "IN" (O "NOT IN") ES UNA LISTA. LUEGO QUE LA

SUBCONSULTA RETORNA RESULTADOS, LA CONSULTA EXTERIOR LOS USA.

LA SINTAXIS BÁSICA ES LA SIGUIENTE:

...WHERE EXPRESION IN (SUBCONSULTA);

ESTE EJEMPLO MUESTRA LOS NOMBRES DE LAS EDITORIALES QUE HA PUBLICADO LIBROS DE UN

DETERMINADO AUTOR:

SELECT NOMBRE

Page 99: Base de Datos SQL

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 COMBINACIÓN (JOIN) SIEMPRE PUEDE SER EXPRESADA COMO UNA SUBCONSULTA; PERO UNA

SUBCONSULTA NO SIEMPRE PUEDE REEMPLAZARSE POR UNA COMBINACIÓN QUE RETORNE EL MISMO

RESULTADO. SI ES POSIBLE, ES ACONSEJABLE EMPLEAR COMBINACIONES EN LUGAR DE SUBCONSULTAS,

SON MÁS EFICIENTES.

SE RECOMIENDA PROBAR LAS SUBCONSULTAS ANTES DE INCLUIRLAS EN UNA CONSULTA EXTERIOR, ASÍ

PUEDE VERIFICAR QUE RETORNA LO NECESARIO, PORQUE A VECES RESULTA DIFÍCIL VERLO EN

CONSULTAS ANIDADAS.

TAMBIÉN PODEMOS BUSCAR VALORES NO COINCIDENTES CON UNA LISTA DE VALORES QUE RETORNA

UNA SUBCONSULTA; POR EJEMPLO, LAS EDITORIALES QUE NO HAN PUBLICADO LIBROS DE UN AUTOR

ESPECÍFICO:

SELECT NOMBRE

FROM EDITORIALES

WHERE CODIGO NOT IN

(SELECT CODIGOEDITORIAL

FROM LIBROS

WHERE AUTOR='RICHARD BACH');

94 - SUBCONSULTAS ANY - SOME - ALL

"ANY" Y "SOME" SON SINÓNIMOS. CHEQUEAN SI ALGUNA FILA DE LA LISTA RESULTADO DE UNA

SUBCONSULTA SE ENCUENTRA EL VALOR ESPECIFICADO EN LA CONDICIÓN.

COMPARA UN VALOR ESCALAR CON LOS VALORES DE UN CAMPO Y DEVUELVEN "TRUE" SI LA

COMPARACIÓN CON CADA VALOR DE LA LISTA DE LA SUBCONSULTA ES VERDADERA, SINO "FALSE".

EL TIPO DE DATOS QUE SE COMPARAN DEBEN SER COMPATIBLES.

LA SINTAXIS BÁSICA ES:

...VALORESCALAR OPERADORDECOMPARACION

ANY (SUBCONSULTA);

Page 100: Base de Datos SQL

QUEREMOS SABER LOS TÍTULOS DE LOS LIBROS DE "BORGES" QUE PERTENECEN A EDITORIALES QUE

HAN PUBLICADO TAMBIÉN LIBROS DE "RICHARD BACH", ES DECIR, SI LOS LIBROS DE "BORGES"

COINCIDEN CON ALGUNA DE LAS EDITORIALES QUE PUBLICÓ LIBROS DE "RICHARD BACH":

SELECT TITULO

FROM LIBROS

WHERE AUTOR='BORGES' AND

CODIGOEDITORIAL = ANY

(SELECT E.CODIGO

FROM EDITORIALES AS E

JOIN LIBROS AS L

ON CODIGOEDITORIAL=E.CODIGO

WHERE L.AUTOR='RICHARD BACH');

LA CONSULTA INTERNA (SUBCONSULTA) RETORNA UNA LISTA DE VALORES DE UN SOLO CAMPO (PUEDE

EJECUTAR LA SUBCONSULTA COMO UNA CONSULTA PARA PROBARLA), LUEGO, LA CONSULTA EXTERNA

COMPARA CADA VALOR DE "CODIGOEDITORIAL" CON CADA VALOR DE LA LISTA DEVOLVIENDO LOS

TÍTULOS DE "BORGES" QUE COINCIDEN.

"ALL" TAMBIÉN COMPARA UN VALOR ESCALAR CON UNA SERIE DE VALORES. CHEQUEA SI TODOS LOS

VALORES DE LA LISTA DE LA CONSULTA EXTERNA SE ENCUENTRAN EN LA LISTA DE VALORES DEVUELTA

POR LA CONSULTA INTERNA.

SINTAXIS:

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 TÍTULOS.

VEAMOS OTRO EJEMPLO CON UN OPERADOR DE COMPARACIÓN DIFERENTE:

QUEREMOS SABER SI ALGUN PRECIO DE LOS LIBROS DE "BORGES" ES MAYOR A ALGUN PRECIO DE

LOS LIBROS DE "RICHARD BACH":

SELECT TITULO,PRECIO

FROM LIBROS

WHERE AUTOR='BORGES' AND

PRECIO > ANY

(SELECT PRECIO

FROM LIBROS

WHERE AUTOR='BACH');

Page 101: Base de Datos SQL

EL PRECIO DE CADA LIBRO DE "BORGES" ES COMPARADO CON CADA VALOR DE LA LISTA DE VALORES

RETORNADA POR LA SUBCONSULTA; SI ALGUNO CUMPLE LA CONDICIÓN, ES DECIR, ES MAYOR A

ALGUN PRECIO DE "RICHARD BACH", SE LISTA.

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 CONDICIÓN, 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 COMPARACIÓN AL CUAL ES

SEGUIDO POR "ANY" O "ALL") PUEDEN INCLUIR CLÁUSULAS "GROUP BY".

95 - SUBCONSULTAS CORRELACIONADAS

UN ALMACÉN ALMACENA LA INFORMACIÓN DE SUS VENTAS EN UNA TABLA LLAMADA "FACTURAS" EN LA

CUAL GUARDA EL NÚMERO DE FACTURA, LA FECHA Y EL NOMBRE DEL CLIENTE Y UNA TABLA

DENOMINADA "DETALLES" EN LA CUAL SE ALMACENAN LOS DISTINTOS ITEMS CORRESPONDIENTES A

CADA FACTURA: EL NOMBRE DEL ARTÍCULO, EL PRECIO (UNITARIO) Y LA CANTIDAD.

SE NECESITA UNA LISTA DE TODAS LAS FACTURAS QUE INCLUYA EL NÚMERO, LA FECHA, EL CLIENTE, LA

CANTIDAD DE ARTÍCULOS COMPRADOS Y EL TOTAL:

SELECT F.*,

(SELECT COUNT(D.NUMEROITEM)

FROM DETALLES AS D

WHERE F.NUMERO=D.NUMEROFACTURA) AS CANTIDAD,

(SELECT SUM(D.PRECIOUNITARIO*CANTIDAD)

FROM DETALLES AS D

WHERE F.NUMERO=D.NUMEROFACTURA) AS TOTAL

FROM FACTURAS AS F;

EL SEGUNDO "SELECT" RETORNA UNA LISTA DE VALORES DE UNA SOLA COLUMNA CON LA CANTIDAD DE

ITEMS POR FACTURA (EL NÚMERO DE FACTURA LO TOMA DEL "SELECT" EXTERIOR); EL TERCER

"SELECT" RETORNA UNA LISTA DE VALORES DE UNA SOLA COLUMNA CON EL TOTAL POR FACTURA (EL

NÚMERO DE FACTURA LO TOMA DEL "SELECT" EXTERIOR); EL PRIMER "SELECT" (EXTERNO) DEVUELVE

TODOS LOS DATOS DE CADA FACTURA.

Page 102: Base de Datos SQL

A ESTE TIPO DE SUBCONSULTA SE LA DENOMINA CONSULTA CORRELACIONADA. LA CONSULTA INTERNA

SE EVALÚA TANTAS VECES COMO REGISTROS TIENE LA CONSULTA EXTERNA, SE REALIZA LA

SUBCONSULTA PARA CADA REGISTRO DE LA CONSULTA EXTERNA. EL CAMPO DE LA TABLA DENTRO DE LA

SUBCONSULTA (F.NUMERO) SE COMPARA CON EL CAMPO DE LA TABLA EXTERNA.

EN ESTE CASO, ESPECÍFICAMENTE, LA CONSULTA EXTERNA PASA UN VALOR DE "NUMERO" A LA

CONSULTA INTERNA. LA CONSULTA INTERNA TOMA ESE VALOR Y DETERMINA SI EXISTE EN "DETALLES",

SI EXISTE, LA CONSULTA INTERNA DEVUELVE LA SUMA. EL PROCESO SE REPITE PARA EL REGISTRO DE LA

CONSULTA EXTERNA, LA CONSULTA EXTERNA PASA OTRO "NUMERO" A LA CONSULTA INTERNA Y SQL

SERVER REPITE LA EVALUACIÓN.

96 - EXISTS Y NO EXISTS

LOS OPERADORES "EXISTS" Y "NOT EXISTS" SE EMPLEAN PARA DETERMINAR SI HAY O NO DATOS EN UNA

LISTA DE VALORES.

ESTOS OPERADORES PUEDEN EMPLEARSE CON SUBCONSULTAS CORRELACIONADAS PARA RESTRINGIR EL

RESULTADO DE UNA CONSULTA EXTERIOR A LOS REGISTROS QUE CUMPLEN LA SUBCONSULTA (CONSULTA

INTERIOR). ESTOS OPERADORES RETORNAN "TRUE" (SI LAS SUBCONSULTAS RETORNAN REGISTROS) O

"FALSE" (SI LAS SUBCONSULTAS NO RETORNAN REGISTROS).

CUANDO SE COLOCA EN UNA SUBCONSULTA EL OPERADOR "EXISTS", SQL SERVER ANALIZA SI HAY

DATOS QUE COINCIDEN CON LA SUBCONSULTA, NO SE DEVUELVE NINGÚN REGISTRO, ES COMO UN TEST DE

EXISTENCIA; SQL SERVER TERMINA LA RECUPERACIÓN DE REGISTROS CUANDO POR LO MENOS UN

REGISTRO CUMPLE LA CONDICIÓN "WHERE" DE LA SUBCONSULTA.

LA SINTAXIS BÁSICA ES LA SIGUIENTE:

... WHERE EXISTS (SUBCONSULTA);

EN ESTE EJEMPLO SE USA UNA SUBCONSULTA CORRELACIONADA CON UN OPERADOR "EXISTS" EN LA

CLÁUSULA "WHERE" PARA DEVOLVER UNA LISTA DE CLIENTES QUE COMPRARON EL ARTÍCULO "LAPIZ":

SELECT CLIENTE,NUMERO

FROM FACTURAS AS F

WHERE EXISTS

(SELECT *FROM DETALLES AS D

WHERE F.NUMERO=D.NUMEROFACTURA

AND D.ARTICULO='LAPIZ');

PUEDE OBTENER EL MISMO RESULTADO EMPLEANDO UNA COMBINACIÓN.

PODEMOS BUSCAR LOS CLIENTES QUE NO HAN ADQUIRIDO EL ARTÍCULO "LAPIZ" EMPLEANDO "IF NOT

EXISTS":

SELECT CLIENTE,NUMERO

FROM FACTURAS AS F

WHERE NOT EXISTS

(SELECT *FROM DETALLES AS D

WHERE F.NUMERO=D.NUMEROFACTURA

Page 103: Base de Datos SQL

AND D.ARTICULO='LAPIZ');

97 - SUBCONSULTA SIMIL AUTOCOMBINACIÓN

ALGUNAS SENTENCIAS EN LAS CUALES LA CONSULTA INTERNA Y LA EXTERNA EMPLEAN LA MISMA TABLA

PUEDEN REEMPLAZARSE POR UNA AUTOCOMBINACIÓN.

POR EJEMPLO, QUEREMOS UNA LISTA DE LOS LIBROS QUE HAN SIDO PUBLICADOS POR DISTINTAS

EDITORIALES.

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 EXPRESIÓN EN UNA CLÁUSULA "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 EVALÚA LA SUBCONSULTA, SI EL PRECIO ES MAYOR QUE EL PROMEDIO.

Page 104: Base de Datos SQL

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 CLÁUSULA "FROM" PARA QUE LA USE UN

"SELECT" EXTERNO.

LA TABLA DERIVADA DEBE IR ENTRE PARÉNTESIS Y TENER UN ALIAS PARA PODER REFERENCIARLA. LA

SINTAXIS BÁSICA ES LA SIGUIENTE:

SELECT ALIASDETABLADERIVADA.CAMPO

FROM (TABLADERIVADA) AS ALIAS;

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 NÚMERO DE

FACTURA Y EL MONTO TOTAL, Y DE LA TABLA "CLIENTES", EL NOMBRE DEL CLIENTE. NOTE QUE ESTE

"JOIN" NO EMPLEA 2 TABLAS, SINO UNA TABLA PROPIAMENTE DICHA Y UNA TABLA DERIVADA, QUE ES EN

REALIDAD UNA SUBCONSULTA.

99 - SUBCONSULTA (UPDATE - DELETE)

Page 105: Base de Datos SQL

DIJIMOS QUE PODEMOS EMPLEAR SUBCONSULTAS EN SENTENCIAS "INSERT", "UPDATE", "DELETE",

ADEMÁS DE "SELECT".

LA SINTAXIS BÁSICA PARA REALIZAR ACTUALIZACIONES CON SUBCONSULTA ES LA SIGUIENTE:

UPDATE TABLA SET CAMPO=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. TAMBIÉN PODEMOS HACERLO CON UN JOIN.

LA SINTAXIS BÁSICA 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 COMBINACIÓN QUE RETORNA UNA LISTA DE VALORES QUE LA CONSULTA

EXTERNA EMPLEA AL SELECCIONAR LOS REGISTROS PARA LA ELIMINACIÓN.

100 - SUBCONSULTA (INSERT)

APRENDIMOS QUE UNA SUBCONSULTA PUEDE ESTAR DENTRO DE UN "SELECT", "UPDATE" Y "DELETE";

TAMBIÉN PUEDE ESTAR DENTRO DE UN "INSERT".

PODEMOS INGRESAR REGISTROS EN UNA TABLA EMPLEANDO UN "SELECT".

LA SINTAXIS BÁSICA ES LA SIGUIENTE:

INSERT INTO TABLAENQUESEINGRESA (CAMPOSTABLA1)

SELECT (CAMPOSTABLACONSULTADA)

FROM TABLACONSULTADA;

Page 106: Base de Datos SQL

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

CARGARÁN (SI SE INGRESAN TODOS LOS CAMPOS NO ES NECESARIO LISTARLOS).

LA CANTIDAD DE COLUMNAS DEVUELTAS EN LA CONSULTA DEBE SER LA MISMA QUE LA CANTIDAD DE

CAMPOS A CARGAR EN EL "INSERT".

SE PUEDEN INSERTAR VALORES EN UNA TABLA CON EL RESULTADO DE UNA CONSULTA QUE INCLUYA

CUALQUIER TIPO DE "JOIN".

101 - CREAR TABLA A PARTIR DE OTRA (SELECT - INTO)

PODEMOS CREAR UNA TABLA E INSERTAR DATOS EN ELLA EN UNA SOLA SENTENCIA CONSULTANDO OTRA

TABLA (O VARIAS) CON ESTA SINTAXIS:

SELECT CAMPOSNUEVATABLA

INTO NUEVATABLA

FROM TABLA

WHERE CONDICION;

ES DECIR, SE CREA UNA NUEVA TABLA Y SE INSERTA EN ELLA EL RESULTADO DE UNA CONSULTA A OTRA

TABLA.

TENEMOS LA TABLA "LIBROS" DE UNA LIBRERÍA Y QUEREMOS CREAR UNA TABLA LLAMADA

"EDITORIALES" QUE CONTENGA LOS NOMBRES DE LAS EDITORIALES.

LA TABLA "EDITORIALES", QUE NO EXISTE, CONTENDRÁ SOLAMENTE UN CAMPO LLAMADO "NOMBRE".

LA TABLA LIBROS CONTIENE VARIOS REGISTROS.

PODEMOS CREAR LA TABLA "EDITORIALES" CON EL CAMPO "NOMBRE" CONSULTANDO LA TABLA

"LIBROS" Y EN EL MISMO MOMENTO INSERTAR LA INFORMACIÓN:

SELECT DISTINCT EDITORIAL AS NOMBRE

INTO EDITORIALES

FROM LIBROS;

LA TABLA "EDITORIALES" SE HA CREADO CON EL CAMPO "NOMBRE" SELECCIONADO DEL CAMPO

"EDITORIAL" DE "LIBROS".

Page 107: Base de Datos SQL

LOS CAMPOS DE LA NUEVA TABLA TIENEN EL MISMO NOMBRE, TIPO DE DATO Y VALORES ALMACENADOS

QUE LOS CAMPOS LISTADOS DE LA TABLA CONSULTADA; SI SE QUIERE DAR OTRO NOMBRE A LOS CAMPOS

DE LA NUEVA TABLA SE DEBEN ESPECIFICAR ALIAS.

ENTONCES, LUEGO DE LA LISTA DE SELECCIÓN DE CAMPOS DE LA TABLA A CONSULTAR, SE COLOCA

"INTO" SEGUIDO DEL NOMBRE DE LA NUEVA TABLA Y SE SIGUE CON LA CONSULTA.

PODEMOS EMPLEAR "GROUP BY", FUNCIONES DE AGRUPAMIENTO Y "ORDER BY" EN LAS CONSULTAS.

TAMBIÉN PODEMOS EMPLEAR "SELECT... INTO" CON COMBINACIONES, PARA CREAR UNA TABLA QUE

CONTENGA DATOS DE 2 O MÁS TABLAS.

102 - go

Esto solo se aplica cuando instale el SQL Server en su máquina.

"go" es un signo de finalización de un lote de sentencias. No es una sentencia, es un comando. El lote de

sentencias está compuesto por todas las sentencias antes de "go" o todas las sentencias entre dos "go".

Las sentencias no deben ocupar la misma linea en la que está "go".

Habrá notado que no se puede ejecutar un procedimiento almacenado luego de otras sentencias a menos que se

incluya "execute" (o "exec").

Por ejemplo, si tipeamos:

select *from empleados;

sp_helpconstraint empleados;

muestra un mensaje de error porque no puede procesar ambas sentencias como un solo lote. Para que no ocurra

debemos tipear:

select *from empleados;

exec sp_helpconstraint empleados;

o separar los lotes con "go":

select *from empleados;

go

sp_helpconstraint empleados;

Las siguientes sentencias no pueden ejecutarse en el mismo lote: create rule, create default,create view, create

procedure, create trigger. Cada una de ellas necesita ejecutarse separándolas con "go". Por ejemplo:

create table....

go

create rule...

go

Recuerde que si coloca "go" no debe incluir el "punto y coma" (;) al finalizar una instrucción.

Page 108: Base de Datos SQL

No está de más recordar que esto solo se aplica cuando instale el SQL Server en su máquina y ejecute los

comandos desde el Query Analyzer.

103 - Vistas

Una vista es una alternativa para mostrar datos de varias tablas. Una vista es como una tabla virtual que

almacena una consulta. Los datos accesibles a través de la vista no están almacenados en la base de datos como

un objeto.

Entonces, una vista almacena una consulta como un objeto para utilizarse posteriormente. Las tablas

consultadas en una vista se llaman tablas base. En general, se puede dar un nombre a cualquier consulta y

almacenarla como una vista.

Una vista suele llamarse también tabla virtual porque los resultados que retorna y la manera de referenciarlas es

la misma que para una tabla.

Las vistas permiten:

- ocultar información: permitiendo el acceso a algunos datos y manteniendo oculto el resto de la información

que no se incluye en la vista. El usuario opera con los datos de una vista como si se tratara de una tabla,

pudiendo modificar tales datos.

- simplificar la administración de los permisos de usuario: se pueden dar al usuario permisos para que solamente

pueda acceder a los datos a través de vistas, en lugar de concederle permisos para acceder a ciertos campos, así

se protegen las tablas base de cambios en su estructura.

- mejorar el rendimiento: se puede evitar tipear instrucciones repetidamente almacenando en una vista el

resultado de una consulta compleja que incluya información de varias tablas.

Podemos crear vistas con: un subconjunto de registros y campos de una tabla; una unión de varias tablas; una

combinación de varias tablas; un resumen estadístico de una tabla; un subconjunto de otra vista, combinación de

vistas y tablas.

Una vista se define usando un "select".

La sintaxis básica parcial para crear una vista es la siguiente:

create view NOMBREVISTA as

SENTENCIASSELECT

from TABLA;

El contenido de una vista se muestra con un "select":

select *from NOMBREVISTA;

En el siguiente ejemplo creamos la vista "vista_empleados", que es resultado de una combinación en la cual se

muestran 4 campos:

create view vista_empleados as

Page 109: Base de Datos SQL

select (apellido+' '+e.nombre) as nombre,sexo,

s.nombre as seccion, cantidadhijos

from empleados as e

join secciones as s

on codigo=seccion

Para ver la información contenida en la vista creada anteriormente tipeamos:

select *from vista_empleados;

Podemos realizar consultas a una vista como si se tratara de una tabla:

select seccion,count(*) as cantidad

from vista_empleados;

Los nombres para vistas deben seguir las mismas reglas que cualquier identificador. Para distinguir una tabla de

una vista podemos fijar una convención para darle nombres, por ejemplo, colocar el sufijo “vista” y luego el

nombre de las tablas consultadas en ellas.

Los campos y expresiones de la consulta que define una vista DEBEN tener un nombre. Se debe colocar

nombre de campo cuando es un campo calculado o si hay 2 campos con el mismo nombre. Note que en el

ejemplo, al concatenar los campos "apellido" y "nombre" colocamos un alias; si no lo hubiésemos hecho

aparecería un mensaje de error porque dicha expresión DEBE tener un encabezado, SQL Server no lo coloca

por defecto.

Los nombres de los campos y expresiones de la consulta que define una vista DEBEN ser únicos (no puede

haber dos campos o encabezados con igual nombre). Note que en la vista definida en el ejemplo, al campo

"s.nombre" le colocamos un alias porque ya había un encabezado (el alias de la concatenación) llamado

"nombre" y no pueden repetirse, si sucediera, aparecería un mensaje de error.

Otra sintaxis es la siguiente:

create view NOMBREVISTA (NOMBRESDEENCABEZADOS)

as

SENTENCIASSELECT

from TABLA;

Creamos otra vista de "empleados" denominada "vista_empleados_ingreso" que almacena la cantidad de

empleados por año:

create view vista_empleados_ingreso (fecha,cantidad)

as

select datepart(year,fechaingreso),count(*)

from empleados

group by datepart(year,fechaingreso)

La diferencia es que se colocan entre paréntesis los encabezados de las columnas que aparecerán en la vista. Si

no los colocamos y empleamos la sintaxis vista anteriormente, se emplean los nombres de los campos o alias

(que en este caso habría que agregar) colocados en el "select" que define la vista. Los nombres que se colocan

entre paréntesis deben ser tantos como los campos o expresiones que se definen en la vista.

Las vistas se crean en la base de datos activa.

Al crear una vista, SQL Server verifica que existan las tablas a las que se hacen referencia en ella.

Page 110: Base de Datos SQL

Se aconseja probar la sentencia "select" con la cual definiremos la vista antes de crearla para asegurarnos que el

resultado que retorna es el imaginado.

Existen algunas restricciones para el uso de "create view", a saber:

- no puede incluir las cláusulas "compute" ni "compute by" ni la palabra clave "into";

- no se pueden crear vistas temporales ni crear vistas sobre tablas temporales.

- no se pueden asociar reglas ni valores por defecto a las vistas.

- no puede combinarse con otras instrucciones en un mismo lote.

Se pueden construir vistas sobre otras vistas.

104 - Vistas (información)

Las vistas son objetos, así que para obtener información de ellos pueden usarse los siguientes procedimientos

almacenados del sistema:

"sp_help" sin parámetros nos muestra todos los objetos de la base de datos seleccionada, incluidas las vistas. En

la columna "Object_type" aparece "view" si es una vista. Si le enviamos como argumento el nombre de una

vista, obtenemos la fecha de creación, propietario, los campos y demás información.

"sp_helptext" seguido del nombre de una vista nos muestra el texto que la define, excepto si ha sido encriptado.

Ejecutando "sp_depends" seguido del nombre de un objeto, obtenemos 2 resultados:

- nombre, tipo, campos, etc. de los objetos de los cuales depende el objeto nombrado y

- nombre y tipo de los objetos que dependen del objeto nombrado.

Si ejecutamos el procedimiento "sp_depends" seguido del nombre de una vista:

sp_depends vista_empleados;

aparecen las tablas (y demás objetos) de las cuales depende la vista, es decir, las tablas referenciadas en la

misma.

Si ejecutamos el procedimiento seguido del nombre de una tabla:

sp_depends empleados;

aparecen los objetos que dependen de la tabla, vistas, restricciones, etc.

También se puede consultar la tabla del sistema "sysobjects":

select *from sysobjects;

Page 111: Base de Datos SQL

Nos muestra nombre y varios datos de todos los objetos de la base de datos actual. La columna "xtype" indica el

tipo de objeto, si es una vista, aparece 'V'.

Si queremos ver todas las vistas creadas por nosotros, podemos tipear:

select *from sysobjects

where xtype='V' and-- tipo vista

name like 'vista%';--búsqueda con comodín

105 - vistas (encriptar)

Podemos ver el texto que define una vista ejecutando el procedimiento almacenado del sistema "sp_helptext"

seguido del nombre de la vista:

sp_helptext NOMBREVISTA;

Podemos ocultar el texto que define una vista empleando la siguiente sintaxis al crearla:

create view NOMBREVISTA

with encryption

as

SENTENCIASSELECT

from TABLA;

"with encryption" indica a SQL Server que codifique las sentencias que definen la vista.

Creamos una vista con su definición oculta:

create view vista_empleados

with encryption

as

select (apellido+' '+e.nombre) as nombre,sexo,

s.nombre as seccion, cantidadhijos

from empleados as e

join secciones as s

on codigo=seccion

Si ejecutamos el procedimiento almacenado del sistema "sp_helptext" seguido del nombre de una vista

encriptada, aparece un mensaje indicando tal situación y el texto no se muestra.

106 - Vistas (eliminar)

Para quitar una vista se emplea "drop view":

drop view NOMBREVISTA;

Page 112: Base de Datos SQL

Si se elimina una tabla a la que hace referencia una vista, la vista no se elimina, hay que eliminarla

explícitamente.

Solo el propietario puede eliminar una vista.

Antes de eliminar un objeto, se recomienda ejecutar el procedimiento almacenado de sistema "sp_depends" para

averiguar si hay objetos que hagan referencia a él.

Eliminamos la vista denominada "vista_empleados":

drop view vista_empleados;

107 - Vistas (with check option)

Es posible obligar a todas las instrucciones de modificación de datos que se ejecutan en una vista a cumplir

ciertos criterios.

Por ejemplo, creamos la siguiente vista:

create view vista_empleados

as

select apellido, e.nombre, sexo, s.nombre as seccion

from empleados as e

join secciones as s

on seccion=codigo

where s.nombre='Administracion'

with check option;

La vista definida anteriormente muestra solamente algunos de los datos de los empleados de la sección

"Administracion". Además, solamente se permiten modificaciones a los empleados de esa sección.

Podemos actualizar el nombre, apellido y sexo a través de la vista, pero no el campo "seccion" porque está

restringuido.

108 - Vistas (modificar datos de una tabla a través

de vistas)

Si se modifican los datos de una vista, se modifica la tabla base.

Se puede insertar, actualizar o eliminar datos de una tabla a través de una vista, teniendo en cuenta lo siguiente,

las modificaciones que se realizan a las vistas:

Page 113: Base de Datos SQL

- no pueden afectar a más de una tabla consultada. Pueden modificarse datos de una vista que combina varias

tablas pero la modificación solamente debe afectar a una sola tabla.

- no se pueden cambiar los campos resultado de un cálculo.

- pueden generar errores si afectan a campos a las que la vista no hace referencia. Por ejemplo, si se ingresa un

registro en una vista que consulta una tabla que tiene campos not null que no están incluidos en la vista.

- la opción "with check option" obliga a todas las instrucciones de modificación que se ejecutan en la vista a

cumplir ciertos criterios que se especifican al definir la vista.

- para eliminar datos de una vista solamente UNA tabla puede ser listada en el "from" de la definicion de la

misma.

109 - Vistas modificar (alter view)

Para modificar una vista puede eliminarla y volver a crearla o emplear "alter view".

Con "alter view" se modifica la definición de una vista sin afectar los procedimientos almacenados y los

permisos. Si elimina una vista y vuelve a crearla, debe reasignar los permisos asociados a ella.

Sintaxis básica para alterar una vista:

alter view NOMBREVISTA

with encryption--opcional

as SELECT

En el ejemplo siguiente se altera vista_empleados para agregar el campo "domicilio":

alter view vista_empleados

with encryption

as

select (apellido+' '+e.nombre) as nombre,sexo,

s.nombre as seccion, cantidadhijos,domicilio

from empleados as e

join secciones as s

on codigo=seccion

Si creó la vista con "with encryption" y quiere modificarla manteniendo la encriptación, debe colocarla

nuevamente, en caso de no hacerlo, desaparece.

Si crea una vista con "select *" y luego agrega campos a la estructura de las tablas involucradas, los nuevos

campos no aparecerán en la vista; esto es porque los campos se seleccionan al ejecutar "create view"; debe

alterar la vista.

110 - Lenguaje de control de flujo (case)

Page 114: Base de Datos SQL

La función "case" compara 2 o más valores y devuelve un resultado.

La sintaxis es la siguiente:

case VALORACOMPARAR

when VALOR1 then RESULTADO1

when VALOR2 then RESULTADO2

...

else RESULTADO3

end

Por cada valor hay un "when" y un "then"; si encuentra un valor coincidente en algún "where" ejecuta el "then"

correspondiente a ese "where", si no encuentra ninguna coincidencia, se ejecuta el "else"; si no hay parte "else"

retorna "null". Finalmente se coloca "end" para indicar que el "case" ha finalizado.

Un profesor guarda las notas de sus alumnos de un curso en una tabla llamada "alumnos" que consta de los

siguientes campos:

- nombre (30 caracteres),

- nota (valor entero entre 0 y 10, puede ser nulo).

Queremos mostrar los nombres, notas de los alumnos y en una columna extra llamada "resultado" empleamos

un case que testee la nota y muestre un mensaje diferente si en dicho campo hay un valor:

- 0, 1, 2 ó 3: 'libre';

- 4, 5 ó 6: 'regular';

- 7, 8, 9 ó 10: 'promocionado';

Esta es la sentencia:

select nombre,nota, resultado=

case nota

when 0 then 'libre'

when 1 then 'libre'

when 2 then 'libre'

when 3 then 'libre'

when 4 then 'regular'

when 5 then 'regular'

when 6 then 'regular'

when 7 then 'promocionado'

when 8 then 'promocionado'

when 9 then 'promocionado'

when 10 then 'promocionado'

end

from alumnos;

Note que cada "where" compara un valor puntual, por ello los valores devueltos son iguales para algunos casos.

Note que como omitimos la parte "else", en caso que el valor no encuentre coincidencia con ninguno valor

"when", retorna "null".

Podemos realizar comparaciones en cada "where". La sintaxis es la siguiente:

case

when VALORACOMPARAR OPERADOR VALOR1 then RESULTADO1

when VALORACOMPARAR OPERADOR VALOR2 then RESULTADO2

...

else RESULTADO3

end

Page 115: Base de Datos SQL

Mostramos los nombres de los alumnos y en una columna extra llamada "resultado" empleamos un case que

teste si la nota es menor a 4, está entre 4 y 7 o supera el 7:

select nombre, nota, condicion=

case

when nota<4 then 'libre'

when nota >=4 and nota<7 then 'regular'

when nota>=7 then 'promocionado'

else 'sin nota'

end

from alumnos;

Puede utilizar una expresión "case" en cualquier lugar en el que pueda utilizar una expresión.

También se puede emplear con "group by" y funciones de agrupamiento.

111 - Lenguaje de control de flujo (if)

Existen palabras especiales que pertenecen al lenguaje de control de flujo que controlan la ejecución de las

sentencias, los bloques de sentencias y procedimientos almacenados.

Tales palabras son: begin... end, goto, if... else, return, waitfor, while, break y continue.

- "begin... end" encierran un bloque de sentencias para que sean tratados como unidad.

- "if... else": testean una condición; se emplean cuando un bloque de sentencias debe ser ejecutado si una

condición se cumple y si no se cumple, se debe ejecutar otro bloque de sentencias diferente.

- "while": ejecuta repetidamente una instrucción siempre que la condición sea verdadera.

- "break" y "continue": controlan la operación de las instrucciones incluidas en el bucle "while".

Veamos un ejemplo. Tenemos nuestra tabla "libros"; queremos mostrar todos los títulos de los cuales no hay

libros disponibles (cantidad=0), si no hay, mostrar un mensaje indicando tal situación:

if exists (select *from libros where cantidad=0)

(select titulo from libros where cantidad=0)

else

select 'No hay libros sin stock';

SQL Server ejecuta la sentencia (en este caso, una subconsulta) luego del "if" si la condición es verdadera; si es

falsa, ejecuta la sentencia del "else" (si existe).

Podemos emplear "if...else" en actualizaciones. Por ejemplo, queremos hacer un descuento en el precio, del

10% a todos los libros de una determinada editorial; si no hay, mostrar un mensaje:

if exists (select *from libros where editorial='Emece')

begin

update libros set precio=precio-(precio*0.1) where editorial='Emece'

select 'libros actualizados'

end

Page 116: Base de Datos SQL

else

select 'no hay registros actualizados';

Note que si la condición es verdadera, se deben ejecutar 2 sentencias. Por lo tanto, se deben encerrar en un

bloque "begin...end".

En el siguiente ejemplo eliminamos los libros cuya cantidad es cero; si no hay, mostramos un mensaje:

if exists (select *from libros where cantidad=0)

delete from libros where cantidad=0

else

select 'No hay registros eliminados;

112 - Variables de usuario

Las variables nos permiten almacenar un valor y recuperarlo más adelante para emplearlos en otras sentencias.

Las variables de usuario son específicas de cada conexión y son liberadas automáticamente al abandonar la

conexión.

Las variables de usuario comienzan con "@" (arroba) seguido del nombre (sin espacios), dicho nombre puede

contener cualquier caracter.

Una variable debe ser declarada antes de usarse. Una variable local se declara así:

declare @NOMBREVARIABLE TIPO

colocando "declare" el nombre de la variable que comienza con el símbolo arroba (@) y el tipo de dato.

Ejemplo:

declare @nombre varchar(20)

Puede declarar varias variables en una misma sentencia:

declare @nombre varchar(20), @edad int

No existen variables globales en SQL Server.

Una variable declarada existe dentro del entorno en que se declara; debemos declarar y emplear la variable en el

mismo lote de sentencias, porque si declaramos una variable y luego, en otro bloque de sentencias pretendemos

emplearla, dicha variable ya no existe. Por ejemplo, si ejecutamos estas sentencias en diferentes lotes:

declare @variable varchar(10); select @variable;

aparece un mensaje indicando que la variable "@variable" debe ser declarada.

Debemos tipear:

declare @variable varchar(10)

select @variable;

Page 117: Base de Datos SQL

Disponemos punto y coma solo al final de la última instrucción del lote.

Una variable a la cual no se le ha asignado un valor contiene "null".

Se le asigna un valor inicial con "set":

set @edad=45

Para almacenar un valor en una variable se coloca el signo igual (=) entre la variable y el valor a asignar.

Si le asignamos un valor resultado de una consulta, la sintaxis es:

select @nombre = autor from libros where titulo='Uno'

Podemos ver el contenido de una variable con:

select @nombre;

Una variable puede tener comodines:

declare @patron varchar(30)

set @patron='B%'

select autor

from libros

where autor like @patron;

La utilidad de las variables consiste en que almacenan valores para utilizarlos en otras consultas.

Por ejemplo, queremos saber todos los datos del libro con mayor precio de la tabla "libros" de una librería. Para

ello podemos emplear una variable para almacenar el precio más alto:

declare @mayorprecio

select @mayorprecio:=max(precio) from libros

y luego mostrar todos los datos de dicho libro empleando la variable anterior:

select *from libros

where precio=@mayorprecio;

Es decir, declaramos la variable y guardamos en ella el precio más alto y luego, en otra sentencia, mostramos

los datos de todos los libros cuyo precio es igual al valor de la variable.

Una variable puede ser definida con cualquier tipo de dato, excepto text, ntext e image; incluso de un tipo de

dato definido por el usuario.

113 - Tipos de datos text, ntext y image

Los tipos de datos "ntext", "text" e "image" representan tipos de datos de longitud fija y variable en los que se

pueden guardar gran cantidad de información, caracteres unicode y no unicode y datos binarios.

Page 118: Base de Datos SQL

"ntext" almacena datos unicode de longitud variable y el máximo es de aproximadamente 1000000000

caracteres, en bytes, el tamaño es el doble de los caracteres ingresados (2 GB).

"text" almacena datos binarios no unicode de longitud variable, el máximo es de 2000000000 caracteres aprox.

(2 GB). No puede emplearse en parámetros de procedimientos almacenados.

"image" es un tipo de dato de longitud variable que puede contener de 0 a 2000000000 bytes (2 GB) aprox. de

datos binarios. Se emplea para almacenar gran cantidad de información o gráficos.

Se emplean estos tipos de datos para almacenar valores superiores a 8000 caracteres.

Ninguno de estos tipos de datos admiten argumento para especificar su longitud, como en el caso de los tipos

"char", o "varchar".

Como estos tipos de datos tiene gran tamaño, SQL Server los almacena fuera de los registros, en su lugar

guarda un puntero (de 16 bytes) que apunta a otro sitio que contiene los datos.

Para declarar un campo de alguno de estos tipos de datos, colocamos el nombre del campo seguido del tipo de

dato:

...

NOMBRECAMPO text

....

Otras consideraciones importantes:

- No pueden definirse variables de estos tipos de datos.

- Los campos de estos tipos de datos no pueden emplearse para índices.

- La única restricción que puede aplicar a estos tipos de datos es "default".

- Se pueden asociar valores predeterminados pero no reglas a campos de estos tipos de datos.

- No pueden alterarse campos de estos tipos con "alter table".

114 - Tipo de dato text - ntext e image (punteros)

Explicamos anteriormente que como estos tipos de datos tiene gran tamaño, SQL Server almacena los datos

fuera de los registros; en el registro guarda un puntero (de 16 bytes) que apunta a otro sitio, que contiene la

dirección en la cual se guardan los datos propiamente dichos.

La función "textptr" devuelve el valor del puntero a texto que corresponde al campo text, ntext o image; tal

valor puede emplearse para manipular los datos de este tipo, con las funciones para leer, escribir y actualizar.

Sintaxis:

textptr(CAMPO);

El campo debe ser tipo text, ntext o image.

Page 119: Base de Datos SQL

En el campo de tipo "text" no se almacenan los datos sino la dirección en la cual se encuentran los datos.

Podemos ver esa dirección tipeando la siguiente sentencia:

select titulo, textptr(sinopsis) from libros;

La función "textptr" retorna un puntero a texto (valor binario de 16). Si el campo no tiene texto, retorna un

puntero a null; por ello se debe usar la función "textvalid" para confirmar si el puntero a texto existe.

Si la consulta retorna más de un registro, "textptr" retorna un puntero a texto del último registro devuelto.

La funcion "textvalid" controla si un puntero a texto es válido. Sintaxis:

textvalid ('TABLA.CAMPO', PUNTEROATEXTO);

Los argumentos son: el nombre de la tabla y campo y el nombre del puntero a texto que se va a controlar.

Retorna 1 si el puntero es válido y 0 si no lo es. No se puede emplear "updatetext", "writetext" y "readtext" si el

puntero no es válido.

La siguiente consulta muestra si los punteros son válidos en cada registro del campo "sinopsis" de la tabla

"libros":

select titulo,

textvalid('libros.sinopsis', textptr(sinopsis)) as 'Puntero valido'

from libros;

En el siguiente ejemplo, declaramos una variable de tipo "varbinary" a la cual le asignamos el valor del puntero

a texto de un registro y luego vemos si dicho puntero es válido, empleando la variable:

declare @puntero varbinary(16)

select @puntero = textptr(sinopsis)

from libros

where titulo= 'Ilusiones'

select textvalid('libros.sinopsis', @puntero);

Solo disponemos punto y coma al final para que SQL Server ejecute todas las instrucciones en un solo lote y

exista la variable @puntero.

Si al insertar registros se ingresa un valor "null" en un campo "text", "ntext" o "image" o no se ingresa valor, no

se crea un puntero válido. Para crear un puntero a texto válido ejecute un "insert" o "update" con datos que no

sean nulos para el campo text, ntext o image.

115 - Tipo de dato text - ntext e image (leer)

La función "readtext" lee valores de un campo text, ntext o image, comenzando desde una posición y leyendo

un específico número de bytes. Sintaxis:

readtext TABLA.CAMPO PUNTEROATEXTO

DESPLAZAMIENTO CANTIDAD;

Analicemos la sintaxis:

Page 120: Base de Datos SQL

- PUNTEROATEXTO: puntero a texto válido, binary(16).

- DESPLAZAMIENTO: número de bytes (para text o image) o caracteres (ntext) que se mueve el puntero antes

de comenzar a leer.

- CANTIDAD: número de bytes o caracteres a leer desde la posición indicada por DESPLAZAMIENTO. Si es

0, se leen 4KB bytes o hasta el final.

Leemos la información almacenada en el campo "sinopsis" de "libros" del registro con código 2, desde la

posición 9, 50 caracteres:

declare @puntero varbinary(16)

select @puntero=textptr(sinopsis)

from libros

where codigo=2

readtext libros.sinopsis @puntero 9 50;

Si al insertar registros se ingresa un valor "null" en un campo "text", "ntext" o "image" o no se ingresan datos,

no se crea un puntero válido y al intentar leer dicho campo ocurre un error, porque la función "readtext"

requiere un puntero válido. Para evitarlo podemos chequear el puntero antes de pasárselo a la función de

lectura:

declare @puntero varbinary(16)

select @puntero=textptr(sinopsis)

from libros where codigo=1

if (textvalid('libros.sinopsis', @puntero)=1)

readtext libros.sinopsis @puntero 9 50

else select 'puntero invalido';

116 - Tipo de dato text - ntext e image (escribir)

La función "writetext" sobreescribe (reemplaza) el texto de un campo "text", "ntext" o "image".

No puede emplearse en vistas.

Sintaxis:

writetext TABLA.CAMPO PUNTEROATEXTO

DATO;

Luego de "writetext" se coloca el nombre de la tabla y el campo (text, ntext o image) a actualizar.

"PUNTEROATEXTO" es el valor que almacena el puntero a texto del dato de tipo "text", "ntext" o "image", tal

puntero debe ser válido. "DATO" es el texto que almacena, puede ser una variable o un literal.

Este ejemplo coloca el puntero a texto en una variable "@puntero" y luego "writetext" almacena el nuevo texto

en el registro apuntado por "@puntero":

declare @puntero binary(16)

select @puntero = textptr (sinopsis)

from libros

where codigo=2

writetext libros.sinopsis @puntero 'Este es un nuevo libro acerca de PHP escrito por el

profesor

Page 121: Base de Datos SQL

Molina que aborda todos los temas necesarios para el aprendizaje desde cero de este

lenguaje.';

Recuerde que si al insertar registros se ingresa un valor "null" en un campo "text", "ntext" o "image" o no se

ingresan datos, no se crea un puntero válido y al intentar escribir dicho campo ocurre un error, porque la

función "writetext" requiere un puntero válido. Para evitarlo podemos chequer el puntero antes de pasárselo a la

función de escritura:

declare @puntero varbinary(16)

select @puntero=textptr(sinopsis)

from libros where codigo=1

if (textvalid('libros.sinopsis', @puntero)=1)

writetext libros.sinopsis @puntero 'Trata de una gaviota que vuela más alto que las

demas.'

else select 'puntero invalido, no se actualizó el registro';

117 - Tipo de dato text - ntext e image (actualizar)

Aprendimos que la función "writetext" sobreescribe, reemplaza el contenido completo de un campo de tipo

"text", "ntext" o "image".

Para actualizar campos de estos tipos también empleamos "updatetext", que permite cambiar una porción del

campo (o todo el campo). La sintaxis básica es la siguiente:

updatetext TABLA.CAMPO PUNTEROATEXTO

DESPLAZAMIENTODELPUNTERO

LONGITUDDEBORRADO

DATOAINSERTAR;

Analizamos la sintaxis:

- TABLA.CAMPO: campo y tabla que se va a actualizar.

- PUNTEROATEXTO: valor del puntero, retornado por la función "textptr", que apunta al dato text, ntext o

image que se quiere actualizar.

- DESPLAZAMIENTODELPUNTERO: indica la posición en que inserta el nuevo dato. Especifica la cantidad

de bytes (para campos text e image) o caracteres (para campos ntext) que debe moverse el puntero para insertar

el dato. Los valores pueden ser: 0 (el nuevo dato se inserta al comienzo), "null" (coloca el puntero al final), un

valor mayor a cero y menor o igual a la longitud total del texto (inserta el nuevo dato en la posición indicada) y

un valor mayor a la longitud total del campo (genera un mensaje de error).

Es importante recordar que cada caracter ntext ocupa 2 bytes.

- LONGITUDDEBORRADO: indica la cantidad de bytes (para text e image) o caracteres (para ntext) a borrar

comenzando de la posición indicada por el parámetro DESPLAZAMIENTODELPUNTERO. Si colocamos el

valor 0 (no se borra ningún dato), "null" (borra todos los datos desde la posición indicada por el parámetro

DESPLAZAMIENTODELPUNTERO hasta el final), un valor mayor que cero y menor o igual a la longitud del

texto (borra tal cantidad) y un valor inválido, es decir, mayor a la longitud del texto (genera un mensaje de

error).

Es importante recordar que cada caracter "ntext" ocupa 2 bytes.

Page 122: Base de Datos SQL

- DATOAINSERTAR: el dato que va a ser insertado en el campo. Puede ser char, nchar, varchar, nvarchar,

binary, varbinary, text, ntext, image, un literal o una variable. Si el dato es un campo text, ntext o image de otra

tabla, se debe indicar el nombre de la tabla junto con el campo y el valor del puntero que apunta al tipo de dato

text, ntext o image (retornado por la función "textptr"), de esta forma:

TABLA.CAMPO PUNTERO;

Tenemos la tabla libros, con un campo de tipo text llamado "sinopsis"; hay un registro cargado con el siguiente

texto: "Para aprender PHP a paso." Necesitamos agregar antes de "a paso" el texto "paso " para que el texto

completo sea "Para aprender PHP paso a paso", tipeamos:

declare @puntero binary(16)

select @puntero = textptr(sinopsis)

from libros

where titulo='Aprenda PHP'

updatetext libros.sinopsis @puntero

18 0 'paso ';

Entonces, declaramos una variable llamada "@puntero"; guardamos en la variable el valor del puntero, obtenido

con la función "textptr(sinopsis)", tal puntero apunta al campo "sinopsis" del libro "Aprenda PHP". Luego

actualizamos el campo, colocando el puntero en la posición 18, no borramos ningún byte y colocamos el texto a

agregar; el campo ahora contendrá "Para aprencer PHP paso a paso".

Es posible guardar en un campo "text" de una tabla el contenido del campo "text" de otra tabla; para ello

debemos utilizar 2 punteros, uno para obtener la dirección del campo que queremos actualizar y otro para

obtener la dirección del campo del cual extraemos la información.

En el siguiente ejemplo guardamos en una variable el valor del puntero a texto al campo "sinopsis" del libro

"Aprenda PHP" de la tabla "libros"; en otra variable guardamos el valor del puntero a texto al campo "sinopsis"

del libro con código 1 de la tabla "ofertas"; finalmente actualizamos el registro de "ofertas" con el texto de

"libros".

declare @puntero1 binary(16)

select @puntero1 = textptr(sinopsis)

from libros

where titulo='Aprenda PHP'

declare @puntero2 binary(16)

select @puntero2 = textptr(sinopsis)

from ofertas

where titulo='Aprenda PHP'

updatetext ofertas.sinopsis @puntero2 0 null

libros.sinopsis @puntero1;

Entonces, se emplea "updatetext" para modificar datos de campos de tipo text, ntext e image, pudiendo cambiar

una porción del texto.

118 - Tipo de dato text - ntext e image (funciones)

Las siguientes son otras funciones que pueden emplearse con estos tipos de datos:

Page 123: Base de Datos SQL

- datalenght(CAMPO): devuelve el número de bytes de un determinado campo. Retorna "null" si el campo es

nulo. Ejemplo:

select titulo, datalength(sinopsis) as longitud

from libros

order by titulo;

- patindex ('PATRON',CAMPO): retorna el comienzo de la primera ocurrencia de un patrón de la expresión

especificada, si el patrón no se encuentra, retorna cero. El patrón es una cadena que puede incluir comodines.

Ejemplo:

select patindex('%PHP%', sinopsis)

from libros;

Con este tipo de datos también puede utilizarse "like", pero "like" solamente puede incluirse en la cláusula

"where".

- substring (TEXTO,INICIO,LONGITUD): devuelve una parte del texto especificado como primer argumento,

empezando desde la posición especificada por el segundo argumento y de tantos caracteres de longitud como

indica el tercer argumento.

Ejemplo:

select titulo,substring(sinopsis,1,20)

from libros;

119 - Procedimientos almacenados

Vimos que SQL Server ofrece dos alternativas para asegurar la integridad de datos, la integridad:

1) DECLARATIVA, mediante el uso de restricciones (constraints), valores predeterminados (defaults) y reglas

(rules) y

2) PROCEDIMENTAL, mediante la implementación de procedimientos almacenados y desencadenadores

(triggers).

Nos detendremos ahora en procedimientos almacenados.

Un procedimiento almacenado es un conjunto de instrucciones a las que se les da un nombre, que se almacena

en el servidor. Permiten encapsular tareas repetitivas.

SQL Server permite los siguientes tipos de procedimientos almacenados:

1) del sistema: están almacenados en la base de datos "master" y llevan el prefijo "sp_"; permiten recuperar

información de las tablas del sistema y pueden ejecutarse en cualquier base de datos.

2) locales: los crea el usuario (próximo tema).

3) temporales: pueden ser locales, cuyos nombres comienzan con un signo numeral (#), o globales, cuyos

nombres comienzan con 2 signos numeral (##). Los procedimientos almacenados temporales locales están

Page 124: Base de Datos SQL

disponibles en la sesión de un solo usuario y se eliminan automáticamente al finalizar la sesión; los globales

están disponibles en las sesiones de todos los usuarios.

4) extendidos: se implementan como bibliotecas de vínculos dinámicos (DLL, Dynamic-Link Libraries), se

ejecutan fuera del entorno de SQL Server. Generalmente llevan el prefijo "xp_". No los estudiaremos.

Al crear un procedimiento almacenado, las instrucciones que contiene se analizan para verificar si son correctas

sintácticamente. Si no se detectan errores, SQL Server guarda el nombre del procedimiento almacenado en la

tabla del sistema "sysobjects" y su contenido en la tabla del sistema "syscomments" en la base de datos activa.

Si se encuentra algún error, no se crea.

Un procedimiento almacenados puede hacer referencia a objetos que no existen al momento de crearlo. Los

objetos deben existir cuando se ejecute el procedimiento almacenado.

Ventajas:

- comparten la lógica de la aplicación con las otras aplicaciones, con lo cual el acceso y las modificaciones de

los datos se hacen en un solo sitio.

- permiten realizar todas las operaciones que los usuarios necesitan evitando que tengan acceso directo a las

tablas.

- reducen el tráfico de red; en vez de enviar muchas instrucciones, los usuarios realizan operaciones enviando

una única instrucción, lo cual disminuye el número de solicitudes entre el cliente y el servidor.

120 - Procedimientos almacenados (crear - ejecutar)

Los procedimientos almacenados se crean en la base de datos seleccionada, excepto los procedimientos

almacenados temporales, que se crean en la base de datos "tempdb".

En primer lugar se deben tipear y probar las instrucciones que se incluyen en el procedimiento almacenado,

luego, si se obtiene el resultado esperado, se crea el procedimiento.

Los procedimientos almacenados pueden hacer referencia a tablas, vistas, a funciones definidas por el usuario, a

otros procedimientos almacenados y a tablas temporales.

Un procedimiento almacenado pueden incluir cualquier cantidad y tipo de instrucciones, excepto:

create default, create procedure, create rule, create trigger y create view.

Se pueden crear otros objetos (por ejemplo índices, tablas), en tal caso deben especificar el nombre del

propietario; se pueden realizar inserciones, actualizaciones, eliminaciones, etc.

Si un procedimiento almacenado crea una tabla temporal, dicha tabla sólo existe dentro del procedimiento y

desaparece al finalizar el mismo. Lo mismo sucede con las variables.

Hemos empleado varias veces procedimientos almacenados del sistema ("sp_help", "sp_helpconstraint", etc.),

ahora aprenderemos a crear nuestros propios procedimientos almacenados.

Page 125: Base de Datos SQL

Para crear un procedimiento almacenado empleamos la instrucción "create procedure".

La sintaxis básica parcial es:

create procedure NOMBREPROCEDIMIENTO

as INSTRUCCIONES;

Para diferenciar los procedimientos almacenados del sistema de los procedimientos almacenados locales use un

prefijo diferente a "sp_" cuando les de el nombre.

Con las siguientes instrucciones creamos un procedimiento almacenado llamado "pa_libros_limite_stock" que

muestra todos los libros de los cuales hay menos de 10 disponibles:

create proc pa_libros_limite_stock

as

select *from libros

where cantidad <=10;

Entonces, creamos un procedimiento almacenado colocando "create procedure" (o "create proc", que es la

forma abreviada), luego el nombre del procedimiento y seguido de "as" las sentencias que definen el

procedimiento.

"create procedure" debe ser la primera sentencia de un lote.

Para ejecutar el procedimiento almacenado creado anteriormente tipeamos:

exec pa_libros_limite_stock;

Entonces, para ejecutar un procedimiento almacenado colocamos "execute" (o "exec") seguido del nombre del

procedimiento.

Cuando realizamos un ejercicio nuevo, siempre realizamos las mismas tareas: eliminamos la tabla si existe, la

creamos y luego ingresamos algunos registros. Podemos crear un procedimiento almacenado que contenga

todas estas instrucciones:

create procedure pa_crear_libros

as

if object_id('libros')is not null

drop table libros;

create table libros(

codigo int identity,

titulo varchar(40),

autor varchar(30),

editorial varchar(20),

precio decimal(5,2),

primary key(codigo)

);

insert into libros values('Uno','Richard Bach','Planeta',15);

insert into libros values('Ilusiones','Richard Bach','Planeta',18);

insert into libros values('El aleph','Borges','Emece',25);

insert into libros values('Aprenda PHP','Mario Molina','Nuevo siglo',45);

insert into libros values('Matematica estas ahi','Paenza','Nuevo siglo',12);

insert into libros values('Java en 10 minutos','Mario Molina','Paidos',35);

Y luego lo ejecutamos cada vez que comenzamos un nuevo ejercicio y así evitamos tipear tantas sentencias:

Page 126: Base de Datos SQL

exec pa_crear_libros;

121 - Procedimientos almacenados (eliminar)

Los procedimientos almacenados se eliminan con "drop procedure". Sintaxis:

drop procedure NOMBREPROCEDIMIENTO;

Eliminamos el procedimiento almacenado llamado "pa_libros_autor":

drop procedure pa_libros_autor;

Si el procedimiento que queremos eliminar no existe, aparece un mensaje de error, para evitarlo, podemos

emplear esta sintaxis:

if object_id('NOMBREPROCEDIMIENTO') is not null

drop procedure NOMBREPROCEDIMIENTO;

Eliminamos, si existe, el procedimiento "pa_libros_autor", si no existe, mostramos un mensaje:

if object_id('pa_libros_autor') is not null

drop procedure pa_libros_autor

else

select 'No existe el procedimiento "pa_libros_autor"';

"drop procedure" puede abreviarse con "drop proc".

Se recomienda ejecutar el procedimiento almacenado del sistema "sp_depends" para ver si algún objeto

depende del procedimiento que deseamos eliminar.

Podemos eliminar una tabla de la cual dependa un procedimiento, SQL Server lo permite, pero luego, al

ejecutar el procedimiento, aparecerá un mensaje de error porque la tabla referenciada no existe.

122 - Procedimientos almacenados (parámetros de

entrada)

Los procedimientos almacenados pueden recibir y devolver información; para ello se emplean parámetros, de

entrada y salida, respectivamente.

Veamos los primeros. Los parámetros de entrada posibilitan pasar información a un procedimiento.

Para que un procedimiento almacenado admita parámetros de entrada se deben declarar variables como

parámetros al crearlo. La sintaxis es:

create proc NOMBREPROCEDIMIENTO

@NOMBREPARAMETRO TIPO =VALORPORDEFECTO

as SENTENCIAS;

Page 127: Base de Datos SQL

Los parámetros se definen luego del nombre del procedimiento, comenzando el nombre con un signo arroba

(@). Los parámetros son locales al procedimiento, es decir, existen solamente dentro del mismo. Pueden

declararse varios parámetros por procedimiento, se separan por comas.

Cuando el procedimiento es ejecutado, deben explicitarse valores para cada uno de los parámetros (en el orden

que fueron definidos), a menos que se haya definido un valor por defecto, en tal caso, pueden omitirse. Pueden

ser de cualquier tipo de dato (excepto cursor).

Luego de definir un parámetro y su tipo, opcionalmente, se puede especificar un valor por defecto; tal valor es

el que asume el procedimiento al ser ejecutado si no recibe parámetros. Si no se coloca valor por defecto, un

procedimiento definido con parámetros no puede ejecutarse sin valores para ellos. El valor por defecto puede

ser "null" o una constante, también puede incluir comodines si el procedimiento emplea "like".

Creamos un procedimiento que recibe el nombre de un autor como parámetro para mostrar todos los libros del

autor solicitado:

create procedure pa_libros_autor

@autor varchar(30)

as

select titulo, editorial,precio

from libros

where autor= @autor;

El procedimiento se ejecuta colocando "execute" (o "exec") seguido del nombre del procedimiento y un valor

para el parámetro:

exec pa_libros_autor 'Borges';

Creamos un procedimiento que recibe 2 parámetros, el nombre de un autor y el de una editorial:

create procedure pa_libros_autor_editorial

@autor varchar(30),

@editorial varchar(20)

as

select titulo, precio

from libros

where autor= @autor and

editorial=@editorial;

El procedimiento se ejecuta colocando "execute" (o "exec") seguido del nombre del procedimiento y los valores

para los parámetros separados por comas:

exec pa_libros_autor_editorial 'Richard Bach','Planeta';

Los valores de un parámetro pueden pasarse al procedimiento mediante el nombre del parámetro o por su

posición. La sintaxis anterior ejecuta el procedimiento pasando valores a los parámetros por posición. También

podemos emplear la otra sintaxis en la cual pasamos valores a los parámetros por su nombre:

exec pa_libros_autor_editorial @editorial='Planeta', @autor='Richard Bach';

Cuando pasamos valores con el nombre del parámetro, el orden en que se colocan puede alterarse.

No podríamos ejecutar el procedimiento anterior sin valores para los parámetros. Si queremos ejecutar un

procedimiento que permita omitir los valores para los parámetros debemos, al crear el procedimiento, definir

valores por defecto para cada parámetro:

Page 128: Base de Datos SQL

create procedure pa_libros_autor_editorial2

@autor varchar(30)='Richard Bach',

@editorial varchar(20)='Planeta'

as

select titulo, autor,editorial,precio

from libros

where autor= @autor and

editorial=@editorial;

Podemos ejecutar el procedimiento anterior sin enviarle valores, usará los predeterminados.

Si enviamos un solo parámetro a un procedimiento que tiene definido más de un parámetro sin especificar a qué

parámetro corresponde (valor por posición), asume que es el primero. Es decir, SQL Server asume que los

valores se dan en el orden que fueron definidos, no se puede interrumpir la secuencia.

Si queremos especificar solamente el segundo parámetro, debemos emplear la sintaxis de paso de valores a

parámetros por nombre:

exec pa_libros_autor_editorial2 @editorial='Paidos';

Podemos emplear patrones de búsqueda en la consulta que define el procedimiento almacenado y utilizar

comodines como valores por defecto:

create proc pa_libros_autor_editorial3

@autor varchar(30) = '%',

@editorial varchar(30) = '%'

as

select titulo,autor,editorial,precio

from libros

where autor like @autor and

editorial like @editorial;

La sentencia siguiente ejecuta el procedimiento almacenado "pa_libros_autor_editorial3" enviando un valor por

posición, se asume que es el primero.

exec pa_libros_autor_editorial3 'P%';

La sentencia siguiente ejecuta el procedimiento almacenado "pa_libros_autor_editorial3" enviando un valor

para el segundo parámetro, para el primer parámetro toma el valor por defecto:

exec pa_libros_autor_editorial3 @editorial='P%';

También podríamos haber tipeado:

exec pa_libros_autor_editorial3 default, 'P%';

123 - Procedimientos almacenados (parámetros de

salida)

Dijimos que los procedimientos almacenados pueden devolver información; para ello se emplean parámetros de

salida. El valor se retorna a quien realizó la llamada con parámetros de salida. Para que un procedimiento

Page 129: Base de Datos SQL

almacenado devuelva un valor se debe declarar una variable con la palabra clave "output" al crear el

procedimiento:

create procedure NOMBREPROCEDIMIENTO

@PARAMETROENTRADA TIPO =VALORPORDEFECTO,

@PARAMETROSALIDA TIPO=VALORPORDEFECTO output

as

SENTENCIAS

select @PARAMETROSALIDA=SENTENCIAS;

Los parámetros de salida pueden ser de cualquier tipo de datos, excepto text, ntext e image.

Creamos un procedimiento almacenado al cual le enviamos 2 números y retorna el promedio:

create procedure pa_promedio

@n1 decimal(4,2),

@n2 decimal(4,2),

@resultado decimal(4,2) output

as

select @resultado=(@n1+@n2)/2;

Al ejecutarlo también debe emplearse "output":

declare @variable decimal(4,2)

execute pa_promedio 5,6, @variable output

select @variable;

Declaramos una variable para guardar el valor devuelto por el procedimiento; ejecutamos el procedimiento

enviándole 2 valores y mostramos el resultado.

La instrucción que realiza la llamada al procedimiento debe contener un nombre de variable para almacenar el

valor retornado.

Creamos un procedimiento almacenado que muestre los títulos, editorial y precio de los libros de un

determinado autor (enviado como parámetro de entrada) y nos retorne la suma y el promedio de los precios de

todos los libros del autor enviado:

create procedure pa_autor_sumaypromedio

@autor varchar(30)='%',

@suma decimal(6,2) output,

@promedio decimal(6,2) output

as

select titulo,editorial,precio

from libros

where autor like @autor

select @suma=sum(precio)

from libros

where autor like @autor

select @promedio=avg(precio)

from libros

where autor like @autor;

Ejecutamos el procedimiento y vemos el contenido de las variables en las que almacenamos los parámetros de

salida del procedimiento:

declare @s decimal(6,2), @p decimal(6,2)

execute pa_autor_sumaypromedio 'Richard Bach', @s output, @p output

Page 130: Base de Datos SQL

select @s as total, @p as promedio;

124 - Procedimientos almacenados (return)

La instrucción "return" sale de una consulta o procedimiento y todas las instrucciones posteriores no son

ejecutadas.

Creamos un procedimiento que muestre todos los libros de un autor determinado que se ingresa como

parámetro. Si no se ingresa un valor, o se ingresa "null", se muestra un mensaje y se sale del procedimiento:

create procedure pa_libros_autor

@autor varchar(30)=null

as

if @autor is null

begin

select 'Debe indicar un autor'

return

end;

select titulo from libros where autor = @autor;

Si al ejecutar el procedimiento enviamos el valor "null" o no pasamos valor, con lo cual toma el valor por

defecto "null", se muestra un mensaje y se sale; en caso contrario, ejecuta la consulta luego del "else".

"return" puede retornar un valor entero.

Un procedimiento puede retornar un valor de estado para indicar si se ha ejecutado correctamente o no.

Creamos un procedimiento almacenado que ingresa registros en la tabla "libros". Los parámetros

correspondientes al título y autor DEBEN ingresarse con un valor distinto de "null", los demás son opcionales.

El procedimiento retorna "1" si la inserción se realiza, es decir, si se ingresan valores para título y autor y "0",

en caso que título o autor sean nulos:

create procedure pa_libros_ingreso

@titulo varchar(40)=null,

@autor varchar(30)=null,

@editorial varchar(20)=null,

@precio decimal(5,2)=null

as

if (@titulo is null) or (@autor is null)

return 0

else

begin

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

return 1

end;

Para ver el resultado, debemos declarar una variable en la cual se almacene el valor devuelto por el

procedimiento; luego, ejecutar el procedimiento asignándole el valor devuelto a la variable, finalmente

mostramos el contenido de la variable:

declare @retorno int

exec @retorno=pa_libros_ingreso 'Alicia en el pais...','Lewis Carroll'

select 'Ingreso realizado=1' = @retorno

exec @retorno=pa_libros_ingreso

Page 131: Base de Datos SQL

select 'Ingreso realizado=1' = @retorno;

También podríamos emplear un "if" para controlar el valor de la variable de retorno:

declare @retorno int;

exec @retorno=pa_libros_ingreso 'El gato con botas','Anónimo'

if @retorno=1 print 'Registro ingresado'

else select 'Registro no ingresado porque faltan datos';

125 - Procedimientos almacenados (información)

Los procedimientos almacenados son objetos, así que para obtener información de ellos pueden usarse los

siguientes procedimientos almacenados del sistema y las siguientes tablas:

- "sp_help": sin parámetros nos muestra todos los objetos de la base de datos seleccionada, incluidos los

procedimientos. En la columna "Object_type" aparece "stored procedure" si es un procedimiento almacenado.

Si le enviamos como argumento el nombre de un procedimiento, obtenemos la fecha de creación e información

sobre sus parámetros.

- "sp_helptext": seguido del nombre de un procedimiento almacenado nos muestra el texto que define el

procedimiento, excepto si ha sido encriptado.

- "sp_stored_procedures": muestra todos los procedimientos almacenados, los propietarios, etc. Este

procedimiento almacenado puede recibir 3 parámetros: @sp_name (nombre, nvarchar, admite comodines para

búsqueda de patrones), @sp_owner (propietario, nvarchar, admite comodines) y @qualifier (nombre de la base

de datos). Por ejemplo, podemos ver todos los procedimientos almacenados creados por nosotros con esta

sentencia:

sp_stored_procedures @sp_name='pa_%';

- "sp_depends": seguido del nombre de un objeto, nos devuelve 2 resultados: 1) nombre, tipo, campos, etc. de

los objetos de los cuales depende el objeto enviado y 2) nombre y tipo de los objetos que dependen del objeto

nombrado. Por ejemplo, ejecutamos "sp_depends" seguido del nombre de un procedimiento:

sp_depends pa_autor_promedio;

aparecen las tablas (y demás objetos) de las cuales depende el procedimiento, es decir, las tablas referenciadas

en el mismo. Podemos ejecutar el procedimiento seguido del nombre de una tabla:

sp_depends libros;

aparecen los procedimientos (y demás objetos) que dependen de ella.

- La tabla del sistema "sysobjects": muestra nombre y varios datos de todos los objetos de la base de datos

actual. La columna "xtype" indica el tipo de objeto. Si es un procedimiento almacenado, muestra "P". Ejemplo:

select *from sysobjects;

Si queremos ver todos los procedimientos almacenados creados por nosotros, podemos tipear:

select *from sysobjects

Page 132: Base de Datos SQL

where xtype='P' and-- tipo procedimiento

name like 'pa%';--búsqueda con comodín

126 - Procedimientos almacenados (encriptado)

Dijimos que SQL Server guarda el nombre del procedimiento almacenado en la tabla del sistema "sysobjects" y

su contenido en la tabla "syscomments".

Si no quiere que los usuarios puedan leer el contenido del procedimiento podemos indicarle a SQL Server que

codifique la entrada a la tabla "syscomments" que contiene el texto. Para ello, debemos colocar la opción "with

encryption" al crear el procedimiento:

create procedure NOMBREPROCEDIMIENTO

PARAMETROS

with encryption

as INSTRUCCIONES;

Esta opción es opcional.

Creamos el procedimiento almacenado "pa_libros_autor" con la opción de encriptado:

create procedure pa_libros_autor

@autor varchar(30)=null

with encryption

as

select *from libros

where autor=@autor;

Si ejecutamos el procedimiento almacenado del sistema "sp_helptext" para ver su contenido, no aparece.

127 - Procedimientos almacenados (modificar)

Los procedimientos almacenados pueden modificarse, por necesidad de los usuarios o por cambios en la

estructura de las tablas que referencia.

Un procedimiento almacenado existente puede modificarse con "alter procedure". Sintaxis:

alter procedure NOMBREPROCEDIMIENTO

@PARAMETRO TIPO = VALORPREDETERMINADO

as SENTENCIAS;

Modificamos el procedimiento almacenado "pa_libros_autor" para que muestre, además del título, la editorial y

precio:

alter procedure pa_libros_autor

@autor varchar(30)=null

as

if @autor is null

begin

Page 133: Base de Datos SQL

select 'Debe indicar un autor'

return

end

else

select titulo,editorial,precio

from libros

where autor = @autor;

Si quiere modificar un procedimiento que se creó con la opción "with encryption" y quiere conservarla, debe

incluirla al alterarlo.

128 - Procedimientos almacenados (insertar)

Podemos ingresar datos en una tabla con el resultado devuelto por un procedimiento almacenado.

La instrucción siguiente crea el procedimiento "pa_ofertas", que ingresa libros en la tabla "ofertas":

create proc pa_ofertas

as

select titulo,autor,editorial,precio

from libros

where precio<50;

La siguiente instrucción ingresa en la tabla "ofertas" el resultado del procedimiento "pa_ofertas":

insert into ofertas exec pa_ofertas;

Las tablas deben existir y los tipos de datos deben coincidir.

129 - Procedimientos almacenados (anidados)

Un procedimiento almacenado puede llamar a otro procedimiento almacenado. El procedimiento que es

invocado por otro debe existir cuando creamos el procedimiento que lo llama. Es decir, si un procedimiento A

llama a otro procedimiento B, B debe existir al crear A.

Los procedimientos almacenados pueden anidarse hasta 32 niveles.

Creamos un procedimiento almacenado que reciba 2 números enteros y nos retorne el producto de los mismos:

create procedure pa_multiplicar

@numero1 int,

@numero2 int,

@producto int output

as

select @producto=@numero1*@numero2;

Page 134: Base de Datos SQL

Creamos otro procedimiento que nos retorne el factorial de un número, tal procedimiento llamará al

procedimiento "pa_multiplicar":

create procedure pa_factorial

@numero int

as

declare @resultado int

declare @num int

set @resultado=1

set @num=@numero

while (@num>1)

begin

exec pa_multiplicar @resultado,@num, @resultado output

set @num=@num-1

end

select rtrim(convert(char,@numero))+'!='+convert(char,@resultado);

Cuando un procedimiento (A) llama a otro (B), el segundo (B) tiene acceso a todos los

objetos que cree el primero (A).

130 - Procedimientos Almacenados (recompilar)

La compilación es un proceso que consiste en analizar el procedimiento almacenado y crear un plan de

ejecución. Se realiza la primera vez que se ejecuta un procedimiento almacenado o si el procedimiento

almacenado se debe volver a compilar (recompilación).

SQL Server recompila automáticamente un procedimiento almacenado si se realiza algún cambio en la

estructura de una tabla (o vista) referenciada en el procedimiento (alter table y alter view) y cuando se

modifican las claves (insert o delete) de una tabla referenciada.

Un procedimiento almacenado puede recompilarse explícitamente. En general se recomienda no hacerlo

excepto si se agrega un índice a una tabla referenciada por el procedimiento o si los datos han variado mucho

desde la última compilación.

SQL Server ofrece tres métodos para recompilar explícitamente un procedimiento almacenado:

1) Se puede indicar, al crear el procedimiento, que SQL Server no guarde en la caché un plan de ejecución para

el procedimiento sino que lo compile cada vez que se ejecute.

En este caso la sintaxis es la siguiente:

create procedure NOMBREPROCEDIMIENTO

PARAMETROS

with recompile

as

SENTENCIAS;

2) Podemos especificar "with recompile" al momento de ejecutarlo:

exec NOMBREPROCEDIMIENTO with recompile;

Page 135: Base de Datos SQL

3) Podemos ejecutar el procedimiento almacenado del sistema "sp_recompile". Este procedimiento vuelve a

compilar el procedimiento almacenado (o desencadenador) que se especifica. La sintaxis es:

exec sp_recompile NOMBREOBJETO;

El parámetro enviado debe ser el nombre de un procedimiento, de un desencadenador, de una tabla o de una

vista. Si es el nombre de una tabla o vista, todos los procedimientos almacenados que usan tal tabla (o vista) se

vuelven a compilar.