0% encontró este documento útil (0 votos)
87 vistas24 páginas

Introducción a SQL y creación de tablas

Este documento describe el lenguaje de consulta estructurado SQL. SQL se originó en un proyecto de investigación de IBM en 1974 y ahora es un estándar ampliamente utilizado para definir, manipular y consultar bases de datos relacionales. El documento explica cómo SQL se puede usar para crear tablas, agregar y eliminar columnas de tablas existentes, y eliminar tablas. También describe los diferentes tipos de datos que admite SQL como enteros, cadenas de caracteres, fechas y más.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
87 vistas24 páginas

Introducción a SQL y creación de tablas

Este documento describe el lenguaje de consulta estructurado SQL. SQL se originó en un proyecto de investigación de IBM en 1974 y ahora es un estándar ampliamente utilizado para definir, manipular y consultar bases de datos relacionales. El documento explica cómo SQL se puede usar para crear tablas, agregar y eliminar columnas de tablas existentes, y eliminar tablas. También describe los diferentes tipos de datos que admite SQL como enteros, cadenas de caracteres, fechas y más.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Lenguaje de Consulta Estructurado: SQL 66

5. Lenguaje de Consulta Estructurado: SQL.

5.1. Introducción.

El SQL (Structured Query Language, lenguaje de consulta estructurado), llamado


anteriormente SEQUEL, proviene de un proyecto de investigación de IBM (1974) en el
San José Research Laboratory, de California, sobre una base de datos relacional llamada
SYSTEM R. SQL pronto se convirtió en un estándar de lenguaje de consulta y
manipulación de los SGBD relacionales.

En la actualidad, los motores de bases de datos relacionales utilizan este lenguaje


para definir, manipular, consultar y administrar sus bases de datos. Entre otros podemos
citar: DB2, ORACLE, SQL Server, INFORMIX, MySQL, Jet (utilizado por Access),
etc...

El SQL está constituido por comandos de consulta, manipulación y definición de


datos de alto nivel, que se pueden ejecutar de varias formas:

• De forma interactiva (ISQL-Interactive SQL), procesando transacciones en línea.


• Por lotes, mediante un fichero batch.
• Embebido o inmerso en programas de aplicaciones escritos en algún lenguaje de
alto nivel.

5.2. Descripción de datos.

En este apartado veremos un conjunto de ordenes SQL utilizadas para la descripción


de los esquemas conceptual y externo, que se utilizan para definir el modelo relacional
de datos (tablas de base) y el submodelo relacional de datos (vistas).

5.2.1. Creación de tablas.

Una tabla de base tiene existencia por sí misma y se suele implementar como un
archivo almacenado distinto.

La creación de una tabla de base en SQL se realiza ejecutado la proposición


CREATE TABLE, cuyo formato simplificado es:

CREATE TABLE nombre-tabla (<definir-campo> [, <definir-campo> ] ...);

El argumento <definir-campo> adopta la forma:

nombre-campo tipo-dato [NOT NULL] [ IDENTITY [(ValorInicial , Incremento)]

La cláusula NOT NULL especifica que el contenido de un campo no se puede dejar


sin definir, es decir, debe contener algún valor distinto de nulo.

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 67

La cláusula IDENTITY [ ( ValorIncial , Incremento ) ] se utiliza para que el valor


del campo se comporte como un tipo autonumérico, que parta de un valor inicial y se
vaya incrementando de forma automática a medida que se vayan introduciendo nuevos
registros. Si no se especifica la inicialización y el incremento, el valor predeterminado
es (1,1). En Access existe el tipo counter que funciona de modo similar.

Los tipos de datos dependerán del motor SQL, los utilizados por SQL Server son
los siguientes:

Bigint: Datos enteros comprendidos entre -2^63 (-9223372036854775808) y 2^63 -1


(9223372036854775807).
Int: Datos enteros comprendidos entre -2^31 (-2.147.483.648) y 2^31 - 1
(2.147.483.647).
Smallint: Datos enteros comprendidos entre -2^15 (-32.768) y 2^15 - 1 (32.767).
Tinyint: Datos enteros comprendidos 0 y 255.
Bit: Datos enteros con valor 1 ó 0.
Decimal: Datos de precisión y escala numérica fijas comprendidos entre –10^38 +1 y
10^38 – 1.
Numeric: Funcionalmente equivalente a decimal.
Money: Valores de moneda comprendidos entre –2^63 (-922.337.203.685.477,5808) y
2^63 - 1 (+922.337.203.685.477,5807), con una precisión de una diezmilésima de la
unidad monetaria.
Smallmoney: Valores de moneda comprendidos entre -214.748,3648 y +214.748,3647,
con una precisión de una diezmilésima de la unidad monetaria.
Float: Números con precisión de coma flotante comprendidos entre -1,79E + 308 y
1,79E + 308.
Real: Números en coma flotante comprendidos entre -3,40E + 38 y 3,40E + 38.
Datetime: Datos de fecha y hora comprendidos entre el 1 de enero de 1753 y el 31 de
diciembre de 9999, con una precisión de 3,33 milisegundos.
Smalldatetime: Datos de fecha y hora comprendidos entre el 1 de enero de 1900 y el 6
de junio de 2079, con una precisión de un minuto.
Char: Datos de caracteres no Unicode de longitud fija con una longitud máxima de
8.000 caracteres.
Varchar: Datos no Unicode de longitud variable con un máximo de 8.000 caracteres.
Text: Datos no Unicode de longitud variable con una longitud máxima de 2^31 - 1
(2.147.483.647) caracteres.
Nchar: Datos Unicode de longitud variable con una longitud máxima de 4.000
caracteres.
Nvarchar: Datos Unicode de longitud variable con una longitud máxima de 4.000
caracteres. sysname es el tipo de datos suministrado por el sistema y definido por el
usuario que es funcionalmente equivalente a nvarchar(128) y que se utiliza para hacer
referencia a nombres de objetos de bases de datos.
Ntext: Datos Unicode de longitud variable con una longitud máxima de 2^30 - 1
(1.073.741.823) caracteres.
Binary: Datos binarios de longitud fija con una longitud máxima de 8.000 bytes.
Varbinary: Datos binarios de longitud variable con una longitud máxima de 8.000
bytes.
Image: Datos binarios de longitud variable con una longitud máxima de 2^31 - 1
(2.147.483.647) bytes.

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 68

Algunos tipos de datos admiten especificar:

− La precisión: el número total de dígitos de un número (parte entera y decimal).


− La escala: el número de dígitos situados a la derecha de la coma decimal.
− La longitud: el número de bytes utilizados para almacenar el dato.

Se puede especificar la precisión y escala de los tipos numeric y decimal:

decimal[(p[, s])] y numeric[(p[, s])]

Donde p es la precisión y s la escala. La precisión máxima predeterminada de los tipos


de datos numeric y decimal es 38. En versiones anteriores de SQL Server, el máximo
predeterminado era 28. La precisión debe ser un valor comprendido entre 1 y la
precisión máxima. La escala debe ser un valor comprendido entre 0 y p. La escala
predeterminada es 0; por tanto, 0 <= s <= p. La longitud (bytes de almacenamiento)
varían según la precisión:
Precisión Longitud (Bytes de almacenamiento)
1–9 5
10-19 9
20-28 13
29-38 17

En un tipo float, también podemos especificar su precisión del siguiente modo:


float [ ( n ) ]

Donde n es el número de bits que se utilizan para almacenar la mantisa del número float
en notación científica y por tanto indica su precisión y el tamaño de almacenamiento. n
tiene que ser un valor entre 1 y 53.
Para valores de n Precisión Tamaño de almacenamiento
1-24 7 cifras 4 bytes
25-53 15 cifras 8 bytes

La longitud para una cadena de caracteres es el número de caracteres. La longitud para


los tipos de datos binary, varbinary e image es el número de bytes.
Veamos algunos ejemplos:

− Un tipo de datos int que puede contener 10 dígitos se almacena en 4 bytes y no


acepta coma decimal. El tipo de datos int tiene una precisión de 10, una longitud
de 4 y una escala de 0.
− Un tipo decimal(6,2) podría almacenar el número 1234,56 que tiene una
precisión de 6, una escala de 2, y una longitud 5 (utilizaría 5 bytes de
almacenamiento).
La especificación Unicode define un esquema de codificación único para la mayor
parte de los caracteres usados con más frecuencia en todo el mundo. Todos los equipos
convierten de forma coherente los patrones de bits de los datos Unicode en caracteres

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 69

con la especificación única de Unicode. Esto asegura que el mismo patrón de bits se
convierte siempre al mismo carácter en todos los equipos. Esta especificación pretende
resolver el problema de los tipos de datos que usan un byte para codificar cada carácter,
que sólo puede representar 256 caracteres distintos. Esto supone que tiene que haber
varias especificaciones de codificación (o páginas de códigos) para distintos alfabetos,
como, por ejemplo, los europeos, que son relativamente pequeños. Tampoco se pueden
tratar sistemas tales como el alfabeto Kanji japonés o el Hangul coreano, que tienen
miles de caracteres.

Los tipos de datos tradicionales no Unicode permiten la utilización de un conjunto


de caracteres que se elige durante la instalación de SQL Server y no puede modificarse.
Si se utilizan los tipos de datos Unicode, una columna puede almacenar cualquier
carácter definido por el estándar Unicode, que incluye todos los caracteres definidos en
los diversos conjuntos de caracteres. Los tipos de datos Unicode ocupan el doble de
espacio que los que no lo son.

Veamos un ejemplo de creación de tablas:

CREATE TABLE
PERSONAL(DNI char(9) NOT NULL, NOMBRE varchar(25), SALARIO smallmoney);

A una tabla de base, ya definida, se le pueden añadir nuevas columnas utilizando el


comando ALTER TABLE, que tiene el formato:

ALTER TABLE nombre-tabla ADD nombre-campo tipo-dato;

Por ejemplo:

ALTER TABLE PERSONAL ADD APELLIDO varchar(20);

Si quisiéramos eliminar una columna utilizaríamos la siguiente sintaxis:

ALTER TABLE nombre-tabla DROP COLUMN nombre-campo;

Por ejemplo:

ALTER TABLE PERSONAL DROP COLUMN APELLIDO;

Para borrar físicamente una tabla de base utilizaríamos el comando DROP


TABLE:

DROP TABLE nombre-tabla;

Por ejemplo:

DROP TABLE PERSONAL;

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 70

5.2.2. Creación de Vistas.

Un submodelo relacional de datos se compone de una o más vistas. Una vista se


puede considerar como una tabla virtual; es decir, no existe en la realidad, y por ello no
hay ningún archivo almacenado que la represente.

La vista se crea a partir de una o más tablas de base con el comando CREATE
VIEW, cuyo formato es:

CREATE VIEW nombre-vista [(nombre-campo [, nombre-campo]...)] AS


SELECT nombre-campo [, nombre-campo]...
FROM nombre-tabla-base [, nombre-tabla-base]...
[WHERE condición];

Veamos un ejemplo que crea una vista llamada MENOSMIL que contiene el
DNI y el NOMBRE de la tabla de base PERSONAL, donde el SALARIO sea menor de
1.000∈:
CREATE VIEW MENOSMIL AS
SELECT DNI, NOMBRE
FROM PERSONAL WHERE SALARIO<1000;

Posteriormente profundizaremos en las cláusulas SELECT-FROM-WHERE.

Aunque la vista no se almacene físicamente, en el diccionario de datos está


guardada su definición y el usuario podrá procesar los datos definidos en ella como si
fuera una tabla de base real.

Una vista se puede borrar del diccionario de datos mediante el comando:

DROP VIEW nombre-vista;

5.2.3. Creación de índices.

El sistema gestor de una base de datos relacional utiliza los índices para el acceso
directo a los datos a través de su clave principal o bien de sus claves secundarias.

El archivo índice se suele implementar físicamente con una estructura de árbol-B.


Para crear un índice se utiliza el comando CREATE INDEX. Si la base de datos ya está
cargada, el índice se construye en ese instante; si está vacía, el sistema construye el
índice a medida que los datos se van insertando en la tabla. En ambos casos el índice se
mantiene automáticamente. La sintaxis del comando utilizado para crear índices es:

CREATE [UNIQUE] [CLUSTERED|NONCLUSTERED]


INDEX nombre-índice ON nombre-tabla
( nombre-campo {ASC/DESC}
[,nombre-campo {ASC/DESC}] ...);

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 71

El campo sobre el que se construye el índice puede ser único o una concatenación
de campos. La ordenación por defecto es en orden ascendente. La cláusula UNIQUE
asegura que los valores de campo indexado deben ser únicos. Veamos un ejemplo:

CREATE UNIQUE INDEX DNIPERSONAL ON PERSONAL (DNI);

La cláusula CLUSTERED reorganiza la tabla, físicamente, por las columnas


indicadas en el índice. Por tanto, sólo podrá haber un índice CLUSTERED por tabla, lo
habitual es que se trate de la clave principal de la tabla.

Un índice se puede suprimir físicamente y eliminar su descripción del diccionario


de datos con el comando:

DROP INDEX NombreTabla.NombreÍndice;

Por ejemplo:

DROP INDEX PERSONAL.DNIPERSONAL;

Algunos motores utilizan la siguiente sintaxis:

DROP INDEX DNIPERSONAL ON PERSONAL;

5.2.4. Definición de restricciones (cláusula CONSTRAINT).

Las restricciones se utilizan para mantener la integridad en la base de datos.


Fundamentalmente la usaremos para establecer claves principales, claves ajenas y
establecer las correspondientes relaciones entre tablas. Para ello se utiliza la cláusula
CONSTRAINT, tanto en las instrucciones ALTER TABLE como CREATE TABLE.

Hay dos tipos de sintaxis para cláusulas CONSTRAINT: una para crear una
limitación en un único campo (restricción a nivel de campo) y otra para crear una
limitación en más de un campo (restricción a nivel de tabla).

CREATE TABLE nombre-tabla (<definir-campo> [, <definir-campo> ] ...


,CONSTRAINT NombreRestricciónDeTabla
{ PRIMARY KEY | UNIQUE } [CLUSTERED | NONCLUSTERED]
(campo1 [,campo2]...)
| FOREIGN KEY (referencia1 [, referencia2]...)
REFERENCES TablaReferenciada [(ClavPrinDeTablaReferenciada)]
[ON DELETE { CASCADE | NO ACTION } ]
[ON UPDATE { CASCADE | NO ACTION } ] );
Donde:

PRIMARY KEY: Establece qué atributos conformarán la clave principal. Todos los
valores de la clave principal deben ser únicos y NOT NULL, y solamente puede
haber una clave principal para una tabla.

UNIQUE: Establece qué atributos conformarán un índice único.

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 72

CLUSTERED|NONCLUSTERED: Determina el tipo de índice que se va a crear.


Por defecto se crea un índice CLUSTERED para una PRIMARY KEY y un índice
NONCLUSTERED para un índice UNIQUE. Sólo se puede especificar
CLUSTERED para una única restricción. Si especifica CLUSTERED para una
restricción UNIQUE y especifica también una restricción PRIMARY KEY, el valor
predeterminado de PRIMARY KEY es NONCLUSTERED.

campo1, campo2,..., hace referencia a los distintos atributos que componen la clave
principal o el índice único (la clave principal o el índice único puede estar formado
por varios atributos).

FOREIGN KEY: Establece qué atributos de la tabla determinan la clave ajena.

referencia1, referencia2,..., se refiere a los distintos atributos que constituyen la


clave ajena (la clave ajena puede estar formada por varios atributos).

REFERENCES: Especifica la tabla a la que se está haciendo referencia mediante la


clave ajena especificada en FOREIGN KEY.

ClavPrinDeTablaReferenciada: Se puede omitir, siempre que se trate de la clave


principal de la tabla referenciada. Si se especifican los nombres de los campos que
conforman el índice único de la tabla referenciada, deberán especificarse en el
mismo orden los atributos referencia1, referencia2,... de FOREIGN KEY.

ON DELETE CASCADE | NO ACTION: Si se especifica CASCADE, al eliminar


una fila en la tabla referenciada, se elimina en cascada la fila de la tabla desde donde
se hace referencia (la que estamos creando). Si se especifica NO ACTION, SQL
Server genera un error y se deshace la acción de eliminación de la fila en la tabla
referenciada. La opción por defecto es NO ACTION.

ON UPDATE CASCADE | NO ACTION: Si se especifica CASCADE, al


modificar una fila en la tabla referenciada, se actualiza en cascada la fila de la tabla
desde donde se hace referencia (la que estamos creando). Si se especifica NO
ACTION, SQL Server genera un error y se deshace la acción de modificación de la
fila en la tabla referenciada. La opción por defecto es NO ACTION.

Para especificar las restricciones a columnas independientes, se incluye la cláusula


CONSTRAINT junto a la definición de la columna correspondiente. En este caso el
argumento <definir-campo> adopta la siguiente forma:

nombre-campo tipo-dato [, NOT NULL] CONSTRAINT NombreRestricciónDeColumna


{PRIMARY KEY | UNIQUE } [CLUSTERED | NONCLUSTERED]
| REFERENCES TablaReferenciada[(ClavPrinDeTablaReferenciada)]
[ON DELETE { CASCADE | NO ACTION } ]
[ON UPDATE { CASCADE | NO ACTION } ]

De esta forma un campo se puede definir como clave primaria o índice único (con
las cláusulas primary key o unique), o bien como clave ajena (con la cláusula
references).

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 73

Veamos algunos ejemplos:

CREATE TABLE Personal (


DNI char(9) CONSTRAINT pkpersonal PRIMARY KEY,
NOMBRE varchar(25),
SALARIO integer );

En el ejemplo anterior se crea una tabla llamada Personal con los campos DNI,
NOMBRE y SALARIO. Además se establece una restricción llamada pkpersonal que
define como clave principal el campo DNI.

CREATE TABLE Incidencias(


NumIncidencia integer IDENTITY(1,1) CONSTRAINT pkIncidencias PRIMARY
KEY,
DniPer char(9) CONSTRAINT Perso_Incid REFERENCES Personal(DNI),
Fecha datetime,
Descripcion varchar(30) );

La instrucción anterior crea una tabla llamada Incidencias con los campos
NumIncidencia, DniPer, Fecha, y Descripción. Establece una restricción llamada
pkIncidencias para definir una clave primaria. Y además, establece otra restricción
llamada Perso_Incid para definir una relación mediante la clave ajena DniPer con la
tabla Personal.

Desde el Administrador Corporativo de SQL Server podríamos ver de forma gráfica lo


ocurrido, creando el correspondiente diagrama:

Si quisiéramos eliminar la restricción Perso_Incid escribiríamos lo siguiente:

ALTER TABLE Incidencias DROP CONSTRAINT Perso_Incid;

Si existieran las tablas Personal e Incidencias, y quisiéramos establecer la relación con


posterioridad, podríamos utilizar la orden ALTER TABLE con la siguiente sintaxis:

ALTER TABLE Incidencias ADD CONSTRAINT Perso_Incid


FOREIGN KEY (DniPer) REFERENCES Personal (DNI);

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 74

Por último, vamos crear la siguiente B.D. mezclando las distintas sintaxis vistas:

Create table Alumnos ( CodAlumno integer constraint pkAlumnos PRIMARY KEY, Nombre
varchar(30), Direccion varchar(30) );

Create table Cursos (CodCurso char(3) constraint pkCursos PRIMARY KEY, Curso
varchar(20), Descripcion varchar(40) );

Create table Ofertas ( CodCurso char(3) constraint OfertCursos REFERENCES Cursos ON


DELETE CASCADE, Fecha datetime, Lugar varchar(25), Plazas integer,
constraint pkOfertas PRIMARY KEY (CodCurso, Fecha) );

Create table Matriculas (CodAlumno integer, CodCurso char(3), Fecha datetime,


constraint pkMatriculas PRIMARY KEY (CodAlumno, CodCurso, Fecha),
constraint MatrOfert FOREIGN KEY (CodCurso, Fecha) REFERENCES Ofertas ON
DELETE CASCADE,
constraint MatrAlum FOREIGN KEY (CodAlumno) REFERENCES Alumnos ON
DELETE CASCADE );

Según las restricciones especificadas, no se permitirá modificación claves de tuplas


referenciadas (ya que no se ha especificado la cláusula ON UPDATE y por defecto SQL Server
restringe), y en caso de eliminación de tuplas referenciadas se borrarán en cascada las tuplas
que la referencian.

5.3. Consulta de datos.

Las consultas en SQL constan de uno o más bloques de recuperación SELECT-


FROM-WHERE. El resultado de una consulta es una relación. Cada bloque de
recuperación tiene la siguiente estructura:

SELECT atributos
FROM relaciones
[WHERE condiciones-lógicas];

La función de cada cláusula es la siguiente:

• SELECT (elegir) corresponde a la operación de proyección del álgebra


relacional. Especifica todos los atributos que se desean recuperar.
• FROM (de) especifica una lista de relaciones de donde se escogerán los atributos
en la cláusula SELECT.
• WHERE (donde) es opcional e incluye las condiciones que deben cumplir los
atributos de las relaciones.

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 75

SQL forma el producto cartesiano de las relaciones especificadas en FROM;


realiza la selección de filas mediante las condiciones de WHERE y proyecta el
resultado a los atributos señalados en SELECT. Como puedes observar las operaciones
select, project y join del álgebra relacional se ejecutan con este comando. No hay que
confundir la operación select del álgebra relacional con el comando SELECT de SQL.

Los ejemplos que exponemos a continuación se basan en la siguiente B.D.:

Relación PROVEEDORES Relación PRECIOS


Nif Nombre Localidad NifPro CodArt Precio
1111 Manuel Málaga 1111 11 13,00
3333 Gabriel Granada 1111 22 200,00
5555 Marco Málaga 3333 22 210,00
7777 Carlos Cádiz 5555 11 14,00
8888 Antonio Almería 7777 11 15,00
7777 22 220,00

Relación COMPRAS Relación ARTICULOS


IdComp CodArt Nif Cantidad Fecha Código Concepto
1 11 1111 100 12/10/04 11 Teclado
2 22 3333 50 17/10/04 22 Impresora
3 11 7777 50 17/10/04
4 22 7777 30 18/10/04
5 11 5555 35 01/11/04

5.3.1. Operaciones de consulta sobre una sola relación

Selección de atributos: Obtener los nombres de los proveedores y su localidad.

SELECT nombre, localidad


FROM proveedores;

Selección de todos los atributos: La selección de todos los atributos de una relación
se puede especificar mediante un asterisco (*).

Obtener todos los datos de los proveedores:

SELECT *
FROM proveedores;

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 76

Recuperación mediante condiciones: La condición que acompaña a WHERE puede


contener los operadores de equivalencia: =, < , >, <>, >= y <=; y los operadores lógicos
AND, OR y NOT, así como paréntesis para señalar el orden de ejecución.

Obtener los nombres de los proveedores de Málaga:

SELECT nombre
FROM proveedores
WHERE localidad = ‘Málaga’;

Predicados para condiciones de comparación: Además de los operadores de


equivalencia y lógicos vistos en el apartado anterior, existen predicados que permiten
expresar ciertas condiciones de forma más cómoda, que si se utilizan los operadores de
equivalencia:

- Expresión [NOT] BETWEEN Expresión1 AND Expresión2


- Expresión [NOT] IN (lista de valores)
- Atributo [NOT] LIKE ‘patrón de cadena de caracteres’
- Atributo IS [NOT] NULL

Predicado BETWEEN: Permite comparar el valor de la expresión situada a la


izquierda de la palabra BETWEEN con los valores comprendidos en el intervalo
definido por las expresiones de la derecha e izquierda de la palabra clave AND.

Obtener los NIF de los proveedores a los que se les haya comprado el código de
artículo 11 en cantidades entre 50 y 100 (ambas incluidas).

SELECT nif
FROM compras
WHERE codart = ‘11’ AND
cantidad BETWEEN 50 AND 100;

Predicado IN: Permite comparar el valor de la expresión situada a la izquierda de


la palabra IN con una lista de valores encerrados entre paréntesis situados a la derecha
de dicha palabra.

Obtener los nombres de los proveedores cuya localidad sea Málaga, Huelva o
Cádiz.
SELECT nombre
FROM proveedores
WHERE localidad IN (‘Málaga’, ‘Huelva’, ‘Cádiz’);

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 77

Predicado LIKE: Permite realizar una comparación de semejanza entre un atributo


y una cadena patrón utilizando caracteres comodín. Los caracteres comodín suelen
variar dependiendo del motor SQL utilizado, veamos algunos casos:

En SQL Server: % Busca cualquier cosa de cualquier longitud.


_ Busca un carácter.
[ ] Contiene un rango o lista de caracteres.
[^] Contiene los caracteres que hay que excluir.

En Access: * Múltiples caracteres.


? Un único carácter.
# Un único número.
[ ] Contiene un rango de caracteres.
[!]Contiene los caracteres que hay que excluir.

Algunos motores, como es el caso de Informix, utilizan el predicado MATCHES


para especificar rangos.

Obtener los datos de los proveedores cuyo nombre empiece por A, B, C o D:

SELECT *
FROM Proveedores
WHERE Nombre LIKE ‘[A-D]%’;
Se recomienda utilizar LIKE cuando se buscan valores datetime, porque las entradas
datetime pueden contener distintas partes de fecha y hora. Por ejemplo, si se inserta el
valor 31-12-2003 9:20 en una columna denominada HoraDeLLegada, la cláusula
WHERE HoraDeLLegada = ‘9:20’ no puede encontrar ninguna coincidencia exacta. Sin
embargo, sí se encontraría, con la cláusula WHERE HoraDeLLegada LIKE ' %9:20%' .
Ante cualquier problema, puede ser conveniente utilizar el generador de vistas del
administrador corporativo o consultar la función CONVERT() de TransacSQL.

LIKE admite las concordancias de patrón ASCII y Unicode. Cuando se utilizan datos
Unicode (tipos de datos nchar o nvarchar) con LIKE, los blancos a la derecha son
importantes; sin embargo, para los datos que no sean Unicode, los blancos a la derecha
no son importantes.

Éstos son varios ejemplos que muestran las diferencias de las filas devueltas por la
concordancia de patrón LIKE para ASCII y Unicode:
-- Patrón ASCII con columna Char()
CREATE TABLE t (col1 char(30))
INSERT INTO t VALUES ('José López')
SELECT *
FROM t
WHERE col1 LIKE '% López' -- Devuelve 1 fila

-- Patrón Unicode con columna nchar()


CREATE TABLE t (col1 nchar(30))
INSERT INTO t VALUES ('José López')
SELECT *
FROM t
WHERE col1 LIKE '% López' -- No devuelve filas

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 78

-- Patrón Unicode con columna nchar y función RTRIM, que quita los
-- espacios en blanco por la derecha

CREATE TABLE t (col1 nchar (30))


INSERT INTO t VALUES ('José López')
SELECT *
FROM t
WHERE RTRIM(col1) LIKE '% López' -- Devuelve una fila

-- Otra posibilidad sería: WHERE col1 LIKE '% López%'

-- Por último, observar que si se utiliza nvarchar, no daría problemas


-- ya que no se almacenan los espacios en blanco por la derecha.

CREATE TABLE t (col1 nvarchar(30))


INSERT INTO t VALUES ('José López')
SELECT *
FROM t
WHERE col1 LIKE '% López' -- Devuelve 1 fila

Predicado IS NULL: En SQL el valor nulo tiene un valor diferente a 0 y a cadena


vacía. Por tanto, para preguntar si un atributo contiene, o no, un valor nulo, hay que
utilizar el predicado IS [NOT] NULL.

Obtener los datos de los proveedores de los que no se conozca su localidad:

SELECT *
FROM Proveedores
WHERE Localidad IS NULL;

Eliminación de las respuestas duplicadas: SQL, como casi todos los lenguajes
comerciales de consulta, permite el duplicado de tuplas debido al tiempo relativamente
largo en su eliminación. Es tarea del usuario la supresión de las tuplas duplicadas. La
supresión se consigue insertando la palabra clave DISTINCT después de SELECT.

Obtener los números de los artículos comprados después del 01/10/03 (sin duplicados):

SELECT DISTINCT CodArt


FROM compras
WHERE fecha > ‘01/10/03’;
(En Access se utiliza el delimitador #01/10/03#)

Recuperación con ordenamiento: El orden, ascendente o descendente, en que se


van a mostrar las tuplas de una relación, lo puede determinar el usuario mediante la
cláusula ORDER BY (ordenar por), cuyo formato es:

ORDER BY atributo [DESC] [, atributo [DESC]] ...

Obtener todos los datos de los proveedores ordenados alfabéticamente por nombre:

SELECT *
FROM proveedores
ORDER BY nombre;

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 79

5.3.2. Operaciones de consulta sobre más de una relación.

Para evitar la ambigüedad en los casos en que un atributo aparece en más de una
relación, SQL utiliza la notación:

nombre-relación.nombre-atributo

Cuando las consultas implican a más de una relación es necesario que estén ligadas
por un campo común
.
Recuperación de datos de dos relaciones. Obtener los nombres de los proveedores
a los que se les haya comprado artículos:

SELECT DISTINCT nombre


FROM proveedores, compras
WHERE proveedores.nif = compras.nif;

Conceptualmente, SQL, para realizar la consulta anterior, debe realizar las


siguientes operaciones en el álgebra relacional:

- Realizar el producto cartesiano de las relaciones PROVEEDORES y


COMPRAS.
- Seleccionar las filas que tienen igual NIF en proveedores y compras.
- Extraer la columna deseada: nombre del proveedor.
- Eliminar las filas duplicadas.

Recuperación de datos mediante la unión de una relación consigo misma.


Obtener las parejas de los nombres de los proveedores que tengan su residencia en la
misma localidad:

SELECT prove1.nombre, prove2.nombre


FROM proveedores as prove1, proveedores as prove2
WHERE prove1.localidad = prove2.localidad AND prove1.nif < prove2.nif;

Este ejemplo incluye la reunión de la tabla PROVEEDORES consigo misma con la


condición de que ambas localidades sean las mismas y que el NIF del primer proveedor
sea menor que el del segundo. De esta forma se elimina la pareja de un proveedor
consigo mismo y la aparición de parejas duplicadas (Por ejemplo: Manuel-Marcos y
Marcos-Manuel).

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 80

5.3.3. Operaciones mediante la cláusula JOIN.

Cuando necesitemos unir varias tablas, podemos utilizar la cláusula WHERE, como
vimos anteriormente, o bien utilizar la cláusula JOIN de la sintaxis ANSI, bastante más
potente. Veamos los tipos de uniones que permite realizar la cláusula JOIN:

• INNER JOIN o unión interior. Es la operación de unión habitual. Si se utiliza el


operador de equivalencia =, se trata de una unión natural del álgebra relacional, y
sólo se presentarían las filas que coinciden en ambas tablas. Daría el mismo
resultado que la unión utilizando la cláusula WHERE.

Por ejemplo: “Obtener los nombres de los proveedores junto con los códigos de
artículos y las cantidades compradas. Mostrando sólo los proveedores a los que se
les ha comprado algún artículo”

SELECT nombre, codart, cantidad


FROM proveedores INNER JOIN compras ON proveedores.nif = compras.nif;

• OUTER JOIN o unión exterior. Existen tres posibles uniones exteriores: unión
exterior izquierda, exterior derecha y exterior completa:

- LEFT JOIN o unión exterior izquierda. Proporciona como resultado todas


las filas de la tabla izquierda de la cláusula JOIN, tengan o no, coincidencia
con filas de la tabla derecha. En los casos en que la tabla derecha no tenga
filas coincidentes se muestran valores NULL en los atributos de ésta.

Por ejemplo para: “Obtener los nombres de los proveedores junto con los
códigos de artículos y las cantidades compradas. Mostrando todos los
proveedores aunque no se les haya comprado ningún artículo”

SELECT nombre, codart, cantidad


FROM proveedores LEFT JOIN compras
ON proveedores.nif = compras.nif;

- RIGHT JOIN o unión exterior derecha. Proporciona como resultado todas


las filas de la tabla derecha de la cláusula JOIN, tengan o no, coincidencia
con filas de la tabla izquierda. En los casos en que la tabla izquierda no tenga
filas coincidentes se muestran valores NULL en los atributos de ésta.

Al seguir con el mismo ejemplo anterior, se nos plantea un caso poco


probable, pero aún así, daremos su solución: “Obtener los nombres de los
proveedores junto con los códigos de artículos y las cantidades compradas.
Mostrando todos los artículos aunque no se conozca su proveedor (Clave
ajena NIF de la tabla Compras con valor NULL)”.

SELECT nombre, codart, cantidad


FROM proveedores RIGHT JOIN compras
ON proveedores.nif = compras.nif;

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 81

- FULL JOIN o unión exterior completa. Devuelve todas las filas, tanto de la
tabla izquierda, como la derecha, aunque no cumplan los criterios de unión.
En este caso las filas de la otra tabla se devolverán con el valor NULL.

Y continuando con ejemplo anterior, se nos vuelve a plantear un caso atípico:


“Obtener los nombres de los proveedores junto con los códigos de artículos
y las cantidades compradas. Mostrando todos los proveedores aunque no se
les haya comprado ningún artículo y mostrando todos los artículos aunque
no se conozca su proveedor (Clave ajena NIF de la tabla Compras con valor
NULL)”.

SELECT nombre, cod_art, cantidad


FROM proveedores FULL JOIN compras
ON proveedores.nif = compras.nif;

• CROSS JOIN o unión cruzada. Es el producto cartesiano de dos tablas, se obtiene


el mismo resultado que si no se especifica una cláusula WHERE en una unión sin la
cláusula JOIN.
Por ejemplo: “Para obtener el producto cartesiano de las tablas proveedores y
artículos, mostrando todas las parejas posibles entre un nombre de proveedor y un
concepto de artículo”
SELECT nombre, concepto
FROM proveedores CROSS JOIN articulos;

O bien, sin la cláusula JOIN:

SELECT nombre, concepto


FROM proveedores, articulos;

Por último, veremos un ejemplo donde se relacionan tres tablas, siendo necesario
anidar dos cláusulas JOIN: “Obtener los nombres de los proveedores a los que se les
haya comprado el artículo Teclado, junto las cantidades compradas.”

SELECT nombre, cantidad


FROM proveedores INNER JOIN
(compras INNER JOIN articulos ON articulos.codigo = compras.codart)
ON proveedores.Nif = compras.Nif
WHERE concepto = ’Teclado’;

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 82

5.3.4. Expresiones con bloques anidados SELECT-FROM-WHERE.

SQL permite que dentro de un bloque SELECT-FROM-WHERE vayan uno o más


bloques SELECT-FROM-WHERE anidados dentro de la cláusula WHERE. Al bloque
anidado se le denomina subconsulta.

Subconsulta con el operador IN:

SELECT atributol, atributo2, ..., atributo-n


FROM relaciones
WHERE atributo [NOT] IN (SELECT ... FROM ...)

El operador IN (en) se puede considerar como un operador de pertenencia. Verifica


si la consulta pertenece a un conjunto de valores producidos por la subconsulta. El
conector NOT IN verifica si no se pertenece al conjunto.

Recuperación usando IN. Obtener los nombres de los proveedores que


suministran el artículo número 22:

SELECT nombre
FROM proveedores
WHERE nif IN
(SELECT nifpro
FROM precios
WHERE codart = ‘22’);

El nombre del proveedor sólo se escoge si en la subconsulta

(SELECT nifpro
FROM precios
WHERE codart = ‘22’);

hay algún artículo con el código 22.

La consulta anterior también se puede escribir, sin necesidad de utilizar bloques


anidados:
SELECT DISTINCT nombre
FROM proveedores, precios
WHERE nif = nifpro AND codart = ‘22’;

Las dos formas de expresar la consulta (mediante subconsulta o mediante reunión)


son correctas, la elección será cuestión del usuario, excepto si el sistema ejecuta de
forma más óptima alguna de las dos.

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 83

Recuperación con una subconsulta utilizando la misma relación en ambos


bloques. Obtener los NIF de los proveedores que suministran al menos un artículo de
los suministrados por el proveedor 3333.

SELECT DISTINCT nifpro


FROM precios
WHERE codart IN (SELECT codart
FROM precios
WHERE nifpro = ‘3333’);

Recuperación con niveles múltiples de anidamiento. Obtener los nombres de los


proveedores a los que se les ha comprado algún teclado.

SELECT DISTINCT nombre


FROM proveedores
WHERE nif IN (SELECT nif
FROM compras
WHERE codart IN (SELECT codigo
FROM articulos
WHERE concepto = ‘Teclado’));

El bloque más interno encuentra el código de artículo del “Teclado”. El segundo


bloque halla el conjunto de nif que han suministrado ese código. El bloque más externo
recupera los nombres de los proveedores de los nif seleccionados.

Las dos sintaxis que veremos a continuación no suelen presentarse con mucha
frecuencia en la práctica, pero se exponen para mostrar la potencia de SQL. Algunos
ejemplos pueden resultar complejos, pero ten en cuenta que las consultas habituales se
suelen resolver con mucha facilidad.

SQL admite los cuantificadores ANY (algún) y ALL (todo). Con el siguiente
formato:
SELECT atributol, atributo2, ..., atributo-n
FROM relaciones
WHERE atributo operador-comparación {ANY / ALL}
(SELECT ... FROM ...)

El operador de comparación puede ser: =, <, >, <>, <= y >=.

Recuperación usando ANY. Obtener los NIF de los proveedores que suministren el
artículo 22 a menor precio que alguno de los proveedores que lo suministran.

SELECT nifpro
1111, 3333, ya que FROM precios
los dos ofrecen WHERE codart =’22’ AND precio <ANY
precios menores
que el más caro, (SELECT precio
ofrecido por 7777.
200,00; 210,00; FROM precios
220,00 WHERE codart = ‘22’);

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 84

Si Sustituimos <ANY por <=ALL, obtendríamos los NIF de los proveedores que
suministran el artículo 22 más barato:

SELECT nifpro
1111, ya que FROM precios
ofrece el precio WHERE codart =’22’ AND precio <=ALL
menor, que
corresponde a (SELECT precio
200,00
200,00; 210,00; FROM precios
220,00 WHERE codart = ‘22’);

Recuperación usando ALL. Obtener los nombres de los proveedores que no


suministran el artículo número “11”.

SELECT nombre
FROM proveedores
WHERE ‘11’ <> ALL (NOT IN)
(SELECT codart
FROM precios
WHERE nifpro = proveedores.nif);

En la última línea, el primer nifpro pertenece a la relación PRECIOS seleccionada


en el bloque interno; sin embargo, para referirse a un atributo del bloque externo dentro
del bloque interno hay que especificar el nombre de su relación, proveedores.nif. Se
trata de consultas correlacionadas.

También admite el cuantificador existencial EXISTS, y se expresa:

SELECT atributol, atributo2, ..., atributo-n


FROM relaciones
WHERE [NOT] EXISTS (SELECT ... FROM...);

el predicado EXISTS (existe) tiene como argumento a una proposición SELECT y es


verdadero si el resultado obtenido dentro de la subconsulta es no vacío.

Recuperación usando EXISTS. Obtener los nombres de los proveedores que


suministran el artículo número “11”. (Similar al ejemplo utilizando el operador IN)

SELECT nombre
FROM proveedores
WHERE EXISTS (SELECT *
FROM precios
WHERE nifpro = proveedores.nif AND codart = ‘11’);

Observa como en la condición WHERE, de la subconsulta, hace referencia a la


tabla proveedores de la consulta (proveedores.nif).

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 85

Recuperación usando NOT EXISTS. Obtener los nombres de los proveedores que
no suministran el artículo número “11” (compáralo con la solución dada con ALL)

SELECT nombre
FROM proveedores
WHERE NOT EXISTS (SELECT *
FROM precios
WHERE nifpro=proveedores.nif AND codart = ‘11’);

5.3.5. Otras posibilidades de consulta.

Algunos motores SQL incluyen las operaciones UNION (unión), INTERSECT


(intersección) y MINUS (diferencia), que operan sobre relaciones y se corresponden con
los operadores del álgebra relacional.

Recuperación usando UNION. Obtener los códigos de artículos de los que se han
comprado más de 60 unidades o el precio sea mayor de 100.

(SELECT codart
FROM compras
WHERE cantidad > 60)
UNION
(SELECT codart
FROM precios
WHERE precio > 100);

Recuperación usando INTERSECT. Obtener los números de los artículos de los


que se han comprado más de 60 unidades y el precio sea mayor de 100.

(SELECT codart
FROM compras
WHERE cantidad > 60)
INTERSECT //Esta sintaxis no la admite SQL Server
(SELECT codart // Se puede solucionar mediante IN
FROM precios
WHERE precio > 100);

Recuperación usando MINUS. Obtener los números de los artículos de los que se
han comprado más de 60 unidades pero que el precio no sea mayor de 100 .

(SELECT codart
FROM compras
WHERE cantidad > 60)
MINUS //Esta sintaxis no la admite SQL Server
(SELECT codart // Se puede solucionar mediante NOT IN
FROM precios
WHERE precio > 100);

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 86

5.3.6. Recuperación mediante funciones de agregados.

SQL ofrece la posibilidad de aplicar funciones de grupo de tuplas mediante la


cláusula GROUP BY (agrupar por). Un grupo se define como el conjunto de tuplas que
tienen el mismo valor en la columna atributo especificada. La cláusula HAVING
expresa la condición que deben cumplir los grupos. HAVING actúa con los grupos, de
forma similar que la cláusula WHERE con las filas. El formato es el siguiente:

SELECT función
FROM relación
WHERE condición
[GROUP BY...] [HAVING función operador-comparación ...]

Las funciones pueden ser: COUNT (contar número de tuplas), SUM (sumar), MIN
(mínimo), MAX (máximo) y AVG (promedio). Admiten los formatos:

- COUNT (*): Cuenta las tuplas de la relación.


- COUNT (DISTINCT atributo): Proyecta y cuenta el número de valores
distintos del atributo especificado.
- SUM (atributo): Suma los valores del atributo especificado.
- MIN (atributo): Halla el mínimo de los valores del atributo especificado.
- MAX (atributo): Halla el máximo de los valores del atributo especificado.
- AVG (atributo): Halla el promedio de los valores del atributo especificado.

Recuperación con la función COUNT (*). Obtener el número total de artículos.


SELECT COUNT (*)
FROM articulos;

Recuperación con la función COUNT (DISTINCT atributo). Contar el número


total de artículos distintos comprados. (Todos los codart repetidos se cuentan como uno
sólo)
SELECT COUNT (DISTINCT codart)
FROM compras;

Recuperación con la función SUM. Obtener la cantidad total comprada del


artículo “11”.
SELECT SUM (cantidad)
FROM compras
WHERE codart = ‘11’;

Recuperación con la función AVG. Obtener la cantidad promedio de las


compras del artículo 11.

SELECT AVG (cantidad)


FROM compras
WHERE codart = ‘11’;

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 87

Recuperación con la cláusula GROUP BY. Obtener los códigos de todos los
artículos comprados y su cantidad total.

SELECT codart, SUM(cantidad)


FROM compras
GROUP BY codart;

Recuperación con la función MAX o MIN. Obtener todos los artículos con su
precio mayor.
SELECT concepto, MAX(precio)
FROM precios, articulos
WHERE codigo = codart
GROUP BY concepto;

Recuperación utilizando HAVING. Obtener ordenadamente el código de


artículo y la suma de las cantidades compradas para aquellos artículos cuya cantidad
total comprada sea mayor de l00.

SELECT codart, SUM(cantidad)


FROM compras
GROUP BY codart
HAVING SUM (cantidad) > l00
ORDER BY codart; // Colocamos ORDER BY al final

5.4. Operaciones de actualización.

SQL incluye las siguientes operaciones de actualización: UPDATE (modificar),


INSERT (insertar) y DELETE (suprimir).

Actualización de un solo registro. Cambiar el precio al artículo 11 del proveedor


7777, a 12.00.

UPDATE precios
SET precio =12.00
WHERE nifpro = ‘7777’ AND codart = ‘11’;

Actualización de registros múltiples. Aumentar en 10 unidades el precio a todos los


artículos.
UPDATE precios
SET precio = precio + 10;

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 88

Actualización con una subconsulta. A los artículos suministrados por los


proveedores de Málaga, disminuirles el precio en cinco unidades.

UPDATE precios
SET precio = precio - 5
WHERE ’Málaga’ = (SELECT localidad
FROM proveedores
WHERE nif = precios.nifpro);

Actualización de tablas múltiples. Con una proposición UPDATE sólo se puede


actualizar una relación, por lo cual habrá que especificar tantas proposiciones UPDATE
como relaciones se deseen modificar.

Inserción de un solo registro. Insertar el artículo disco duro con el número 33.

INSERT
INTO articulos (codigo, concepto) //Los nombre de los atributos se pueden omitir
VALUES (‘33’, ‘Disco duro’); // siempre que se utilicen todos.

Inserción de múltiples registros. Insertar en la relación ARTI2, que tiene una


columna COD, los códigos de los artículos suministrados por el proveedor 3333.

INSERT INTO arti2(cod)


SELECT codart
FROM precios
WHERE nifpro = ‘3333’;

Supresión de un solo registro. Borrar el artículo disco duro.

DELETE FROM articulos


WHERE concepto = ‘Disco duro’;

Supresión de múltiples registros: Borrar todas las compras.

DELETE FROM compras;

Se han suprimido todas las filas de la relación; está vacía, pero sigue existiendo la
tabla.

I.E.S. Bezmiliana
Lenguaje de Consulta Estructurado: SQL 89

Supresión en relaciones múltiples de registros múltiples. Borrar al proveedor


“Marco”. Si se ha exigido integridad referencial y no se ha establecido el borrado en
cascada, tendríamos que eliminar con anterioridad todos los precios de sus artículos y
las compras que se le hayan realizado. De lo contrario no podríamos eliminarlo.

DELETE FROM compras // Se eliminan las compras de Marco


WHERE nif IN
(SELECT nif
FROM proveedor
WHERE nombre = ‘Marco’);

DELETE FROM precios // Se eliminan los precios de Marco


WHERE nifpro IN
(SELECT nif
FROM proveedor
WHERE nombre = ‘Marco’);

DELETE FROM proveedores // Se eliminan los datos de Marco


WHERE nombre = ‘Marco’;

5.5. Control de acceso.

Para utilizar una base de datos SQL, los usuarios deben identificarse mediante un
password. El administrador de la base de datos puede proporcionar privilegios a los
usuarios con la proposición GRANT (conceder) o retirárselos con REVOKE (revocar).

La proposición GRANT tiene el formato:

GRANT lista-privilegios [ON relación] TO lista-usuarios [WITH GRANT OPTION];

La lista de privilegios puede incluir uno de los siguientes: SELECT, INSERT,


DELETE, UPDATE, EXEC y DRI (permisos declarativos de integridad referencial). Si
se incluye la opción WITH GRANT OPTION, se está autorizando a un usuario a
delegar los privilegios a otros usuarios.

Veamos algún ejemplo: “Autorizar al usuario Luis el privilegio SELECT(consulta)


en la relación PROVEEDORES”.

GRANT SELECT ON proveedores TO Luis;

“Otorgar los seis privilegios al usuario Luis en la relación PROVEEDORES y


concederle el privilegio de dárselo a otros usuarios”.

GRANT ALL PRIVILEGES ON proveedores TO Luis WITH GRANT OPTION;

El formato de REVOKE es:


REVOKE lista-privilegios [ON relación] TO lista-usuarios;

I.E.S. Bezmiliana

También podría gustarte