Parte 1 - Uniones y Uniones
Esta respuesta cubre:
- Parte 1
- Parte 2
- Subconsultas: qué son, dónde se pueden usar y a qué vigilar
- Cartesian se une a AKA - ¡Oh, la miseria!
Hay varias formas de recuperar datos de varias tablas en una base de datos. En esta respuesta, usaré la sintaxis de unión ANSI-92. Esto puede ser diferente a una serie de otros tutoriales que usan la sintaxis ANSI-89 anterior (y si estás acostumbrado a 89, puede parecer mucho menos intuitivo, pero todo lo que puedo decir es que lo pruebes) ya que es mucho más fácil entender cuándo las consultas comienzan a ser más complejas. ¿Por qué usarlo? ¿Hay un aumento de rendimiento? La respuesta corta es no, pero es más fácil de leer una vez que te acostumbras. Es más fácil leer consultas escritas por otras personas que usan esta sintaxis.
También voy a utilizar el concepto de un pequeño caryard que tiene una base de datos para realizar un seguimiento de los automóviles que tiene disponibles. El propietario lo ha contratado como su chico de informática y espera que pueda soltarle los datos que solicita en un abrir y cerrar de ojos.
He hecho una serie de tablas de búsqueda que serán utilizadas por la tabla final. Esto nos dará un modelo razonable para trabajar. Para comenzar, ejecutaré mis consultas en una base de datos de ejemplo que tiene la siguiente estructura. Trataré de pensar en los errores comunes que se cometen al comenzar y explicaré qué sucede con ellos, así como, por supuesto, mostraré cómo corregirlos.
La primera tabla es simplemente una lista de colores para que sepamos qué colores tenemos en el patio del automóvil.
mysql> create table colors(id int(3) not null auto_increment primary key,
-> color varchar(15), paint varchar(10));
Query OK, 0 rows affected (0.01 sec)
mysql> show columns from colors;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| color | varchar(15) | YES | | NULL | |
| paint | varchar(10) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
mysql> insert into colors (color, paint) values ('Red', 'Metallic'),
-> ('Green', 'Gloss'), ('Blue', 'Metallic'),
-> ('White' 'Gloss'), ('Black' 'Gloss');
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> select * from colors;
+----+-------+----------+
| id | color | paint |
+----+-------+----------+
| 1 | Red | Metallic |
| 2 | Green | Gloss |
| 3 | Blue | Metallic |
| 4 | White | Gloss |
| 5 | Black | Gloss |
+----+-------+----------+
5 rows in set (0.00 sec)
La tabla de marcas identifica las diferentes marcas de los automóviles que Caryard podría vender.
mysql> create table brands (id int(3) not null auto_increment primary key,
-> brand varchar(15));
Query OK, 0 rows affected (0.01 sec)
mysql> show columns from brands;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| brand | varchar(15) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)
mysql> insert into brands (brand) values ('Ford'), ('Toyota'),
-> ('Nissan'), ('Smart'), ('BMW');
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> select * from brands;
+----+--------+
| id | brand |
+----+--------+
| 1 | Ford |
| 2 | Toyota |
| 3 | Nissan |
| 4 | Smart |
| 5 | BMW |
+----+--------+
5 rows in set (0.00 sec)
La tabla de modelos cubrirá diferentes tipos de automóviles, será más simple para esto usar diferentes tipos de automóviles en lugar de modelos de automóviles reales.
mysql> create table models (id int(3) not null auto_increment primary key,
-> model varchar(15));
Query OK, 0 rows affected (0.01 sec)
mysql> show columns from models;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| model | varchar(15) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> insert into models (model) values ('Sports'), ('Sedan'), ('4WD'), ('Luxury');
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from models;
+----+--------+
| id | model |
+----+--------+
| 1 | Sports |
| 2 | Sedan |
| 3 | 4WD |
| 4 | Luxury |
+----+--------+
4 rows in set (0.00 sec)
Y finalmente, para unir todas estas otras tablas, la tabla que une todo. El campo ID es en realidad el número de lote único utilizado para identificar automóviles.
mysql> create table cars (id int(3) not null auto_increment primary key,
-> color int(3), brand int(3), model int(3));
Query OK, 0 rows affected (0.01 sec)
mysql> show columns from cars;
+-------+--------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| color | int(3) | YES | | NULL | |
| brand | int(3) | YES | | NULL | |
| model | int(3) | YES | | NULL | |
+-------+--------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
mysql> insert into cars (color, brand, model) values (1,2,1), (3,1,2), (5,3,1),
-> (4,4,2), (2,2,3), (3,5,4), (4,1,3), (2,2,1), (5,2,3), (4,5,1);
Query OK, 10 rows affected (0.00 sec)
Records: 10 Duplicates: 0 Warnings: 0
mysql> select * from cars;
+----+-------+-------+-------+
| id | color | brand | model |
+----+-------+-------+-------+
| 1 | 1 | 2 | 1 |
| 2 | 3 | 1 | 2 |
| 3 | 5 | 3 | 1 |
| 4 | 4 | 4 | 2 |
| 5 | 2 | 2 | 3 |
| 6 | 3 | 5 | 4 |
| 7 | 4 | 1 | 3 |
| 8 | 2 | 2 | 1 |
| 9 | 5 | 2 | 3 |
| 10 | 4 | 5 | 1 |
+----+-------+-------+-------+
10 rows in set (0.00 sec)
Esto nos dará suficientes datos (espero) para cubrir los siguientes ejemplos de diferentes tipos de combinaciones y también proporcionará suficientes datos para que valgan la pena.
Entonces, entrando en la arena, el jefe quiere saber las identificaciones de todos los autos deportivos que tiene .
Esta es una combinación simple de dos tablas. Tenemos una tabla que identifica el modelo y la tabla con el stock disponible. Como puede ver, los datos en la model
columna de la cars
tabla se relacionan con la models
columna de la cars
tabla que tenemos. Ahora, sabemos que la tabla de modelos tiene un ID de 1
for, Sports
así que vamos a escribir la unión.
select
ID,
model
from
cars
join models
on model=ID
Entonces esta consulta se ve bien, ¿verdad? Hemos identificado las dos tablas y contiene la información que necesitamos y utilizamos una combinación que identifica correctamente en qué columnas unirnos.
ERROR 1052 (23000): Column 'ID' in field list is ambiguous
Oh no! Un error en nuestra primera consulta! Sí, y es una ciruela. Verá, la consulta tiene las columnas correctas, pero algunas de ellas existen en ambas tablas, por lo que la base de datos se confunde acerca de qué columna real queremos decir y dónde. Hay dos soluciones para resolver esto. El primero es agradable y simple, podemos usar tableName.columnName
para decirle a la base de datos exactamente lo que queremos decir, así:
select
cars.ID,
models.model
from
cars
join models
on cars.model=models.ID
+----+--------+
| ID | model |
+----+--------+
| 1 | Sports |
| 3 | Sports |
| 8 | Sports |
| 10 | Sports |
| 2 | Sedan |
| 4 | Sedan |
| 5 | 4WD |
| 7 | 4WD |
| 9 | 4WD |
| 6 | Luxury |
+----+--------+
10 rows in set (0.00 sec)
El otro probablemente se usa con más frecuencia y se llama alias de tabla. Las tablas en este ejemplo tienen nombres simples y agradables, pero escribir algo así KPI_DAILY_SALES_BY_DEPARTMENT
probablemente envejecería rápidamente, por lo que una forma simple es ponerle un apodo a la tabla de esta manera:
select
a.ID,
b.model
from
cars a
join models b
on a.model=b.ID
Ahora, de vuelta a la solicitud. Como puede ver, tenemos la información que necesitamos, pero también tenemos información que no se solicitó, por lo que debemos incluir una cláusula where en la declaración para obtener solo los autos deportivos como se solicitó. Como prefiero el método de alias de tabla en lugar de usar los nombres de tabla una y otra vez, me atendré a él a partir de este momento.
Claramente, necesitamos agregar una cláusula where a nuestra consulta. Podemos identificar autos deportivos por ID=1
o model='Sports'
. A medida que la ID se indexa y la clave principal (y resulta que está escribiendo menos), usemos eso en nuestra consulta.
select
a.ID,
b.model
from
cars a
join models b
on a.model=b.ID
where
b.ID=1
+----+--------+
| ID | model |
+----+--------+
| 1 | Sports |
| 3 | Sports |
| 8 | Sports |
| 10 | Sports |
+----+--------+
4 rows in set (0.00 sec)
¡Bingo! El jefe esta feliz. Por supuesto, como jefe y nunca contento con lo que pidió, mira la información y luego dice que también quiero los colores .
Bien, tenemos una buena parte de nuestra consulta ya escrita, pero necesitamos usar una tercera tabla que es colores. Ahora, nuestra tabla de información principal cars
almacena la identificación del color del automóvil y esta vuelve a la columna de identificación del color. Entonces, de manera similar al original, podemos unirnos a una tercera tabla:
select
a.ID,
b.model
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
where
b.ID=1
+----+--------+
| ID | model |
+----+--------+
| 1 | Sports |
| 3 | Sports |
| 8 | Sports |
| 10 | Sports |
+----+--------+
4 rows in set (0.00 sec)
Maldición, aunque la tabla se unió correctamente y las columnas relacionadas se vincularon, olvidamos extraer la información real de la nueva tabla que acabamos de vincular.
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
where
b.ID=1
+----+--------+-------+
| ID | model | color |
+----+--------+-------+
| 1 | Sports | Red |
| 8 | Sports | Green |
| 10 | Sports | White |
| 3 | Sports | Black |
+----+--------+-------+
4 rows in set (0.00 sec)
Correcto, ese es el jefe de nuestras espaldas por un momento. Ahora, para explicar algo de esto con un poco más de detalle. Como puede ver, la from
cláusula en nuestra declaración vincula nuestra tabla principal (a menudo uso una tabla que contiene información en lugar de una tabla de búsqueda o dimensión. La consulta funcionaría igual de bien con todas las tablas cambiadas, pero tiene menos sentido cuando volvemos a esta consulta para leerla dentro de unos meses, por lo que a menudo es mejor intentar escribir una consulta que sea agradable y fácil de entender: exponga intuitivamente, use una sangría agradable para que todo sea tan claro como sea posible. puede ser. Si continúa enseñando a otros, intente inculcar estas características en sus consultas, especialmente si va a solucionarlos.
Es completamente posible seguir vinculando más y más tablas de esta manera.
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=1
Si bien olvidé incluir una tabla donde podríamos unir más de una columna en la join
declaración, aquí hay un ejemplo. Si la models
tabla tenía modelos específicos de la marca y, por lo tanto, también tenía una columna llamada brand
que se vinculaba de nuevo a la brands
tabla en el ID
campo, podría hacerse así:
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
and b.brand=d.ID
where
b.ID=1
Puede ver que la consulta anterior no solo vincula las tablas unidas a la cars
tabla principal , sino que también especifica las uniones entre las tablas ya unidas. Si esto no se hizo, el resultado se llama una unión cartesiana, que es hablar mal. Una combinación cartesiana es aquella en la que se devuelven filas porque la información no le dice a la base de datos cómo limitar los resultados, por lo que la consulta devuelve todas las filas que se ajustan a los criterios.
Entonces, para dar un ejemplo de una unión cartesiana, ejecutemos la siguiente consulta:
select
a.ID,
b.model
from
cars a
join models b
+----+--------+
| ID | model |
+----+--------+
| 1 | Sports |
| 1 | Sedan |
| 1 | 4WD |
| 1 | Luxury |
| 2 | Sports |
| 2 | Sedan |
| 2 | 4WD |
| 2 | Luxury |
| 3 | Sports |
| 3 | Sedan |
| 3 | 4WD |
| 3 | Luxury |
| 4 | Sports |
| 4 | Sedan |
| 4 | 4WD |
| 4 | Luxury |
| 5 | Sports |
| 5 | Sedan |
| 5 | 4WD |
| 5 | Luxury |
| 6 | Sports |
| 6 | Sedan |
| 6 | 4WD |
| 6 | Luxury |
| 7 | Sports |
| 7 | Sedan |
| 7 | 4WD |
| 7 | Luxury |
| 8 | Sports |
| 8 | Sedan |
| 8 | 4WD |
| 8 | Luxury |
| 9 | Sports |
| 9 | Sedan |
| 9 | 4WD |
| 9 | Luxury |
| 10 | Sports |
| 10 | Sedan |
| 10 | 4WD |
| 10 | Luxury |
+----+--------+
40 rows in set (0.00 sec)
Dios mío, eso es feo. Sin embargo, en lo que respecta a la base de datos, es exactamente lo que se solicitó. En la consulta, solicitamos el ID
de cars
y el model
de models
. Sin embargo, debido a que no especificamos cómo unir las tablas, la base de datos ha coincidido con cada fila de la primera tabla con cada fila de la segunda tabla.
Bien, entonces el jefe está de regreso y quiere más información nuevamente. Quiero la misma lista, pero también incluyo 4WD en ella .
Sin embargo, esto nos da una gran excusa para ver dos formas diferentes de lograr esto. Podríamos agregar otra condición a la cláusula where como esta:
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=1
or b.ID=3
Si bien lo anterior funcionará perfectamente bien, veámoslo de manera diferente, esta es una gran excusa para mostrar cómo funcionará una union
consulta.
Sabemos que lo siguiente devolverá todos los autos deportivos:
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=1
Y lo siguiente devolvería todos los 4WD:
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=3
Entonces, al agregar una union all
cláusula entre ellos, los resultados de la segunda consulta se agregarán a los resultados de la primera consulta.
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=1
union all
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=3
+----+--------+-------+
| ID | model | color |
+----+--------+-------+
| 1 | Sports | Red |
| 8 | Sports | Green |
| 10 | Sports | White |
| 3 | Sports | Black |
| 5 | 4WD | Green |
| 7 | 4WD | White |
| 9 | 4WD | Black |
+----+--------+-------+
7 rows in set (0.00 sec)
Como puede ver, los resultados de la primera consulta se devuelven primero, seguidos de los resultados de la segunda consulta.
En este ejemplo, por supuesto, habría sido mucho más fácil simplemente usar la primera consulta, pero las union
consultas pueden ser excelentes para casos específicos. Ellos son una gran manera para obtener resultados específicos de las tablas de las tablas que no están unidos entre sí con facilidad - o para el caso por completo tablas no relacionadas. Sin embargo, hay algunas reglas a seguir.
- Los tipos de columna de la primera consulta deben coincidir con los tipos de columna de cualquier otra consulta a continuación.
- Los nombres de las columnas de la primera consulta se utilizarán para identificar el conjunto completo de resultados.
- El número de columnas en cada consulta debe ser el mismo.
Ahora, puede que se pregunte cuál es la diferencia entre usar union
y union all
. Una union
consulta eliminará duplicados, mientras que una union all
no lo hará. Esto significa que hay un pequeño impacto en el rendimiento cuando se usa union
más, union all
pero los resultados pueden valer la pena; sin embargo, no especularé sobre ese tipo de cosas en esto.
En esta nota, podría valer la pena señalar algunas notas adicionales aquí.
- Si quisiéramos ordenar los resultados, podemos usar un
order by
pero ya no puede usar el alias. En la consulta anterior, agregar un order by a.ID
daría como resultado un error, en lo que respecta a los resultados, la columna se llama en ID
lugar de hacerlo a.ID
, a pesar de que se ha utilizado el mismo alias en ambas consultas.
- Solo podemos tener una
order by
declaración, y debe ser como la última declaración.
Para los siguientes ejemplos, agregaré algunas filas adicionales a nuestras tablas.
He agregado Holden
a la tabla de marcas. También he agregado una fila cars
que tiene el color
valor de 12
, que no tiene referencia en la tabla de colores.
De acuerdo, el jefe está de regreso otra vez, ladrando solicitudes - * ¡Quiero un recuento de cada marca que tenemos y la cantidad de autos que contiene! `- Típico, solo llegamos a una sección interesante de nuestra discusión y el jefe quiere más trabajo .
Rightyo, así que lo primero que debemos hacer es obtener una lista completa de posibles marcas.
select
a.brand
from
brands a
+--------+
| brand |
+--------+
| Ford |
| Toyota |
| Nissan |
| Smart |
| BMW |
| Holden |
+--------+
6 rows in set (0.00 sec)
Ahora, cuando unimos esto a nuestra mesa de autos, obtenemos el siguiente resultado:
select
a.brand
from
brands a
join cars b
on a.ID=b.brand
group by
a.brand
+--------+
| brand |
+--------+
| BMW |
| Ford |
| Nissan |
| Smart |
| Toyota |
+--------+
5 rows in set (0.00 sec)
Lo cual, por supuesto, es un problema: no estamos viendo ninguna mención de la hermosa Holden
marca que agregué.
Esto se debe a que una unión busca filas coincidentes en ambas tablas. Como no hay datos en los automóviles que sean de tipo Holden
, no se devuelven. Aquí es donde podemos usar una outer
unión. Esto devolverá todos los resultados de una tabla, ya sea que coincidan en la otra tabla o no:
select
a.brand
from
brands a
left outer join cars b
on a.ID=b.brand
group by
a.brand
+--------+
| brand |
+--------+
| BMW |
| Ford |
| Holden |
| Nissan |
| Smart |
| Toyota |
+--------+
6 rows in set (0.00 sec)
Ahora que tenemos eso, podemos agregar una función agregada encantadora para obtener un recuento y sacar al jefe de nuestras espaldas por un momento.
select
a.brand,
count(b.id) as countOfBrand
from
brands a
left outer join cars b
on a.ID=b.brand
group by
a.brand
+--------+--------------+
| brand | countOfBrand |
+--------+--------------+
| BMW | 2 |
| Ford | 2 |
| Holden | 0 |
| Nissan | 1 |
| Smart | 1 |
| Toyota | 5 |
+--------+--------------+
6 rows in set (0.00 sec)
Y con eso, el jefe se esconde.
Ahora, para explicar esto con más detalle, las uniones externas pueden ser del tipo left
o right
. La izquierda o la derecha define qué tabla está completamente incluida. A left outer join
incluirá todas las filas de la tabla de la izquierda, mientras que (lo adivinó) a right outer join
trae todos los resultados de la tabla de la derecha a los resultados.
Algunas bases de datos permitirán una full outer join
que traerá resultados (ya sea coincidentes o no) de ambas tablas, pero esto no es compatible con todas las bases de datos.
Ahora, probablemente supongo que en este momento, se está preguntando si puede fusionar o no los tipos de combinación en una consulta, y la respuesta es sí, absolutamente puede.
select
b.brand,
c.color,
count(a.id) as countOfBrand
from
cars a
right outer join brands b
on b.ID=a.brand
join colors c
on a.color=c.ID
group by
a.brand,
c.color
+--------+-------+--------------+
| brand | color | countOfBrand |
+--------+-------+--------------+
| Ford | Blue | 1 |
| Ford | White | 1 |
| Toyota | Black | 1 |
| Toyota | Green | 2 |
| Toyota | Red | 1 |
| Nissan | Black | 1 |
| Smart | White | 1 |
| BMW | Blue | 1 |
| BMW | White | 1 |
+--------+-------+--------------+
9 rows in set (0.00 sec)
Entonces, ¿por qué no son los resultados que se esperaban? Esto se debe a que, aunque hemos seleccionado la combinación externa de automóviles a marcas, no se especificó en la combinación de colores, por lo que esa combinación en particular solo devolverá resultados que coincidan en ambas tablas.
Aquí está la consulta que funcionaría para obtener los resultados que esperábamos:
select
a.brand,
c.color,
count(b.id) as countOfBrand
from
brands a
left outer join cars b
on a.ID=b.brand
left outer join colors c
on b.color=c.ID
group by
a.brand,
c.color
+--------+-------+--------------+
| brand | color | countOfBrand |
+--------+-------+--------------+
| BMW | Blue | 1 |
| BMW | White | 1 |
| Ford | Blue | 1 |
| Ford | White | 1 |
| Holden | NULL | 0 |
| Nissan | Black | 1 |
| Smart | White | 1 |
| Toyota | NULL | 1 |
| Toyota | Black | 1 |
| Toyota | Green | 2 |
| Toyota | Red | 1 |
+--------+-------+--------------+
11 rows in set (0.00 sec)
Como podemos ver, tenemos dos combinaciones externas en la consulta y los resultados se obtienen como se esperaba.
Ahora, ¿qué tal esos otros tipos de combinaciones que preguntas? ¿Qué pasa con las intersecciones?
Bueno, no todas las bases de datos son compatibles, intersection
pero prácticamente todas las bases de datos le permitirán crear una intersección a través de una unión (o una declaración where bien estructurada como mínimo).
Una intersección es un tipo de unión algo similar a la union
descrita anteriormente, pero la diferencia es que solo devuelve filas de datos que son idénticos (y quiero decir idénticos) entre las diversas consultas individuales unidas por la unión. Solo se devolverán las filas que sean idénticas en todos los aspectos.
Un ejemplo simple sería como tal:
select
*
from
colors
where
ID>2
intersect
select
*
from
colors
where
id<4
Mientras que una union
consulta normal devolvería todas las filas de la tabla (la primera consulta devolvería cualquier cosa ID>2
y la segunda cualquier cosa que tuviera ID<4
) lo que daría como resultado un conjunto completo, una consulta de intersección solo devolvería la coincidencia de fila id=3
ya que cumple con ambos criterios.
Ahora, si su base de datos no admite una intersect
consulta, lo anterior se puede cumplir fácilmente con la siguiente consulta:
select
a.ID,
a.color,
a.paint
from
colors a
join colors b
on a.ID=b.ID
where
a.ID>2
and b.ID<4
+----+-------+----------+
| ID | color | paint |
+----+-------+----------+
| 3 | Blue | Metallic |
+----+-------+----------+
1 row in set (0.00 sec)
Si desea realizar una intersección en dos tablas diferentes utilizando una base de datos que no admite inherentemente una consulta de intersección, deberá crear una unión en cada columna de las tablas.
Ok, esta publicación me pareció muy interesante y me gustaría compartir algunos de mis conocimientos sobre cómo crear una consulta. Gracias por este Fluffeh . Otros que pueden leer esto y pueden sentir que estoy equivocado son 101% libres de editar y criticar mi respuesta. ( Honestamente, me siento muy agradecido por corregir mi error (s). )
Publicaré algunas de las preguntas frecuentes en la
MySQL
etiqueta.Truco No. 1 ( filas que coinciden con múltiples condiciones )
Dado este esquema
PREGUNTA
Encuentra todas las películas que pertenecen a por lo menos tanto
Comedy
yRomance
categorías.Solución
Esta pregunta puede ser muy complicada a veces. Puede parecer que una consulta como esta será la respuesta:
Demostración de SQLFiddle
lo cual definitivamente está muy mal porque no produce ningún resultado . La explicación de esto es que solo hay un valor válido de
CategoryName
en cada fila . Por ejemplo, la primera condición devuelve verdadero , la segunda condición siempre es falsa. Por lo tanto, al usar elAND
operador, ambas condiciones deben ser verdaderas; de lo contrario, será falso. Otra consulta es así,Demostración de SQLFiddle
y el resultado sigue siendo incorrecto porque coincide con el registro que tiene al menos una coincidencia en el
categoryName
. La solución real sería contar el número de instancias de grabación por película . El número de instancias debe coincidir con el número total de los valores suministrados en la condición.SQLFiddle Demo (la respuesta)
Truco No. 2 ( registro máximo para cada entrada )
Esquema dado
PREGUNTA
Encuentra la última versión de cada software. Visualizar las siguientes columnas:
SoftwareName
,Descriptions
,LatestVersion
( de la columna VersionNo ),DateReleased
Solución
Algunos desarrolladores de SQL utilizan por error
MAX()
la función agregada. Tienden a crear así,Demostración de SQLFiddle
(la mayoría de RDBMS genera un error de sintaxis en esto debido a que no especifica algunas de las columnas no agregadas en la
group by
cláusula ) el resultado produce el correctoLatestVersion
en cada software pero obviamenteDateReleased
es incorrecto.MySQL
no es compatibleWindow Functions
y,Common Table Expression
sin embargo, como algunos RDBMS ya lo hacen. La solución a este problema es crear unasubquery
que obtenga el máximo individualversionNo
en cada software y luego se una en las otras tablas.SQLFiddle Demo (la respuesta)
Así que eso fue todo. Publicaré otro pronto cuando recuerde cualquier otra pregunta frecuente en la
MySQL
etiqueta. Gracias por leer este pequeño artículo. Espero que al menos tengas un poco de conocimiento de esto.ACTUALIZACIÓN 1
Truco No. 3 ( Encontrar el último registro entre dos ID )
Esquema dado
PREGUNTA
Encuentra la última conversación entre dos usuarios.
Solución
Demostración de SQLFiddle
fuente
comedy
yromance
.Having
no se adapta entonces ..distinct
la cláusula have SQLFiddle Demo : DParte 2 - Subconsultas
Bien, ahora el jefe ha vuelto a entrar: ¡quiero una lista de todos nuestros autos con la marca y un total de cuántos de esa marca tenemos!
Esta es una gran oportunidad para usar el siguiente truco en nuestra bolsa de productos SQL: la subconsulta. Si no está familiarizado con el término, una subconsulta es una consulta que se ejecuta dentro de otra consulta. Hay muchas formas diferentes de usarlos.
Para nuestra solicitud, primero hagamos una consulta simple que enumere cada automóvil y la marca:
Ahora, si simplemente quisiéramos obtener un recuento de autos ordenados por marca, por supuesto podríamos escribir esto:
Entonces, deberíamos poder simplemente agregar la función de conteo a nuestra consulta original, ¿verdad?
Lamentablemente, no, no podemos hacer eso. La razón es que cuando agregamos la ID del automóvil (columna a.ID) tenemos que agregarla al grupo, así que ahora, cuando funciona la función de conteo, solo hay una ID coincidente por ID.
Sin embargo, aquí es donde podemos usar una subconsulta; de hecho, podemos hacer dos tipos de subconsulta completamente diferentes que arrojarán los mismos resultados que necesitamos para esto. El primero es simplemente poner la subconsulta en la
select
cláusula. Esto significa que cada vez que obtenemos una fila de datos, la subconsulta se ejecutará, obtendrá una columna de datos y luego aparecerá en nuestra fila de datos.¡Y Bam !, esto nos haría bien. Sin embargo, si se dio cuenta, esta subconsulta tendrá que ejecutarse para cada fila de datos que devolvemos. Incluso en este pequeño ejemplo, solo tenemos cinco marcas diferentes de automóviles, pero la subconsulta se ejecutó once veces ya que tenemos once filas de datos que estamos devolviendo. Entonces, en este caso, no parece ser la forma más eficiente de escribir código.
Para un enfoque diferente, ejecutemos una subconsulta y pretendamos que es una tabla:
De acuerdo, tenemos los mismos resultados (ordenados ligeramente diferentes, parece que la base de datos quería devolver los resultados ordenados por la primera columna que seleccionamos esta vez), pero los mismos números correctos.
Entonces, ¿cuál es la diferencia entre los dos, y cuándo debemos usar cada tipo de subconsulta? Primero, asegurémonos de que entendemos cómo funciona esa segunda consulta. Seleccionamos dos tablas en la
from
cláusula de nuestra consulta, y luego escribimos una consulta y le dijimos a la base de datos que en realidad era una tabla, con lo cual la base de datos está perfectamente satisfecha. No puede haber algunos beneficios al uso de este método (así como algunas limitaciones). Lo principal es que esta subconsulta se ejecutó una vez . Si nuestra base de datos contuviera un gran volumen de datos, bien podría haber una mejora masiva sobre el primer método. Sin embargo, como estamos usando esto como una tabla, tenemos que incorporar filas adicionales de datos, para que puedan unirse de nuevo a nuestras filas de datos. También tenemos que asegurarnos de que haya suficientesfilas de datos si vamos a usar una unión simple como en la consulta anterior. Si recuerda, la unión solo retirará las filas que tienen datos coincidentes en ambos lados de la unión. Si no tenemos cuidado, esto podría resultar en que no se devuelvan datos válidos de nuestra tabla de autos si no hubiera una fila coincidente en esta subconsulta.Ahora, mirando hacia atrás en la primera subconsulta, también hay algunas limitaciones. Debido a que estamos volviendo a colocar los datos en una sola fila, SOLO podemos retirar una fila de datos. Subconsultas utilizados en la
select
cláusula de una consulta muy a menudo utilizan sólo una función de agregación tales comosum
,count
,max
u otra función de agregado similar. No tienen que hacerlo, pero a menudo así es como se escriben.Entonces, antes de continuar, echemos un vistazo rápido a dónde más podemos usar una subconsulta. Podemos usarlo en la
where
cláusula: ahora, este ejemplo es un poco artificial, ya que en nuestra base de datos, hay mejores formas de obtener los siguientes datos, pero ya que es solo un ejemplo, echemos un vistazo:Esto nos devuelve una lista de ID de marca y nombres de marca (la segunda columna solo se agrega para mostrarnos las marcas) que contienen la letra
o
en el nombre.Ahora, podríamos usar los resultados de esta consulta en una cláusula where:
Como puede ver, a pesar de que la subconsulta devolvía las tres identificaciones de marca, nuestra tabla de autos solo tenía entradas para dos de ellas.
En este caso, para más detalles, la subconsulta funciona como si escribiéramos el siguiente código:
Nuevamente, puede ver cómo una subconsulta vs entradas manuales ha cambiado el orden de las filas al regresar de la base de datos.
Mientras discutimos las subconsultas, veamos qué más podemos hacer con una subconsulta:
select
cláusula, algunas en lafrom
cláusula y un par más en lawhere
cláusula; solo recuerde que cada una de las que ingresa hace que su consulta sea más compleja y probablemente tome más tiempo para ejecutar.Si necesita escribir un código eficiente, puede ser beneficioso escribir la consulta de varias maneras y ver (ya sea cronometrando o usando un plan de explicación) cuál es la consulta óptima para obtener sus resultados. La primera forma en que funciona puede no ser siempre la mejor manera de hacerlo.
fuente
Parte 3 - Trucos y código eficiente
MySQL en () eficiencia
Pensé que agregaría algunos bits adicionales, para consejos y trucos que han surgido.
Una pregunta que veo surgir un poco, es ¿Cómo obtengo filas no coincidentes de dos tablas y veo la respuesta más comúnmente aceptada como algo como lo siguiente (según nuestra tabla de autos y marcas, que tiene a Holden como marca, pero no aparece en la tabla de coches):
Y sí , funcionará.
Sin embargo, es no eficiente en alguna base de datos. Aquí hay un enlace a una pregunta sobre el desbordamiento de la pila , y aquí hay un excelente artículo en profundidad si desea entrar en el meollo de la cuestión.
La respuesta corta es, si el optimizador no lo maneja eficientemente, puede ser mucho mejor usar una consulta como la siguiente para obtener filas no coincidentes:
Actualizar tabla con la misma tabla en subconsulta
Ahhh, otro viejo pero bueno: el viejo No puede especificar 'marcas' de tabla de destino para actualizar en la cláusula FROM .
MySQL no le permitirá ejecutar una
update...
consulta con una subselección en la misma tabla. Ahora, usted podría estar pensando, ¿por qué no simplemente incluirlo en la cláusula where? Pero, ¿qué sucede si desea actualizar solo la fila con lamax()
fecha entre un montón de otras filas? No puedes hacer eso exactamente en una cláusula where.Entonces, no podemos hacer eso, ¿eh? Bueno no exactamente. Existe una solución furtiva que desconoce un número sorprendentemente grande de usuarios, aunque incluye algunos hackers a los que deberá prestar atención.
Puede pegar la subconsulta dentro de otra subconsulta, lo que deja suficiente espacio entre las dos consultas para que funcione. Sin embargo, tenga en cuenta que puede ser más seguro pegar la consulta dentro de una transacción; esto evitará que se realicen otros cambios en las tablas mientras se ejecuta la consulta.
fuente
Puede usar el concepto de consultas múltiples en la palabra clave FROM. Déjame mostrarte un ejemplo:
Puede usar tantas tablas como desee. Utilice uniones externas y uniones donde sea necesario, incluso dentro de subconsultas de tabla.
Es un método muy fácil para involucrar tantas tablas como campos.
fuente
Espera que esto lo haga encontrar las tablas mientras estás leyendo:
jsfiddle
fuente