Este cursillo de SQL se har�
en tres parte, en la primera nos centraremos en la generalidad del
SQL, trataremos con postgreSQL que es un servidor de bases de datos
v�a SQL de dominio p�blico. La segunda parte estudiaremos los comandos
SQL con un mayor detalle. En la tercera parte trataremos comando SQL
con opciones avanzadas as� como funciones del propio gestor PostgreSQL
que pueden ser interesantes para nuestros desarrollos y haremos un
peque�o programa en C.
Introducci�n
Durante esta r�pida introducci�n s�lo hablar� de gestores de base de
datos. Existen otras organizaciones de datos, pero hablar de ellas se
saldr�a del objetivo del curso.
Hasta el momento, el acceso a los datos se hac�a mediante accesos a
entidades que se relacionaban entre s� mediante una ligaduras
definidas en el esquema de la base de datos, eso ten�a una ventaja,
rapidez, pero una gran desventaja, s�lo pod�amos acceder a los datos
mediante una ligadura, ejemplo :
pa�s -> provincias -> municipios
pero nunca :
pa�s -> municipios
Siendo "->" la ligadura.
Si quer�amos realizar esa segunda relaci�n, deb�amos redefinir el esquema y
recompilarlo...
En efecto, en una BD jerarquica, la relaci�n entre las diversas entidades es est�tica y solo modificable mediante modificaci�n del esquema de la base de datos y recompilacion de este ultimo.
La idea b�sica de los gestores de bases de datos relacionales es
justamente ligar los datos en el momento de la petici�n de estos, pero
sin necesitar una ligadura est�tica, sino una identificaci�n que
permita ligar un registro con otro.
Esto que acabo de escribir necesita una Aspirina :-)
Los gestores de base de datos relacionales no precisan unas ligaduras
est�ticas para poder descender una jerarquia de entidades, sino que usan un
c�digo �nico que les identifica para realizar una relaci�n temporanea que es el
resultado de una pregunta al gestor.
Esta identificaci�n no es m�s que el c�digo. Ej: mi n�mero de telefono
no es el :
1234567
sino el :
34 6 1234567
En efecto mi numero de telefono esta identificado por el c�digo pa�s (34),
el c�digo de la provincia (6) y el propio n�mero de aparato (1234567).
- En la entidad paises, el c�digo 34 (Espa�a) es �nico.
- En la entidad provincias, el c�digo 34-6 (Espa�a/Valencia) es �nico.
- En la entidad aparatos, el c�digo 34-6-1234567 (Espa�a/Valencia/mi telefono) es �nico.
Vamos a poner las bases del primer ejemplo que ilustrara lo que acabo de decir.
Todos los municipios tienen un c�digo, pertenecen a una provincia y a un pa�s
Todas las provincias tienen un c�digo y pertenecen a un pa�s
Todos los pa�ses tienen un c�digo
Para conocer todos los municipios de una provincia, relaciono el
municipio con la provincia por el c�digo de pa�s y provincia; para
saber todos los municipio de un pa�s, relaciono el municipio con el
pa�s por el c�digo de pa�s. Estas relaciones son tempor�neas y s�lo
existen durante la realizaci�n de mi pregunta.
Es un poco duro, pero con los primeros ejemplos comprenderemos un poco mejor
este concepto de c�digo y de pertenencia.
Al realizar mi pregunta el gestor me entregara todos los datos que se
relacionen entre s�. Pero �qu� datos me va a dar? Pues la conjunci�n
de los datos de pa�ses y municipios, para cada municipio me repetir�
los datos del pa�s.
Durante la realizaci�n de mi pregunta se ha creado un nueva entidad
que no tiene nombre y que contiene una r�plica de pa�ses y
municipios. Esa nueva entidad, y me repito, desaparecer� una vez
terminada mi lectura.
Antes llam�bamos a los conjuntos de datos, ficheros. Estos se componen
de registros y estos �ltimos se componen de campos. Bien, pues en una
base de datos relacional, un "fichero" se llama tabla, una tabla se
compone de tuplas y una tupla contiene columnas, no es m�s que un
matiz... ;-)
Hay que destacar que ciertos gestores de BD jer�rquicos introduc�an
SQL como lenguaje de acceso, pero esto es anecd�tico. El lenguaje SQL
es casi una exclusividad de los gestores relacionales.
Para ilustrar el curso utilizaremos el gestor relacional PostgreSQL,
aunque no cumple con todas las normas SQL, s� que es m�s que
suficiente para nosotros, y para otros menesteres m�s duros tambi�n.
Voy a explicar muy brevemente el proceso de instalaci�n, dado que el
objetivo de este art�culo es SQL.
Primero bajamos los fuentes de www.postgresql.org, as� como los
parches. Los extraemos (tar zxvf) en un directorio, cd
postgresql-6.3
cd src
./configure --prefix=/el/path/deseado
make all >& make.log &
tail -f make.log
export PATH=$PATH:/el/path/deseado/pgsql/bin
export MANPATH=$MANPATH:/el/path/deseado/pgsql/man
export PGLIB=/el/path/deseado/pgsql/lib
export PGDATA=/el/path/deseado/pgsql/data
initdb
createdb prueba
psql prueba
Welcome to the POSTGRESQL interactive sql monitor:
Please read the file COPYRIGHT for copyright terms of POSTGRESQL
type \? for help on slash commands
type \q to quit
type \g or terminate with semicolon to execute query
You are currently connected to the database: postgres
prueba=>
Este es el prompt de postgres, ahora podemos ejecutar comandos.
prueba=>create table prueba (campo1 varchar(10));
CREATE
prueba=>insert into prueba values ('hello');
INSERT numerito 1
prueba=>commit work;
NOTICE:EndTransactionBlock and not inprogress/abort state
END
prueba=>select * from prueba;
campo1
------
hello
(1 row)
prueba=>drop table prueba;
DROP
prueba=>Ctrl-d
Ya estamos fuera del monitor SQL.
Si no hab�is conseguido compilar e instalar Postgres95 correctamente,
referiros al fichero INSTALL que est� en el directorio de entrada de
la distribuci�n.
Como comentario, vamos a ver como esta construido un servidor de bases de
datos relacional :
- La capa de acceso a los datos
- La capa gestora SQL
- La capa traductora SQL
- La capa de comunicaciones
Como cliente nos conectaremos a la capa 4, le enviaremos los comandos
SQL a esta capa, que los pasar� a la capa 3. �sta hace la traducci�n
del comando y, si no hay errores, env�a el comando a la capa 2. La
capa 2 hace toda la gesti�n del comando con la colaboraci�n de la capa
1: recoge los datos y errores para enviarlos al cliente, v�a la capa
4; y es capaz de mantener un di�logo con el programa cliente para
coordinarse. La capa 1 es la encargada de gestionar correctamente los
datos y controlar los bloqueos y transacciones.
Primer Paso
Vamos a ilustrar con datos lo que antes he explicado, as� que vamos a
crear 3 tablas (o ficheros) :
Fichero: paises.sql
create table paises (cod_pais integer, nombre varchar(30));
insert into paises values (1, 'pais 1');
insert into paises values (2, 'pais 2');
insert into paises values (3, 'pais 3');
commit work;
Fichero: provincias.sql
create table provincias (cod_provincia int,
cod_pais int,
nom_provincia varchar(30));
insert into provincias values (1, 1, 'Provincia 1, Pais 1');
insert into provincias values (2, 1, 'Provincia 2, Pais 1');
insert into provincias values (1, 2, 'Provincia 1, Pais 2');
insert into provincias values (2, 2, 'Provincia 2, Pais 2');
insert into provincias values (1, 3, 'Provincia 1, Pais 3');
insert into provincias values (2, 3, 'Provincia 2, Pais 3');
commit work;
Fichero: municipios.sql
create table municipios (cod_pais int,
cod_provincia int,
cod_municipio int,
nombre_municipio varchar(60));
insert into municipios values (1, 1, 1, 'Municipio 1, Provincia 1, Pais 1');
insert into municipios values (2, 1, 1, 'Municipio 2, Provincia 1, Pais 1');
insert into municipios values (3, 1, 1, 'Municipio 3, Provincia 1, Pais 1');
insert into municipios values (1, 2, 1, 'Municipio 1, Provincia 2, Pais 1');
insert into municipios values (2, 2, 1, 'Municipio 2, Provincia 2, Pais 1');
insert into municipios values (3, 2, 1, 'Municipio 3, Provincia 2, Pais 1');
insert into municipios values (1, 3, 1, 'Municipio 1, Provincia 3, Pais 1');
insert into municipios values (2, 3, 1, 'Municipio 2, Provincia 3, Pais 1');
insert into municipios values (3, 3, 1, 'Municipio 3, Provincia 3, Pais 1');
insert into municipios values (1, 1, 2, 'Municipio 1, Provincia 1, Pais 2');
insert into municipios values (2, 1, 2, 'Municipio 2, Provincia 1, Pais 2');
insert into municipios values (3, 1, 2, 'Municipio 3, Provincia 1, Pais 2');
insert into municipios values (1, 2, 2, 'Municipio 1, Provincia 2, Pais 2');
insert into municipios values (2, 2, 2, 'Municipio 2, Provincia 2, Pais 2');
insert into municipios values (3, 2, 2, 'Municipio 3, Provincia 2, Pais 2');
insert into municipios values (1, 3, 2, 'Municipio 1, Provincia 3, Pais 2');
insert into municipios values (2, 3, 2, 'Municipio 2, Provincia 3, Pais 2');
insert into municipios values (3, 3, 2, 'Municipio 3, Provincia 3, Pais 2');
insert into municipios values (1, 1, 3, 'Municipio 1, Provincia 1, Pais 3');
insert into municipios values (2, 1, 3, 'Municipio 2, Provincia 1, Pais 3');
insert into municipios values (3, 1, 3, 'Municipio 3, Provincia 1, Pais 3');
insert into municipios values (1, 2, 3, 'Municipio 1, Provincia 2, Pais 3');
insert into municipios values (2, 2, 3, 'Municipio 2, Provincia 2, Pais 3');
insert into municipios values (3, 2, 3, 'Municipio 3, Provincia 2, Pais 3');
insert into municipios values (1, 3, 3, 'Municipio 1, Provincia 3, Pais 3');
insert into municipios values (2, 3, 3, 'Municipio 2, Provincia 3, Pais 3');
insert into municipios values (3, 3, 3, 'Municipio 3, Provincia 3, Pais 3');
commit work;
Para ejecutar dentro del psql unos comandos sql de un fichero, hacer :
\i nombre_del_fichero
Tamb�n podemos hacer un cortar y pegar desde estas p�ginas.
Vamos a ver qu� municipios tenemos :
select * from municipios;
cod_pais|cod_provincia|cod_municipio|nombre_municpio
--------+-------------+-------------+--------------------------------
1| 1| 1|Municipio 1, Provincia 1, Pais 1
2| 1| 1|Municipio 2, Provincia 1, Pais 1
3| 1| 1|Municipio 3, Provincia 1, Pais 1
1| 2| 1|Municipio 1, Provincia 2, Pais 1
2| 2| 1|Municipio 2, Provincia 2, Pais 1
3| 2| 1|Municipio 3, Provincia 2, Pais 1
1| 3| 1|Municipio 1, Provincia 3, Pais 1
2| 3| 1|Municipio 2, Provincia 3, Pais 1
3| 3| 1|Municipio 3, Provincia 3, Pais 1
1| 1| 2|Municipio 1, Provincia 1, Pais 2
2| 1| 2|Municipio 2, Provincia 1, Pais 2
3| 1| 2|Municipio 3, Provincia 1, Pais 2
1| 2| 2|Municipio 1, Provincia 2, Pais 2
2| 2| 2|Municipio 2, Provincia 2, Pais 2
3| 2| 2|Municipio 3, Provincia 2, Pais 2
1| 3| 2|Municipio 1, Provincia 3, Pais 2
2| 3| 2|Municipio 2, Provincia 3, Pais 2
3| 3| 2|Municipio 3, Provincia 3, Pais 2
1| 1| 3|Municipio 1, Provincia 1, Pais 3
2| 1| 3|Municipio 2, Provincia 1, Pais 3
3| 1| 3|Municipio 3, Provincia 1, Pais 3
1| 2| 3|Municipio 1, Provincia 2, Pais 3
2| 2| 3|Municipio 2, Provincia 2, Pais 3
3| 2| 3|Municipio 3, Provincia 2, Pais 3
1| 3| 3|Municipio 1, Provincia 3, Pais 3
2| 3| 3|Municipio 2, Provincia 3, Pais 3
3| 3| 3|Municipio 3, Provincia 3, Pais 3
(27 rows)
prueba=>
Bien tenemos 27 tuplas y el pgsql est� esperando otro comando,
vamos a ver este :
select * from paises, municipios
cod_pais|nombre|cod_provincia|cod_pais|nom_provincia
--------+------+-------------+--------+-------------------
1|pais 1| 1| 1|Provincia 1, Pais 1
2|pais 2| 1| 1|Provincia 1, Pais 1
3|pais 3| 1| 1|Provincia 1, Pais 1
1|pais 1| 2| 1|Provincia 2, Pais 1
2|pais 2| 2| 1|Provincia 2, Pais 1
3|pais 3| 2| 1|Provincia 2, Pais 1
1|pais 1| 1| 2|Provincia 1, Pais 2
2|pais 2| 1| 2|Provincia 1, Pais 2
3|pais 3| 1| 2|Provincia 1, Pais 2
1|pais 1| 2| 2|Provincia 2, Pais 2
2|pais 2| 2| 2|Provincia 2, Pais 2
3|pais 3| 2| 2|Provincia 2, Pais 2
1|pais 1| 1| 3|Provincia 1, Pais 3
2|pais 2| 1| 3|Provincia 1, Pais 3
3|pais 3| 1| 3|Provincia 1, Pais 3
1|pais 1| 2| 3|Provincia 2, Pais 3
2|pais 2| 2| 3|Provincia 2, Pais 3
3|pais 3| 2| 3|Provincia 2, Pais 3
(18 rows)
���18 tuplas ??? Vamos a ver, hemos insertado 3 pa�ses, y 6
provincias, todas ellas identificadas en un pa�s. �C�mo es posible
que nos saque 18 tuplas?
En este �ltimo comando hemos, realizado una uni�n de dos tablas, hemos
relacionado la tabla de pa�ses con la de municipios, como no le hemos
dado ninguna regla de uni�n, nos ha devuelto TODAS las tuplas de pa�ses
relacionadas con TODAS las tuplas de provincias, es decir 3 tuplas de
pa�ses por 6 de provincias total 18 tuplas, este resultado es
totalmente il�gico e in�til, ahora mejor hacer:
select * from paises, provincias
where paises.cod_pais = provincias.cod_pais;
cod_pais|nombre|cod_provincia|cod_pais|nom_provincia
--------+------+-------------+--------+-------------------
1|pais 1| 1| 1|Provincia 1, Pais 1
1|pais 1| 2| 1|Provincia 2, Pais 1
2|pais 2| 1| 2|Provincia 1, Pais 2
2|pais 2| 2| 2|Provincia 2, Pais 2
3|pais 3| 1| 3|Provincia 1, Pais 3
3|pais 3| 2| 3|Provincia 2, Pais 3
(6 rows)
Bueno, esto ya empieza a ser m�s razonable. �Seis tuplas, correcto?
Si tenemos seis municipios y cada municipio est� en un pa�s. Es normal
que me d� un n�mero de tuplas igual al de municipios, dado que pa�ses
es un calificativo de municipios. Acabamos de relacionar la tabla de
pa�ses con la tabla de provincias mediante el c�digo de pa�s.
Recordemos que pa�ses tiene c�digo y que provincias tiene el c�digo
pa�s al que pertenece.
�Porqu� paises.cod_pais = provincias.cod_pais ?
C�digo de pa�s en la tabla de pa�ses se llama cod_pais y en
la tabla de provincias tambi�n, entonces:
cod_pais = cod_pais
es il�gico, el interprete nunca sabr�a como manejar eso y nos dar�a un
error:
select * from paises, provincias
where cod_pais = cod_pais;
ERROR: Column cod_pais is ambiguous
Esto ahora podemos dar alias a las columnas :
select * from paises a, provincias b
where a.cod_pais = b.cod_pais;
cod_pais|nombre|cod_provincia|cod_pais|nom_provincia
--------+------+-------------+--------+-------------------
1|pais 1| 1| 1|Provincia 1, Pais 1
1|pais 1| 2| 1|Provincia 2, Pais 1
2|pais 2| 1| 2|Provincia 1, Pais 2
2|pais 2| 2| 2|Provincia 2, Pais 2
3|pais 3| 1| 3|Provincia 1, Pais 3
3|pais 3| 2| 3|Provincia 2, Pais 3
(6 rows)
�Qu� nos devuelve el gestor?: cod_pais, nombre,
cod_provincia, cod_pais y nom_provincia.
Como hemos pedido "select * from pa�ses, provincias", el
* es un comod�n que indica que queremos TODO, por eso nos
devuelve las dos columnas de pa�ses y las 3 de provincias, ahora
queremos algo m�s expl�cito
select a.cod_pais, cod_provincia, nombre, nom_provincia
from paises a, provincias b
where a.cod_pais = b.cod_pais;
cod_pais|cod_provincia|nombre|nom_provincia
--------+-------------+------+-------------------
1| 1|pais 1|Provincia 1, Pais 1
1| 2|pais 1|Provincia 2, Pais 1
2| 1|pais 2|Provincia 1, Pais 2
2| 2|pais 2|Provincia 2, Pais 2
3| 1|pais 3|Provincia 1, Pais 3
3| 2|pais 3|Provincia 2, Pais 3
(6 rows)
En este comando hemos especificado que queremos, concretamente el
c�digo del pa�s, el c�digo de la provincia, el nombre del pa�s y el
nombre de la provincia. Fijaros que ciertos nombres de columna est�n
cualificados (a.cod_pais) mientras que otros no (nom_provincia), esto
es debido a que cod_pais est� repetido en ambas tablas mientras que
nom_provincia s�lo se encuentra en provincias. Los nombres de columnas
�nicos no hace falta cualificarlos.
Complicamos un poco m�s:
select a.cod_pais, cod_provincia, nombre, nom_provincia
from paises a, provincias b
where a.cod_pais = b.cod_pais
and a.cod_pais = 3;
cod_pais|cod_provincia|nombre|nom_provincia
--------+-------------+------+-------------------
3| 1|pais 3|Provincia 1, Pais 3
3| 2|pais 3|Provincia 2, Pais 3
(2 rows)
Esta vez hemos limitado la busqueda a los que s�lo tienen como c�digo
pa�s el 3.
Funciones
A t�tulo de ejemplo vamos a ver la funci�n de recuento de tuplas,
count().
select count(*) from municipios;
count
-----
27
(1 row)
Nos devuelve el n�mero de tuplas que tiene la tabla de municipios,
ahora:
select cod_pais, count(*) from municipios
group by cod_pais;
cod_pais|count
--------+-----
1| 9
2| 9
3| 9
(3 rows)
Nos devuelve el n�mero de tuplas que tienen el MISMO c�digo de pa�s,
por eso usamos el discriminante cod_pais.
Para ilustrarlo mejor:
select nombre, count(*) from paises a, municipios b
where a.cod_pais = b.cod_pais
group by nombre;
nombre|count
------+-----
pais 1| 9
pais 2| 9
pais 3| 9
(3 rows)
Continuamos teniendo nuestras tres tuplas pero un pel�n m�s claras.
Bueno esto era una mera introducci�n, una forma de ponernos en calor :-)
Revisi�n de Conceptos
Hemos visto unos conceptos muy b�sicos de SQL. Lo m�s importante es el
concepto b�sico de SQL. Con �ste se deja de trabajar sobre datos
concretos para hacerlo con entidades de datos. Una entidad de datos es
el concepto abstracto de la base de datos. En resumen "DE TODO LO QUE
TIENES S�LO QUIERO UNA PARTE".
Hemos visto varios comandos:
CREATE TABLE | Este comando permite crear una
tabla con sus columnas. |
DROP TABLE | Borrar� la tabla. |
SELECT |
Este comando es la base de SQL, es el que permite crear una tabla
temporal con los datos que necesitamos. Este comando puede contener
funciones o predicados complejos, as� como sub_selects:
select count(*) from municipios
where cod_pais in (select cod_pais from paises);
count
-----
27
(1 row)
|
COMMIT WORK | Este es otro comando muy
importante. Este comando indica al gestor que TODAS las modificaciones
desde el BEGIN WORK pueden hacerse definitivas. En nuestro gestor lo
que marca el inicio de una transacci�n es el BEGIN WORK, en otros
gestores el inicio de una transacci�n la marca el primer comando que
modifica algo en la base de datos. En postgreSQL todo comando que
modifique datos lo har� directamente, si previamente no se ha
realizado un BEGIN WORK.
NOTA: los comandos que modifican el esquema de la base de datos
realizan un COMMIT WORK, como tal si se ha abierto una transacci�n y
se realiza un comando que modifique el esquema, nuestra transacci�n se
vera cerrada, con la imposibilidad de realizar un ROLLBACK WORK.
Mientras un usuario tenga una transacci�n activa, este podr� decidir
como los dem�s usuarios tendr�n acceso a sus datos :
Datos modificados
Datos originales a la transacci�n
Bloqueo de acceso
|
COMMIT WORK | Cierra una transacci�n dejando
las modificaciones como definitivas mientras que ROLLBACK WORK
devuelve los datos al estado anterior al inicio de la
transacci�n. |
El concepto de transacci�n es muy importante, dado que permite la
vuelta al estado anterior en caso de haberse producido un error.
Ahora probemos ese concepto, empezamos por un "rollback work"
para cerrar cualquier transacci�n abierta:
select * from paises;
cod_pais|nombre
--------+------
1|pais 1
2|pais 2
3|pais 3
(3 rows)
Tenemos tres tuplas.
begin work;
Inicio la transacci�n
insert into paises values (5, 'pais de mentira');
Inserto una tupla.
select * from paises;
cod_pais|nombre
--------+---------------
1|pais 1
2|pais 2
3|pais 3
5|pais de mentira
(4 rows)
Verificamos que est�n todas y lo est�n.
rollback work;
Abandonamos la transacci�n.
select * from paises;
cod_pais|nombre
--------+------
1|pais 1
2|pais 2
3|pais 3
(3 rows)
Todo est� como antes.
INSERT |
Tambi�n lo hemos visto, este comando sirve para meter datos en una
tabla. |
CREATE TABLE | Otro comando muy importante, el
de creaci�n de la tabla y sus columnas, vamos a ver que tipos de datos
podemos tratar :
char(rango): |
Dato alfanum�rico de longitud fija de 30 bytes.
|
varchar(rango): |
Dato alfanum�rico de longitud variable de hasta 30 bytes. |
int2: | Dato
num�rico binario de 2 bytes : 2**-15 hasta 2**15
|
int4: | Dato
num�rico binario de 4 bytes : 2**-31 - 2**31
|
money: |
Dato num�rico de coma fija, ej: money(6,3), dato num�rico de seis
d�gitos de los cuales 3 son decimales (3 enteros y tres decimales).
|
time: | Dato
de tiempo que contendr� horas, minutos, segundos, cent�simas,
HH:MM:SS:CCC
|
date: | Dato
de fecha que contendr� a�o, mes, d�a, AAAA/MM/DD
|
timestamp: |
Dato fecha y hora, AAAA/MM/DD:HH:MM:SS:CCC
|
float(n): |
Dato real de precisi�n
|
float3: |
Dato real de doble precisi�n
|
Las definiciones de los tipos de datos son propias a cada gestor,
existe una normalizaci�n de SQL (la �ltima es la ANSI/92 o SQL/3) que
define unos tipos de datos con sus caracter�sticas, como tal en este
cursillo s�lo veremos unos cuantos propios a PostgreSQL.
|
DELETE | Con este borraremos tuplas de una tabla
|
UPDATE | Con este modificaremos columnas de tuplas de una tabla
|
Resumen
Aunque parezca un tanto revuelto, nos hemos introducido al SQL y
tenemos instalado un gestor de bases de datos relacionales.
SQL nos permite construir una capa de abstracci�n a los datos y
manejar estos seg�n lo necesitemos.
De la forma que hemos visto esto, cabe una pregunta :
�C�mo aplico SQL a una aplicaci�n?
La respuesta vendr� poco a poco y en la tercera entrega haremos una
peque�a aplicaci�n en C.
|