Mantenga en mente la sintaxis
CREATE RULE rule_name AS ON event
TO object [WHERE rule_qualification]
DO [INSTEAD] [action | (actions) | NOTHING]; |
En lo que sigue, "las reglas de update" muestran reglas que est�n definidas
ON INSERT, UPDATE o DELETE.
Update toma las reglas aplicadas por el sistema de reglas cuando la
relaci�n resultado y el tipo de comando de un �rbol de traducci�n son
iguales al objeto y el acontecimiento dado en el comando CREATE RULE. Para
reglas de update, el sistema de reglas crea una lista de �rboles de
traducci�n. Inicialmente la lista de �rboles de traducci�n est� vac�a.
Puede haber cero (palabra clave NOTHING), una o m�ltiples acciones. Para
simplificar, veremos una regla con una acci�n. Esta regla puede tener una
cualificaci�n o no y puede ser INSTEAD o no.
�Qu� es una cualificaci�n de una regla? Es una restricci�n que se dice
cu�ndo las acciones de una regla se deber�an realizar y cu�ndo no. Esta
cualficaci�n s�lo se puede referir a las pseudo-relaciones NEW y/o OLD, que
b�sicamente son la relaci�n dada como objeto (pero con unas caracter�sticas
especiales).
De este modo tenemos cuatro casos que producen los siguientes �rboles de
traducci�n para una regla de una acci�n:
Sin cualificaci�n ni INSTEAD:
Sin cualificaci�n pero con INSTEAD:
Se da cualificaci�n y no se da INSTEAD:
Se da cualificaci�n y se da INSTEAD:
El �rbol de traducci�n de la acci�n de la regla a la que se han
a�adido la cualificaci�n de la regla y la cualificaci�n de los
�rboles de traducci�n originales.
El �rbol de traducci�n original al que se le ha a�adido la
cualificaci�n de la regla negada.
Finalmente, si la regla no es INSTEAD, el �rbol de traducci�n original sin
cambiar se a�ade a la lista. Puesto que s�lo las reglas INSTEAD
cualificadas se a�aden al �rbol de traducci�n original, terminamos con un
m�ximo total de dos �rboles de traducci�n para una regla con una acci�n.
Los �rboles de traducci�n generados a partir de las acciones de las reglas
se colocan en el sistema de reescritura de nuevo, y puede ser que otras
reglas aplicadas resulten en m�s o menos �rboles de traducci�n.
De este modo, los �rboles de traducci�n de las acciones de las reglas
deber�an tener bien otro tipo de comando, bien otra relaci�n resultado. De
otro modo, este proceso recursivo terminar�a en un bucle. Hay un l�mite de
recursiones compiladas actualmente de 10 iteraciones. Si tras 10
iteraciones a�n sigue habiendo reglas de update para aplicar, el sistema de
reglas asumir� que se ha producido un bucle entre muchas definiciones de
reglas y aborta la transacci�n.
Los �rboles de traducci�n encontrados en las acciones del cat�logo de
sistema pg_rewrite son s�lo plantillas. Una vez que
ellos pueden hacer referencia a las entradas de tabla de rango para NEW u
OLD, algunas sustituciones habr�n sido hechas antes de ser utilizadas. Para
cualquier referencia a NEW, la lista objetivo de la query original se
revisa busando una entrada correspondiente. si se encuentra, esas entradas
de la expresi�n se sit�an en la referencia. De otro modo, NEW se mantiene
igual que OLD. Cualquier referencia a OLD se reemplaza por una referencia a
la entrada de la tabla de rango que es la relaci�n resultado.
Queremos tracear los cambios en la columna sl_avail de la relaci�n
shoelace_data. Para ello, crearemos una tabla de log,
y una regla que escriba las entradas cada vez que se realice una UPDATE
sobre shoelace_data.
CREATE TABLE shoelace_log (
sl_name char(10), -- shoelace changed
sl_avail integer, -- new available value
log_who name, -- who did it
log_when datetime -- when
);
CREATE RULE log_shoelace AS ON UPDATE TO shoelace_data
WHERE NEW.sl_avail != OLD.sl_avail
DO INSERT INTO shoelace_log VALUES (
NEW.sl_name,
NEW.sl_avail,
getpgusername(),
'now'::text
); |
Un detalle interesante es la caracterizaci�n de 'now' en la reglas de la
acci�n INSERT para teclear texto. Sin ello, el traductor ver�a en el
momento del CREATE RULE, que el tipo objetivo en
shoelace_log es un dato de tipo fecha, e intenta hacer
una constante de �l... con �xito. De ese modo, se almacenar�a un valor
constante en la acci�n de la regla y todas las entradas del log tendr�an la
hora de la instrucci�n CREATE RULE. No es eso exactamente lo que queremos.
La caracterizaci�n lleva al traductor a construir un "fecha-hora" que ser�
evaluada en el momento de la ejecuci�n (datetime('now'::text)).
Ahora Al hace
al_bundy=> UPDATE shoelace_data SET sl_avail = 6
al_bundy-> WHERE sl_name = 'sl7'; |
y nosotros miramos en la tabla de log.
al_bundy=> SELECT * FROM shoelace_log;
sl_name |sl_avail|log_who|log_when
----------+--------+-------+--------------------------------
sl7 | 6|Al |Tue Oct 20 16:14:45 1998 MET DST
(1 row) |
Que es justo lo que nosotros esper�bamos. Veamos qu� ha ocurrido en la
sombra. El traductor cre� un �rbol de traducci�n (esta vez la parte del
�rbol de traducci�n original est� resaltado porque la base de las operaci�n
es es la acci�n de la regla para las reglas de update)
UPDATE shoelace_data SET sl_avail = 6
FROM shoelace_data shoelace_data
WHERE bpchareq(shoelace_data.sl_name, 'sl7'); |
Hay una regla para 'log_shoelace' que es ON UPDATE con la expresi�n de
cualificaci�n de la regla:
int4ne(NEW.sl_avail, OLD.sl_avail) |
y una acci�n
INSERT INTO shoelace_log SELECT
*NEW*.sl_name, *NEW*.sl_avail,
getpgusername(), datetime('now'::text)
FROM shoelace_data *NEW*, shoelace_data *OLD*,
shoelace_log shoelace_log; |
No detallaremos la salida de la vista del sistema pg_rules. Especialmente
manipula la siutaci�n de que aqu� s�lo se haga referencia a NEW y OLD en la
INSERT, y las salidas del formato de VALUES de INSERT. De hecho, no hay
diferencia entre una INSERT ... VALUES y una INSERT ... SELECT al nivel del
�rbol de traducci�n. Ambos tienen tablas de rango, listas objetivo, pueden
tener cualificaci�n, etc. El optimizador decide m�s tarde si crear un plan
de ejecuci�n de tio resultado, barrido secuencial, barrido de �ndice, join
o cualquier otro para ese �rbol de traducci�n. Si no hay referencias en
entradas de la tabla de rango previas al �rbol de traducci�n, �ste se
convierte en un plan de ejecuci�n (la versi�n INSERT ... VALUES). La acci�n
de las reglas anterior puede ciertamente resultar en ambas variantes.
La regla es una regla no-INSTEAD cualificada, de modo que el sistema de
reglas deber� devolver dos �rboles de traducci�n. La acci�n de la regla
modificada y el �rbol de traducci�n original. En el primer paso, la tabla
de rango de la query original est� incorporada al �rbol de traducci�n de la
acci�n de las reglas. Esto da como resultado
INSERT INTO shoelace_log SELECT
*NEW*.sl_name, *NEW*.sl_avai,
getpgusername(), datetime('now'::text)
FROM shoelace_data shoelace_data,
shoelace_data *NEW*,
shoelace_data *OLD*,
shoelace_log shoelace_log; |
En el segundo paso, se a�ade la cualificaci�n de la regla, de modo que el
resultado se restringe a las filas en las que sl_avail cambie.
INSERT INTO shoelace_log SELECT
*NEW*.sl_name, *NEW*.sl_avai,
getpgusername(), datetime('now'::text)
FROM shoelace_data shoelace_data, shoelace_data *NEW*,
shoelace_data *OLD*, shoelace_log shoelace_log
WHERE int4ne(*NEW*.sl_avail, *OLD*.sl_avail); |
En el tercer paso, se a�ade la cualificaci�n de los �rboles de traducci�n
originales, restringiendo el juego de resultados m�s a�n, a s�lo las filas
tocadas por el �rbol de traducci�n original.
INSERT INTO shoelace_log SELECT
*NEW*.sl_name, *NEW*.sl_avai,
getpgusername(), datetime('now'::text)
FROM shoelace_data shoelace_data, shoelace_data *NEW*,
shoelace_data *OLD*, shoelace_log shoelace_log
WHERE int4ne(*NEW*.sl_avail, *OLD*.sl_avail)
AND bpchareq(shoelace_data.sl_name, 'sl7'); |
En el paso cuatro se sustituyen las referencias NEW por las entradas de la
lista objetivo del �rbol de traducci�n original o con las referencias a
variables correspondientes de la relaci�n resultado.
INSERT INTO shoelace_log SELECT
shoelace_data.sl_name,
6,
getpgusername(), datetime('now'::text)
FROM shoelace_data shoelace_data, shoelace_data *NEW*,
shoelace_data *OLD*, shoelace_log shoelace_log
WHERE int4ne(6, *OLD*.sl_avail)
AND bpchareq(shoelace_data.sl_name, 'sl7'); |
El paso 5 reemplaza las referencias OLD por referencias en la relaci�n
resultado.
INSERT INTO shoelace_log SELECT
shoelace_data.sl_name, 6,
getpgusername(), datetime('now'::text)
FROM shoelace_data shoelace_data, shoelace_data *NEW*,
shoelace_data *OLD*, shoelace_log shoelace_log
WHERE int4ne(6, shoelace_data.sl_avail)
AND bpchareq(shoelace_data.sl_name, 'sl7'); |
Y esto es. De modo que la m�xima reducci�n de la salida del sistema de
reglas es una lista de dos �rboles de traducci�n que son lo mismo que las
instrucciones:
INSERT INTO shoelace_log SELECT
shoelace_data.sl_name, 6,
getpgusername(), 'now'
FROM shoelace_data
WHERE 6 != shoelace_data.sl_avail
AND shoelace_data.sl_name = 'sl7';
UPDATE shoelace_data SET sl_avail = 6
WHERE sl_name = 'sl7'; |
Estas con ejecutadas en este orden y eso es exactamente lo que la regla
define. Las sustituciones y las cualificaciones a�adidas aseguran que si la
query original fuese una
UPDATE shoelace_data SET sl_color = 'green'
WHERE sl_name = 'sl7'; |
no se habr�a escrito ninguna entrada en la tabla de log, ya que esta vez el
�rbol de traducci�n original no contiene una entrada de la lista objetivo
para sl_avail, de modo que NEW.sl_avail ser� reemplazada por
shoelace_data.sl_avail resultando en la query adicional
INSERT INTO shoelace_log SELECT
shoelace_data.sl_name,
shoelace_data.sl_avail,
getpgusername(), 'now'
FROM shoelace_data
WHERE shoelace_data.sl_avail !=
shoelace_data.sl_avail
AND shoelace_data.sl_name = 'sl7'; |
cuya cualificaci�n nunca ser� cierta. Una vez que no hay diferencias a
nivel de �rbol de traducci�n entre una INSERT ... SELECT, y una INSERT ...
VALUES, trabajar� tambi�n si la query original modificaba multiples
columnas. De modo que si Al hubiese pedido el comando
UPDATE shoelace_data SET sl_avail = 0
WHERE sl_color = 'black'; |
ser�n actualizadas cuatro filas (sl1, sl2, sl3 y sl4). Pero sl3 ya tiene
sl_avail = 0. Esta vez, la cualificaci�n de los �rboles de traducci�n
originales es diferente y como resultado tenemos el �rbol de traducci�n
adicional
INSERT INTO shoelace_log SELECT
shoelace_data.sl_name, 0,
getpgusername(), 'now'
FROM shoelace_data
WHERE 0 != shoelace_data.sl_avail
AND shoelace_data.sl_color = 'black'; |
Este �rbol de traducci�n seguramente insertar� tres nuevas entradas de la
tabla de log. Y eso es absol�tamente correcto.
Es importante recordar que el �rbol de traducci�n original se ejecuta el
�ltimo. El "agente de tr�fico" de Postgres
incrementa el contador de comandos entre la ejecuci�n de los dos �rboles de
traducci�n, de modo que el segundo puede ver cambios realizados por el
primero. Si la UPDATE hubiera sido ejecutada primero, todas las filas
estar�an ya a 0, de modo que la INSERT del logging no habr�a encontrado
ninguna fila para las que shoelace_data.sl_avail != 0: no habr�a dejado
ning�n rastro.
Una forma sencilla de proteger las relaciones vista de la mencionada
posibilidad de que alguien pueda INSERT, UPDATE y DELETE datos invisibles
es permitir a sus �rboles de traducci�n recorrerlas de nuevo.
Creamos las reglas
CREATE RULE shoe_ins_protect AS ON INSERT TO shoe
DO INSTEAD NOTHING;
CREATE RULE shoe_upd_protect AS ON UPDATE TO shoe
DO INSTEAD NOTHING;
CREATE RULE shoe_del_protect AS ON DELETE TO shoe
DO INSTEAD NOTHING; |
Si Al ahora intenta hacer cualquiera de estas operaciones en la relaci�n
vista
shoe, el sistema de reglas aplicar� las reglas.
Una vez que las reglas no tiene acciones y son INSTEAD, la lista resultante
de �rboles de traducci�n estar� vac�a, y la query no devolver� nada, debido
a que no hay nada para ser optimizado o ejecutado tras la actuaci�n del
sistema de reglas.
| Nota |
---|
| Este hecho deber�a irritar a las aplicaciones cliente, ya que no ocurre
absol�tamente nada en la base de datos, y por ello, el servidor no devuelve
nada para la query. Ni siquiera un PGRES_EMPTY_QUERY o similar ser�
utilizable en libpq. En psql, no ocurre nada. Esto deber�a cambiar en el
futuro.
|
Una forma m�s sofisticada de utilizar el sistema de reglas es crear reglas
que reescriban el �rbol de traducci�n en uno que haga la operaci�n correcta
en las tablas reales. Para hacer esto en la vista
shoelace, crearemos las siguientes reglas:
CREATE RULE shoelace_ins AS ON INSERT TO shoelace
DO INSTEAD
INSERT INTO shoelace_data VALUES (
NEW.sl_name,
NEW.sl_avail,
NEW.sl_color,
NEW.sl_len,
NEW.sl_unit);
CREATE RULE shoelace_upd AS ON UPDATE TO shoelace
DO INSTEAD
UPDATE shoelace_data SET
sl_name = NEW.sl_name,
sl_avail = NEW.sl_avail,
sl_color = NEW.sl_color,
sl_len = NEW.sl_len,
sl_unit = NEW.sl_unit
WHERE sl_name = OLD.sl_name;
CREATE RULE shoelace_del AS ON DELETE TO shoelace
DO INSTEAD
DELETE FROM shoelace_data
WHERE sl_name = OLD.sl_name; |
Ahora llega un paquete de cordones de zapatos a la tienda de Al, y el tiene
una gran lista de art�culos. Al no es particularmente bueno haciendo
c�lculos, y no lo queremos actualizando manualmente la vista shoelace. En
su lugar, creamos dos tablas peque�as, una donde �l pueda insertar los
datos de la lista de art�culos, y otra con un truco especial.
Los comandos CREATE completos son:
CREATE TABLE shoelace_arrive (
arr_name char(10),
arr_quant integer
);
CREATE TABLE shoelace_ok (
ok_name char(10),
ok_quant integer
);
CREATE RULE shoelace_ok_ins AS ON INSERT TO shoelace_ok
DO INSTEAD
UPDATE shoelace SET
sl_avail = sl_avail + NEW.ok_quant
WHERE sl_name = NEW.ok_name; |
ahora Al puede sentarse y hacer algo como:
al_bundy=> SELECT * FROM shoelace_arrive;
arr_name |arr_quant
----------+---------
sl3 | 10
sl6 | 20
sl8 | 20
(3 rows) |
Que es exactametne lo que hab�a en la lista de art�culos. Daremos una
r�pida mirada en los datos actuales.
al_bundy=> SELECT * FROM shoelace ORDER BY sl_name;
sl_name |sl_avail|sl_color |sl_len|sl_unit |sl_len_cm
----------+--------+----------+------+--------+---------
sl1 | 5|black | 80|cm | 80
sl2 | 6|black | 100|cm | 100
sl7 | 6|brown | 60|cm | 60
sl3 | 0|black | 35|inch | 88.9
sl4 | 8|black | 40|inch | 101.6
sl8 | 1|brown | 40|inch | 101.6
sl5 | 4|brown | 1|m | 100
sl6 | 0|brown | 0.9|m | 90
(8 rows) |
trasladamos los cordones recien llegados:
al_bundy=> INSERT INTO shoelace_ok SELECT * FROM shoelace_arrive; |
y comprobamos los resultados:
al_bundy=> SELECT * FROM shoelace ORDER BY sl_name;
sl_name |sl_avail|sl_color |sl_len|sl_unit |sl_len_cm
----------+--------+----------+------+--------+---------
sl1 | 5|black | 80|cm | 80
sl2 | 6|black | 100|cm | 100
sl7 | 6|brown | 60|cm | 60
sl4 | 8|black | 40|inch | 101.6
sl3 | 10|black | 35|inch | 88.9
sl8 | 21|brown | 40|inch | 101.6
sl5 | 4|brown | 1|m | 100
sl6 | 20|brown | 0.9|m | 90
(8 rows)
al_bundy=> SELECT * FROM shoelace_log;
sl_name |sl_avail|log_who|log_when
----------+--------+-------+--------------------------------
sl7 | 6|Al |Tue Oct 20 19:14:45 1998 MET DST
sl3 | 10|Al |Tue Oct 20 19:25:16 1998 MET DST
sl6 | 20|Al |Tue Oct 20 19:25:16 1998 MET DST
sl8 | 21|Al |Tue Oct 20 19:25:16 1998 MET DST
(4 rows) |
Esta es una larga v�a desde la primera INSERT ... SELECT a estos
resultados. Y su descripci�n ser� la �ltima en este documento (pero no el
�ltimo ejemplo :-). Primero estaba la salida de los traductores:
INSERT INTO shoelace_ok SELECT
shoelace_arrive.arr_name, shoelace_arrive.arr_quant
FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok; |
Ahora se aplica la primera regla 'shoelace_ok_in' y se vuelve:
UPDATE shoelace SET
sl_avail = int4pl(shoelace.sl_avail, shoelace_arrive.arr_quant)
FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok,
shoelace_ok *OLD*, shoelace_ok *NEW*,
shoelace shoelace
WHERE bpchareq(shoelace.sl_name, showlace_arrive.arr_name); |
y lanza otra vez la INSERT original sobre
shoelace_ok.
Esta query reescrita se pasa al sistema de reglas de nuevo, y la aplicaci�n
de la segunda regla 'shoelace_upd' produce
UPDATE shoelace_data SET
sl_name = shoelace.sl_name,
sl_avail = int4pl(shoelace.sl_avail, shoelace_arrive.arr_quant),
sl_color = shoelace.sl_color,
sl_len = shoelace.sl_len,
sl_unit = shoelace.sl_unit
FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok,
shoelace_ok *OLD*, shoelace_ok *NEW*,
shoelace shoelace, shoelace *OLD*,
shoelace *NEW*, shoelace_data showlace_data
WHERE bpchareq(shoelace.sl_name, showlace_arrive.arr_name)
AND bpchareq(shoelace_data.sl_name, shoelace.sl_name); |
Otra vez es una regla INSTEAD, y el �rbol de traducci�n anterior se
deshecha. N�tese que esta query a�n utiliza la vista
shoelace. Pero el sistema de reglas no ha terminado
con esta vuelta, de modo que contin�a y aplica la regla '_RETshoelace',
produciendo
UPDATE shoelace_data SET
sl_name = s.sl_name,
sl_avail = int4pl(s.sl_avail, shoelace_arrive.arr_quant),
sl_color = s.sl_color,
sl_len = s.sl_len,
sl_unit = s.sl_unit
FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok,
shoelace_ok *OLD*, shoelace_ok *NEW*,
shoelace shoelace, shoelace *OLD*,
shoelace *NEW*, shoelace_data showlace_data,
shoelace *OLD*, shoelace *NEW*,
shoelace_data s, unit u
WHERE bpchareq(s.sl_name, showlace_arrive.arr_name)
AND bpchareq(shoelace_data.sl_name, s.sl_name); |
De nuevo se ha aplicado una regla de update y por ello vuelve a girar la
rueda, y llegamos a la ronda de reescritura n�mero 3. Esta vez, se aplica
la regla 'log_shoelace', que produce el �rbol de traducci�n extra
INSERT INTO shoelace_log SELECT
s.sl_name,
int4pl(s.sl_avail, shoelace_arrive.arr_quant),
getpgusername(),
datetime('now'::text)
FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok,
shoelace_ok *OLD*, shoelace_ok *NEW*,
shoelace shoelace, shoelace *OLD*,
shoelace *NEW*, shoelace_data showlace_data,
shoelace *OLD*, shoelace *NEW*,
shoelace_data s, unit u,
shoelace_data *OLD*, shoelace_data *NEW*
shoelace_log shoelace_log
WHERE bpchareq(s.sl_name, showlace_arrive.arr_name)
AND bpchareq(shoelace_data.sl_name, s.sl_name);
AND int4ne(int4pl(s.sl_avail, shoelace_arrive.arr_quant),
s.sl_avail); |
Tras de lo cual, el sistema de reglas se desconecta y devuelve los �rboles
de traducci�n generados. De esta forma, terminamos con dos �rboles de
traducci�n finales que son iguales a las instrucciones de
SQL
INSERT INTO shoelace_log SELECT
s.sl_name,
s.sl_avail + shoelace_arrive.arr_quant,
getpgusername(),
'now'
FROM shoelace_arrive shoelace_arrive, shoelace_data shoelace_data,
shoelace_data s
WHERE s.sl_name = shoelace_arrive.arr_name
AND shoelace_data.sl_name = s.sl_name
AND s.sl_avail + shoelace_arrive.arr_quant != s.sl_avail;
UPDATE shoelace_data SET
sl_avail = shoelace_data.sl_avail + shoelace_arrive.arr_quant
FROM shoelace_arrive shoelace_arrive,
shoelace_data shoelace_data,
shoelace_data s
WHERE s.sl_name = shoelace_arrive.sl_name
AND shoelace_data.sl_name = s.sl_name; |
El resultado es que los datos vienen de una relaci�n, se insertan en otra,
cambian por actualizaciones una tercera, cambian por actualizaciones una
cuarta, m�s registran esa actualizaci�n final en una quinta: todo eso se
reduce a dos queries.
Hay un peque�o detalle un tanto desagradable. Mirando en las dos queries,
descrubrimos que la relaci�n shoelace_data aparece dos
veces en la tabla de rango, lo que se deber�a reducir a una s�la.
El optimizador no manipula esto, y por ello el plan de ejecuci�n para la
salida del sistema de reglas de la INSERT ser�
Nested Loop
-> Merge Join
-> Seq Scan
-> Sort
-> Seq Scan on s
-> Seq Scan
-> Sort
-> Seq Scan on shoelace_arrive
-> Seq Scan on shoelace_data |
mientras que omitiendo la entrada extra a la tabla de rango deber�a ser
Merge Join
-> Seq Scan
-> Sort
-> Seq Scan on s
-> Seq Scan
-> Sort
-> Seq Scan on shoelace_arrive |
que produce exactamente las mismas entradas en la relaci�n de log. Es
decir, el sistema de regl�s ha probocado un barrido extra de la relaci�n
shoelace_data absol�tamente innecesario. Y el mismo
barrido obsoleto se produce de nuevo en la UPDATE. Pero era un trabajo
realmente duro hacer que todo sea posible.
Una demostraci�n final del sistema de reglas de
Postgres y de su poder. Hay una astuta rubia que
vende cordones de zapatos. Y lo que Al nunca hubiese imaginado, ella no es
s�lo astuta, tambi�n es elegante, un poco demasiado elegante. Por ello,
ella se empe�a de tiempo en tiempo en que Al pida cordones que son
absol�tamente invendibles. Esta vez ha pedido 1000 pares de cordones
magenta, y aunque ahora no es posible adquirir otro color, como �l se
comprometi� a comprar algo, prepara su base de datos para cordones rosa.
al_bundy=> INSERT INTO shoelace VALUES
al_bundy-> ('sl9', 0, 'pink', 35.0, 'inch', 0.0);
al_bundy=> INSERT INTO shoelace VALUES
al_bundy-> ('sl10', 1000, 'magenta', 40.0, 'inch', 0.0); |
Ahora quiere revisar los cordones que no casan con ning�n par de zapatos.
El podr�a realizar una complicada query cada vez, o bien le podemos
preparar una vista al efecto:
CREATE VIEW shoelace_obsolete AS
SELECT * FROM shoelace WHERE NOT EXISTS
(SELECT shoename FROM shoe WHERE slcolor = sl_color); |
cuya salida es
al_bundy=> SELECT * FROM shoelace_obsolete;
sl_name |sl_avail|sl_color |sl_len|sl_unit |sl_len_cm
----------+--------+----------+------+--------+---------
sl9 | 0|pink | 35|inch | 88.9
sl10 | 1000|magenta | 40|inch | 101.6 |
Sobre los 1000 cordones magenta, deber�amos avisar a Al antes de que
podamos hacerlo de nuevo, pero ese es otro problema. La entrada rosa, la
borramos. Para hacerlo un poco m�s dificil para
Postgres, no la borramos directamente. En su
lugar, crearemos una nueva vista
CREATE VIEW shoelace_candelete AS
SELECT * FROM shoelace_obsolete WHERE sl_avail = 0; |
Y lo haremos de esta forma:
DELETE FROM shoelace WHERE EXISTS
(SELECT * FROM shoelace_candelete
WHERE sl_name = shoelace.sl_name); |
Voila:
al_bundy=> SELECT * FROM shoelace;
sl_name |sl_avail|sl_color |sl_len|sl_unit |sl_len_cm
----------+--------+----------+------+--------+---------
sl1 | 5|black | 80|cm | 80
sl2 | 6|black | 100|cm | 100
sl7 | 6|brown | 60|cm | 60
sl4 | 8|black | 40|inch | 101.6
sl3 | 10|black | 35|inch | 88.9
sl8 | 21|brown | 40|inch | 101.6
sl10 | 1000|magenta | 40|inch | 101.6
sl5 | 4|brown | 1|m | 100
sl6 | 20|brown | 0.9|m | 90
(9 rows) |
Una DELETE en una vista, con una subselect como cualificaci�n, que en total
utiliza 4 vistas anidadas/cruzadas, donde una de ellas mismas tiene una
subselect de cualificaci�n conteniendo una vista y donde se utilizan
columnas calculadas queda reescrita en un �nico �rbol de traducci�n que
borra los datos requeridos de una tabla real.
Pienso que hay muy pocas ocasiones en el mundo real en las que se una
construcci�n similar sea necesaria. Pero me tranquiliza un poco que esto
funcione.
| La verdad es |
---|
| Haciendo esto encontr� otro bug mientras escrib�a este documento. Pero
tras fijarlo comprob� un poco avergonzado que trabajaba correctamente.
|