Anda di halaman 1dari 32

SUBCONSULTAS

CARLOS ALFONSO BASTO OLAYA

QU ES?
Es un comando SELECT dentro de otro comando SELECT.
SELECT * FROM t1 WHERE column1 = (SELECT column1
FROM t2);
Una subconsulta esta anidad en una consulta externa, de
hecho una subconsulta puede contener otras subconsultas
hasta una profundidad considerable. Las subconsultas
siempre deben aparecer entre parntesis.

VENTAJAS
Permiten consultas estructuradas de forma que es

posible aislar cada parte de un comando.


Proporcionan un modo alternativo de realizar
operaciones que de otro modo necesitaran JOINs y
UNIONs complejos.
Son, en la opinin de mucha gente, lebles. De
hecho, fue la innovacin de las subconsultas lo que
dio a la gente la idea original de llamar a SQL
Structured Query Language.

CARACTERSTICAS

escalar registro columna tabla


Subconsulta
DISTINCT, GROUP BY, ORDER BY, LIMIT,
JOINs, trucos de ndices, UNION,
comentarios, funciones, y as.

RESTRICCIONES

Una restriccin es que el comando exterior de una

subconsulta debe ser: SELECT, INSERT, UPDATE,


DELETE, SET, o DO.
Otra restriccin es que actualmente no puede
modificar una tabla y seleccionar de la misma
tabla en la subconsulta. Esto se aplica a comandos
tales como DELETE, INSERT, REPLACE, y UPDATE.

SUBCONSULTA COMO VALORES ESCALARES


CREATE TABLE t1 (s1 INT, s2 CHAR(5) NOT NULL);
INSERT INTO t1 VALUES(100, 'abcde');
SELECT (SELECT s2 FROM t1);

Hay contextos en donde una subconsulta literal no se puede


usar, por ejemplo si un comando permite un valor literal
(LIMIT, LOAD DATA).

SUBCONSULTAS EN CONSULTAS

operando_no_subconsulta operador_comparador
(subconsulta)
He aqu un ejemplo de una comparacin comn de subconsultas que no
puede hacerse mediante un JOIN. Encuentra todos los valores en la tabla t1
que son iguales a un valor mximo en la tabla t2:
SELECT column1 FROM t1 WHERE column1 = (SELECT MAX(column2)
FROM t2);

Encuentra todos los registros en la tabla t1 que


contengan un valor que ocurre dos veces en una
columna dada:
SELECT * FROM t1 AS t
WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id
= t.id);
Subconsulta de registros (ms adelante).

SUBCONSULTAS CON ANY, IN Y SOME

operando operador_comparador ANY


(subconsulta)
operando IN (subconsulta)
operando operador_comparador SOME
(subconsulta)

ANY significa return TRUE si la comparacin es TRUE para ANY (cualquiera) de los valores en la
columna que retorna la subconsulta.

SELECT s1 FROM t1 WHERE s1 > ANY (SELECT s1 FROM t2);


TRUE = Alguna (1 o ms) de las comparaciones es verdadera
FALSE = Ninguna de las comparaciones es verdadera
UNKNOWN = Si la tabla de la subconsulta tiene todos sus registros en NULL

SELECT s1 FROM t1 WHERE s1 = ANY (SELECT s1 FROM t2);


SELECT s1 FROM t1 WHERE s1 IN (SELECT s1 FROM t2); # NOT IN es diferente a <> ANY
SELECT s1 FROM t1 WHERE s1 = SOME (SELECT s1 FROM t2);
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2); # Por qu mostrara
error?

SUBCONSULTAS CON ALL

operando operador_comparador ALL(subconsulta)


TRUE = Todas las comparaciones son verdaderas
TRUE = Si la tabla de la subconsulta est vaca
FALSE = Alguna (1 o ms) de las comparaciones son falsas
UNKNOWN = Alguna (1 o ms) de las comparaciones es con NULL

TRUE
SELECT * FROM t1 WHERE 1 > ALL (SELECT s1 FROM t2);

UNKNOWN
SELECT * FROM t1 WHERE 1 > (SELECT s1 FROM t2);

UNKNOWN
SELECT * FROM t1 WHERE 1 > ALL (SELECT MAX(s1) FROM t2);

SELECT s1 FROM t1 WHERE s1 <> ALL (SELECT s1 FROM t2);


SELECT s1 FROM t1 WHERE s1 NOT IN (SELECT s1 FROM t2);

SUBCONSULTAS DE REGISTRO
SELECT * FROM t1 WHERE (1,2) = (SELECT column1, column2 FROM t2);
SELECT * FROM t1 WHERE ROW(1,2) = (SELECT column1, column2
FROM t2);
(1,2), ROW(1,2) -> constructores de registros
SELECT * FROM t1 WHERE (column1,column2) = (1,1);
SELECT * FROM t1 WHERE column1 = 1 AND column2 = 1;

SELECT column1,column2,column3
FROM t1
WHERE (column1,column2,column3)
IN
(SELECT column1,column2,column3
FROM t2);

EXISTS Y NOT EXISTS

Si la subconsulta contiene registros, as sea solo valores


NULL
EXISTS (subconsulta) => TRUE
NOT EXISTS (subconsulta) => FALSE

Qu clase de tienda hay en una o ms ciudades?


SELECT DISTINCT store_type FROM Stores
WHERE EXISTS (SELECT * FROM Cities_Stores
WHERE Cities_Stores.store_type = Stores.store_type);
Qu clase de tienda no hay en ninguna ciudad?
SELECT DISTINCT store_type FROM Stores
WHERE NOT EXISTS (SELECT * FROM Cities_Stores
WHERE Cities_Stores.store_type = Stores.store_type);

SUBCONSULTAS CORRELACIONADAS
Una subconsulta correlacionada es una subconsulta que
contiene una referencia a una tabla que tambin aparece en
la consulta exterior.
SELECT * FROM t1 WHERE column1 = ANY
(SELECT column1 FROM t2 WHERE t2.column2 =
t1.column2);

MySQL evalua desde dentro hacia fuera


SELECT column1 FROM t1 AS x
WHERE x.column1 = (SELECT column1 FROM t2 AS x
WHERE x.column1 = (SELECT column1 FROM t3
WHERE x.column2 = t3.column1));
Reescribir la consulta como un JOIN puede mejorar el
rendimiento.
Las subconsultas correlacionadas no pueden referirse a los
resultados de funciones agregadas de la consulta exterior.

SUBCONSULTAS EN LA CLUSULA FROM


SELECT ... FROM (subconsulta) [AS] name ...
[AS] name es obligatoria
CREATE TABLE t1 (s1 INT, s2 CHAR(5), s3 FLOAT);
INSERT INTO t1 VALUES (1,'1',1.0);
INSERT INTO t1 VALUES (2,'2',2.0);
SELECT sb1,sb2,sb3
FROM (SELECT s1 AS sb1, s2 AS sb2, s3*2 AS sb3 FROM t1) AS sb
WHERE sb1 > 1;
Resultado: 2, '2', 4.0.

Suponga que quiere conocer la media de un conjunto de


sumas para una tabla agrupada.
SELECT AVG(SUM(column1)) FROM t1 GROUP BY column1;
# No funciona
SELECT AVG(sum_column1)
FROM (SELECT SUM(column1) AS sum_column1
FROM t1 GROUP BY column1) AS t1;
# Funciona

Las subconsultas en la clusula FROM pueden retornar un


escalar, columna, registro o tabla, pero no pueden ser
subconsultas correladas.
UPDATE t1 SET column2 = (SELECT MAX(column1) FROM
t1); # Error

ERRORES EN SUBCONSULTAS
Nmero incorrecto de columnas de la subconsulta:
ERROR 1241 (ER_OPERAND_COL)
SQLSTATE = 21000
Message = "Operand should contain 1 column(s)
SELECT (SELECT column1, column2 FROM t2) FROM t1;

Nmero incorrecto de registros de la subconsulta:


ERROR 1242 (ER_SUBSELECT_NO_1_ROW)
SQLSTATE = 21000
Message = "Subquery returns more than 1 row
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM
t2);

Tabla usada incorrectamente en la subconsulta:


Error 1093 (ER_UPDATE_TABLE_USED)
SQLSTATE = HY000
Message = "You can't specify target table 'x'
for update in FROM clause
UPDATE t1 SET column2 = (SELECT MAX(column1) FROM t1);
Motores transaccionales -> Falla el comando entero
Motores no transaccionales -> Modificaciones antes del error se preservan

OPTIMIZAR SUBCONSULTAS
Usar clusulas de subconsulta que afecten al nmero u orden de los registros en la
subconsulta.
SELECT * FROM t1 WHERE t1.column1 IN
(SELECT column1 FROM t2 ORDER BY column1);
SELECT * FROM t1 WHERE t1.column1 IN
(SELECT DISTINCT column1 FROM t2);
SELECT * FROM t1 WHERE EXISTS
(SELECT * FROM t2 LIMIT 1);

Un JOIN por una subconsulta:


SELECT DISTINCT t1.column1 FROM t1, t2
WHERE t1.column1 = t2.column1;
SELECT DISTINCT column1 FROM t1 WHERE
t1.column1 IN (
SELECT column1 FROM t2);

Mueva las clusulas desde fuera hacia dentro en la subconsulta.


SELECT * FROM t1
WHERE s1 IN (SELECT s1 FROM t1) OR s1 IN (SELECT s1 FROM t2);
SELECT * FROM t1
WHERE s1 IN (SELECT s1 FROM t1 UNION ALL SELECT s1 FROM t2);
SELECT (SELECT column1 FROM t1) + 5 FROM t2;
SELECT (SELECT column1 + 5 FROM t1) FROM t2;

Use una subconsulta de registro en lugar de una subconsulta


correlacionada.
SELECT * FROM t1
WHERE EXISTS (SELECT * FROM t2 WHERE
t2.column1=t1.column1
AND t2.column2=t1.column2);
SELECT * FROM t1
WHERE (column1,column2) IN (SELECT column1,column2
FROM t2);

Use NOT (a = ANY (...)) en lugar de a <> ALL (...).


Use x = ANY (table containing (1,2)) en lugar de x=1 OR

x=2.
Use = ANY en lugar de EXISTS.
Para subconsultas no correlacionadas que siempre
retornan un registro, IN siempre es ms lento que =.

Algunas optimizaciones que hace MySQL:


MySQL ejecuta subconsultas no correlacionadas slo una

vez. Use EXPLAIN para asegurar que una subconsulta


dada realmente no est correlacionada.
MySQL reescribe subconsultas IN, ALL, ANY, y SOME para
aprovechar que las columnas de la lista de SELECT de la
subconsulta est indexada.

MySQL reemplaza subconsultas de la siguiente forma con

una funcin de bsqueda de ndice, que EXPLAIN describe


como tipo especial de join (unique_subquery o
index_subquery):
... IN (SELECT indexed_column FROM single_table ...)
MySQL mejora expresiones de la siguiente forma con una
expresin que involucre MIN() o MAX(), a no ser que hayan
involucrados valores NULL o conjuntos vacos:
WHERE 5 > ALL (SELECT x FROM t);
WHERE 5 > (SELECT MAX(x) FROM t);

GRACIAS

Anda mungkin juga menyukai