Reglas sobre INSERT, UPDATE y DELETE
Diferencias con las reglas de las vistas.
Las reglas que se definien para ON INSERT, UPDATE y DELETE son totalmente diferentes de las que se han descrito en la sección anterior para las vistas. Primero, su comando CREATE RULE permite más:
Pueden no tener acción.
Pueden tener múltiples acciones.
La palabra clave INSTEAD es opcional.
Las pseudo-relaciones NEW y OLD se vuelven utilizables.
Puede haber cualificaciones a las reglas.
Segundo, no modifican el árbol de traducción en el sitio. En lugar de ello, crean cero o varios árboles de traducción nuevos y pueden desechar el original.
Cómo trabajan estas reglas
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
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:
El árbol de traducción para la acción de la regla a la que se ha añadido cualificación a los árboles de traducción originales.
Sin cualificación pero con INSTEAD:
El árbol de traducción para la acción de la regla a la que se ha añadido cualificación a los árboles de traducción originales.
Se da cualificación y no 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.
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.
Una primera regla paso a paso.
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.
Cooperación con las vistas 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. Note: 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.
Competencias Digitales (Tic’s Basicas) a practicar con este TEMA:
- Usar (click en )www.Google.com para buscar y localizar UN material academico apropiado y que se pueda recomendar para el tema, ver VIDEO BUSQUEDAS abajo en esta pagina.
- En el post ( o tema ) apropiado en el Libro de Blogger, pegar el material localizado y que se recomienda para este tema, ver VIDEO BLOGGER abajo en esta pagina.
pd: Recordar incluir la fuente del tema usando el formato de citacion apropiado, ver VIDEO WIKIPEDIA abajo en esta pagina.
- En el editor de Blogger usar colores para destacar los parrafos mas importantes y usar subrayados para las citas mas relevantes.
- En el post ( o tema ) apropiado en el libro en Blogger, para incluir ecuaciones o notacion matematica se debera usar el icono del editor de Blogger IMAGE y construir esta notacion matematica con imagenes Latex, ver VIDEO LATEX ABAJO.
- Construir al final y despues de la fuente del material, un breve resumen ( no mas de 2–3 parrafos) explicando palabras propias el contenido del tema.
pd: Se pueden usar alguna de las citas que encontradas dentro del tema, solo recordar encerrarla entre comillas.
pd: Se pueden usar tambien cambios en fonts para darle mas visibilidad, consistencia y relevancia al resumen del tema.
- PUNTOS EXTRAS Si se usa una segunda fuente valiosa de informacion y recordar encadenar los dos materiales mediante uno o dos parrafos apropiados.
- Enviar a el maestro o compañeros un correo electronico que incluya la liga a el tema en blogger para revision, recomendacion, sugerencias y evaluacion, ver VIDEO LIGAS GMAIL abajo.
- Sacar una cuenta (click en)http://docs.google.com, usando el correo de Gmail y tratar de conseguir el mismo usuario que se construyo en Gmail y Blogger ver VIDEO GOOGLE DOCS abajo en esta pagina.
pd: Si ya se tiene una cuenta ignorar esta competencia digital.
pd: Google Docs es el equivalente a OFFICE pero con la caracteristica que todos sus componentes ( procesador de palabras, presentacion electronica y hoja de calculo) estan completamente en internet, es decir todos los archivos o material estaran en linea, seguros y siempre disponibles, ademas de que se pueden trabajarlos desde cualquier pc, ya sea la personal, la del laboratorio de la escuela o la de un lugar publico como la biblioteca o un cafe internet.
- Construir una Presentacion Electronica ( usando muy pocos slides) del tema en GOOGLE DOCS e incrustrarla en el tema de bloger ver VIDEO GOOGLE DOCS en esta pagina abajo.
pd: Recordar que una presentacion electronica, es solamente un resumen muy condensado del tema ( o mapa o guia mental ), que ayuda a recordar los elementos y conceptos mas basicos del tema, cuando se estan exponiendo frente a un grupo.
pd: No olvidar incluir un primer slide con el titulo de la presentacion electronica, un segundo slide con un indice de la presentacion electronica y un ultimo slide con dos o tres parrafos de conclusiones y bibliografia.
- Buscar en Google Imagenes o www.Flickr.com o www.PhotoBucket.com una galeria de fotos o de imagenes apropiadas al tema actual,
- Para los casos de Photobucket y Flicker, ambos sitios proporcionan ligas a sus imagenes y tambien objetos (los recuerdan??), que se pueden incluir en el tema del libro apropiado en Blogger.
pd: para estos sitios deberan obtener una cuenta usando el correo de gmail y de preferencia obtener el mismo usario que se ha venido manejando a lo largo del curso.
pd: Tratar de usar resoluciones y tamaños de imagenes chicos o medianos, recordar que todo este material termina en el post del tema en Blogger y esa pagina no tiene mucho espacio para desplegar fotos o imagenes.
pd: El formato apropiado para fotos o imagenes es JPG, tratar de no usar otros formatos.
pd: Se puede construir y conseguir esta coleccion o galeria de imagenes con:
1) Usando Google Imagenes, recordar conseguir solo imagenes que tengan permiso de publicacion abierto, no usar imagenes o fotos que tengan derechos reservados.
pd: Estas fotos almacenarlas en un folder en el desktop o escritorio de su computadora y subirlas a el post en blogger usando el icono IMAGE del editor de Blogger.
2) Flickr y Photo Bucket tambien tienen una gran cantidad de imagenes que se pueden usar o mejor dicho enlazar a el tema o post en Blogger.
3) Tambien se puede usar la camaras digitales o las camaras de sus telefonos celulares.
4) Tambien se puede usar el programa o aplicacion llamado Srip32.exe( solo buscar srip32 en google) bajarlo e instalarlo, este programa permite capturar una pantalla de la pc, es decir si se encuentra un sitio con imagenes o incluso texto apropiado o relevante al tema, capturar la pantalla con srip32 y ya se tendra la imagen, ver VIDEO Srip32 abajo.
- Incluir al menos una imagen de cada uno de los dos sitios (flickr y Photobucket) en el tema o post que se esta construyendo en Blogger.
- PUNTOS EXTRAS Si se incluyen una galeria completa de imagenes apropiadas desde cualquiera de estos sitios de FLICKR o Photobucket.
- Sacar una cuenta (click en)www.DivShare.com, usando el correo de Gmail y tratar de conseguir el mismo usuario que se consiguio en Gmail y Blogger y Flickr ver VIDEO DIVSHARE abajo en esta pagina.
pd: Si ya se tiene una cuenta ignorar esta competencia digital.
pd: Usar Divshare para almacenar material en audio (MP3) apropiado a el tema ( no usarlo para almacenar material comercial o les suspenden la cuenta)
pd: El material en Audio, con formato MP3 se debera producir usando un microfono en la pc y programas de aplicacion apropiados, llamados editores de audio, un ejemplo de ellos es el SOUND RECORDER que ya viene en Windows, pero se recomienda usar mejor AUDACITY ( solo buscar en google AUDACITY) bajarlo e instalarlo, ver VIDEO AUDACITY abajo.
- Crear al menos dos archivos de audio mp3:
1) El primero de ellos sera la lectura completa de este tema en voz apropiada. ( o aprender a editar con audacity la voz)
2) El segundo de ellos sera un resumen del tema. ( buena voz o editarla con audacity)
3) Ambos archivos subirlos a Div Share (recordor que tienen que ser MP3) y el reproductor que proporciona gratis Div Share, ver VIDEO DIVSHARE abajo e insertarlo en el lugar apropiado del tema que se esta construyendo en Blogger.
4) Ejemplo del reproductor incrustado en una pagina:
- Sacar una cuenta (click en)www.YouTube.com, usando el correo de Gmail y tratar de conseguir el mismo usuario que se consiguio en Gmail y Blogger y Flickr.
pd: Si ya se tiene una cuenta ignorar esta competencia digital.
- Para producir video se pueden usar tres fuentes:
1) Localizar Videos apropiados en Youtube.
2) Usar nuestras camaras digitales o nuestros telefonos celulares para producir video.
3) Producir un video de la propia pantalla de la computadora ( muy similar a lo que se hizo con Srip32) pero usando un programa especializado en video, tal como CAMSTUDIO (click en www.CamStudio.org) bajar e instalar ( no olvidar bajar e instalar el CODEC que esta abajo en el mismo sitio.
3.1) para Usar Camstudio solo recordar que es muy similar a Srip32 Solo que el resultado final es un archivo de video AVI.
- Producir un video de resumen del tema (usar camstudio con el fondo de la pagina con el tema e irlo comentando en voz apropiada)
- Producir un video en vivo con la exposicion del tema ( pueden usar la presentacion electronica de fondo o cualquier otro material, pizarron, filminas, rotafolios, etc.)
- Subir los videos a su cuenta en Youtube e incluirlos o ligarlos en la pagina en Blogger, tambien los pueden subir directamente a BLOGGER ver VIDEO BLOGGER VIDEO abajo.
Saludos y suerte prof Lauro Soto, Ensenada, BC, Mexico.