SQL query devuelve datos de varias tablas


Me gustaría saber lo siguiente:

  • cómo obtener datos de varias tablas en mi base de datos?
  • ¿qué tipos de métodos existen para hacer esto?
  • ¿qué son uniones y uniones y en qué se diferencian unas de otras?
  • ¿Cuándo debo usar cada uno en comparación con los demás?

Estoy planeando usar esto en mi aplicación (por ejemplo-PHP), pero no quiero ejecutar múltiples consultas contra la base de datos, ¿ qué opciones tengo para obtener datos de varias tablas en una sola consulta?

Nota: Estoy escribiendo esto ya que me gustaría poder enlazar a una guía bien escrita sobre las numerosas preguntas que constantemente me encuentro en la cola de PHP, para que pueda enlazar a esto para obtener más detalles cuando publique una respuesta.

Las respuestas cubren lo siguiente:

  1. Parte 1-Uniones y uniones
  2. Parte 2-Subconsultas
  3. Parte 3-Trucos y Código eficiente
  4. Parte 4 - Subconsultas en la Cláusula From
  5. Parte 5-Bolsa mixta de los Trucos de Juan
Author: Fluffeh, 2012-09-18

6 answers

Parte 1-Uniones y Uniones

Esta respuesta cubre:

  1. Parte 1
    • Unir dos o más tablas usando una unión interna (Ver la entrada de wikipedia para obtener información adicional)
    • Cómo usar una consulta de unión
    • Uniones externas izquierda y Derecha (esta respuesta de stackOverflow es excelente para describir tipos de uniones)
    • Intersect queries (y cómo reproducirlas si tu base de datos no las soporta ) - esta es una función de SQL-Server (ver info) y parte de la razón por la que escribí todo esto en primer lugar.
  2. Parte 2
    • Subconsultas: qué son, dónde se pueden usar y qué hay que tener en cuenta{[91]]}
    • Cartesiano 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 un número de otros tutoriales por ahí que utilizan la sintaxis ANSI-89 más antigua (y si estás acostumbrado a 89, puede parecer mucho menos intuitivo - pero todo lo que puedo decir es probarlo) ya que es mucho más fácil de entender cuando las consultas comienzan a ser más complejas. ¿Por qué usarlo? ¿Hay una ganancia de rendimiento? La respuesta corta es no, pero es más fácil de leer una vez que te acostumbras a ella. Es más fácil leer consultas escritas por otras personas usando esta sintaxis.

También voy a usar el concepto de un pequeño corral que tiene una base de datos para realizar un seguimiento de los coches que tiene disponibles. El propietario te ha contratado como su tipo de la Computadora y espera que usted sea capaz de colocar en él los datos que le pide a la caída de un sombrero.

He hecho una serie de tablas de búsqueda que serán utilizadas por la mesa final. Esto nos dará un modelo razonable para trabajar. Para empezar, voy a ejecutar mis consultas en una base de datos de ejemplo que tiene la siguiente estructura. Voy a tratar de pensar en errores comunes que se cometen al comenzar y explicar lo que va mal 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 de automóviles.

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 coches 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, va a ser más simple para esto usar diferentes tipos de automóviles en lugar de modelos de coches 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, atar todas estas otras mesas, la mesa que ata todo. El campo ID es en realidad el número de lote único utilizado para identificar los coches.

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 ejemplos a continuación de diferentes tipos de uniones y también nos dará suficientes datos para que valgan la pena.

Así que entrando en el grano de la misma, el jefe quiere saber Las identificaciones de todos los coches deportivos que has .

Esta es una simple combinación de dos tablas. Tenemos una tabla que identifica el modelo y la tabla con el stock disponible en ella. Como puede ver, los datos en la columna model de la tabla cars se relacionan con la columna models de la tabla cars que tenemos. Ahora, sabemos que la tabla de modelos tiene un ID de 1 para Sports así que vamos a escribir la combinación.

select
    ID,
    model
from
    cars
        join models
            on model=ID

Así que esta consulta se ve bien ¿verdad? Hemos identificado las dos tablas y contener la información que necesitamos y utilizar un join que identifica correctamente en qué columnas unirse.

ERROR 1052 (23000): Column 'ID' in field list is ambiguous

Oh noes! Un error en nuestra primera consulta! Sí, y es una ciruela. Verás, la consulta tiene de hecho 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. La primera 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 es probablemente más utilizado y se llama alias de tabla. Las tablas en este ejemplo tienen nombres simples y cortos, pero escribir algo como KPI_DAILY_SALES_BY_DEPARTMENT probablemente se haría viejo rápidamente, por lo que una manera simple es ponerle un apodo a la tabla como este:

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 pidió, por lo que necesitamos incluir una cláusula where en la declaración para obtener solo los autos deportivos como se pidió. Como prefiero el método de alias de tabla en lugar que usar los nombres de las tablas una y otra vez, me apegaré a ello a partir de este punto.

Claramente, necesitamos agregar una cláusula where a nuestra consulta. Podemos identificar autos deportivos ya sea por ID=1 o model='Sports'. Como el ID está indexado y la clave principal (y pasa a ser menos tipeo), vamos a usar 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 está feliz. Por supuesto, ser un jefe y nunca estar contento con lo que pidió, mira la información, luego dice Quiero los colores como bien .

Bien, así que 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 el ID de color del automóvil y esto se vincula a la columna ID de colores. Por lo tanto, de manera similar a la original, podemos unir 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)

Maldita sea, aunque la tabla estaba correctamente unida y las columnas relacionadas estaban vinculadas, nos olvidamos de extraer la información real de la nueva tabla que sólo enlazado.

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 nuestra espalda por un momento. Ahora, para explicar algo de esto con un poco más de detalle. Como puede ver, la cláusula from en nuestra instrucció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 intercambiadas, pero tiene menos sentido cuando volvemos a esta consulta para leerla en unos meses, por lo que a menudo es mejor intentar escribir una consulta eso será agradable y fácil de entender: exponerlo intuitivamente, usar sangría agradable para que todo sea lo más claro posible. Si continúa enseñando a otros, intente inculcar estas características en sus consultas, especialmente si las solucionará.

Es totalmente posible seguir enlazando 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 querer unir más de una columna en la instrucción join, aquí hay una ejemplo. Si la tabla models tenía modelos específicos de la marca y, por lo tanto, también tenía una columna llamada brand que se vinculaba a la tabla brands en el campo ID, podría hacerse de la siguiente 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
            and b.brand=d.ID
where
    b.ID=1

Puede ver que la consulta anterior no solo vincula las tablas unidas a la tabla principal cars, 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 dba habla por malo. Una unión cartesiana es aquella en la que se devuelven filas debido a que la información no indica a la base de datos cómo limitar los resultados, la consulta devuelve todas las filas que se ajustan al criterio.

Así que, para dar un ejemplo de una combinació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 pidió. En la consulta, pedimos para el ID de cars y el model de models. Sin embargo, porque no especificamos cómopara unir las tablas, la base de datos ha emparejado cada filade la primera tabla con cada fila de la segunda tabla.

Está bien, así que el jefe está de vuelta, y quiere más información de nuevo. Quiero la misma lista, pero también incluir 4WDs en ella.

Esto sin embargo, nos da una gran excusa para mirar dos maneras diferentes de lograr esto. Podríamos añadir 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

Mientras que el arriba funcionará perfectamente bien, vamos a verlo de manera diferente, esta es una gran excusa para mostrar cómo funcionará una consulta union.

Sabemos que lo siguiente devolverá todos los autos deportivos:{[84]]}

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 4WDs: {[84]]}

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 cláusula union all 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, seguido de los resultados de la segunda consulta.

En este ejemplo, por supuesto habría sido mucho más fácil usar simplemente la primera consulta, pero union las consultas pueden ser excelentes para casos específicos. Son una gran manera de devolver resultados específicos de tablas de tablas que no se unen fácilmente-o para el caso completamente 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 cada 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, usted podría preguntarse cuál es la diferencia entre usar union y union all. Una consulta union eliminará duplicados, mientras que una union all no lo hará. Esto significa que hay un pequeño golpe de rendimiento cuando se usa union sobre union all, pero los resultados pueden valer la pena no voy a especular sobre ese tipo de cosas en este caso.

En esta nota, podría valer la pena señalar algunas notas adicionales aquí.

  • Si queremos ordenar los resultados, podemos usar un order by pero ya no puedes usar el alias. En la consulta anterior, agregar un order by a.ID resultaría en un error - en lo que respecta a los resultados, la columna se llama ID en lugar de a.ID - a pesar de que el mismo alias se ha utilizado en ambas consultas.
  • Solo podemos tener uno order by declaración, y debe ser como la última declaración.

Para los siguientes ejemplos, estoy agregando algunas filas adicionales a nuestras tablas.

He añadido Holden a la tabla de marcas. También he añadido una fila en cars que tiene el valor color de 12 - que no tiene referencia en la tabla de colores.

Bien, el jefe está de vuelta otra vez, ladrando solicitudes - * Quiero un recuento de cada marca que llevamos y el número de coches en ella!- Típico, acabamos de llegar a un interesante sección de nuestra discusión y el jefe quiere más trabajo.

Rightyo, así que lo primero que tenemos que 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 tabla cars obtenemos el siguiente resultado:{[84]]}

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)

Que es, por supuesto, un problema - no estamos viendo ninguna mención de la encantadora marca Holden que agregué.

Esto se debe a que una combinación busca filas coincidentes en ambas tablas. Como no hay datos en los coches que es de tipo Holden no se devuelve. Aquí es donde podemos usar un outer join. 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 hermosa función de agregado para obtener un conteo 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, lejos los skulks jefe.

Ahora, para explicar esto con más detalle, las uniones externas pueden ser del tipo left o right. La Izquierda o Right 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 un full outer join que traerá resultados (coincidentes o no) de ambas tablas, pero esto no es compatible con todas las bases de datos.

Ahora, probablemente me imagino que en este punto en el tiempo, te estás preguntando si puede combinar 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 coches a marcas, no se especificó en la combinación de colores, por lo que esa combinación en particular solo devolverá los 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 uniones externas en la consulta y los resultados están llegando como se esperaba.

Ahora, ¿qué tal esos otros tipos de joins que preguntas? ¿Qué hay de las Intersecciones?

Bueno, no todas las bases de datos soportan intersection pero casi 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 un union como se describió anteriormente, pero la diferencia es que solo devuelve filas de datos que son idénticas (y quiero decir idénticas) entre las diversas consultas individuales a las que se une la unión. Solo se devolverán las filas que sean idénticas en todos los aspectos.

Un ejemplo simple sería como tal:{[84]]}

select
    *
from
    colors
where
    ID>2
intersect
select
    *
from
    colors
where
    id<4

Mientras que una consulta normal union devolvería todas las filas de la tabla (la primera consulta devolvería cualquier cosa sobre ID>2 y la segunda cualquier cosa que tuviera ID<4) lo que resultaría en un conjunto completo, una consulta intersect solo devolvería la fila que coincidía id=3 ya que cumple ambos criterios.

Ahora, si su base de datos no admite una consulta intersect, lo anterior se puede completar 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 entre dos tablas diferentes utilizando una base de datos que no soporta inherentemente una consulta de intersección, necesitará crear una combinación en cada columna de las tablas.

 411
Author: Fluffeh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:38

Ok, encontré este post muy interesante y me gustaría compartir algunos de mis conocimientos sobre la creación de una consulta. Gracias por esto 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 (s) error (s).)

Publicaré algunas de las preguntas más frecuentes en la etiqueta MySQL.


Truco No. 1 (filas que coinciden con múltiples condiciones)

Dado este esquema

CREATE TABLE MovieList
(
    ID INT,
    MovieName VARCHAR(25),
    CONSTRAINT ml_pk PRIMARY KEY (ID),
    CONSTRAINT ml_uq UNIQUE (MovieName)
);

INSERT INTO MovieList VALUES (1, 'American Pie');
INSERT INTO MovieList VALUES (2, 'The Notebook');
INSERT INTO MovieList VALUES (3, 'Discovery Channel: Africa');
INSERT INTO MovieList VALUES (4, 'Mr. Bean');
INSERT INTO MovieList VALUES (5, 'Expendables 2');

CREATE TABLE CategoryList
(
    MovieID INT,
    CategoryName VARCHAR(25),
    CONSTRAINT cl_uq UNIQUE(MovieID, CategoryName),
    CONSTRAINT cl_fk FOREIGN KEY (MovieID) REFERENCES MovieList(ID)
);

INSERT INTO CategoryList VALUES (1, 'Comedy');
INSERT INTO CategoryList VALUES (1, 'Romance');
INSERT INTO CategoryList VALUES (2, 'Romance');
INSERT INTO CategoryList VALUES (2, 'Drama');
INSERT INTO CategoryList VALUES (3, 'Documentary');
INSERT INTO CategoryList VALUES (4, 'Comedy');
INSERT INTO CategoryList VALUES (5, 'Comedy');
INSERT INTO CategoryList VALUES (5, 'Action');

PREGUNTA

Encuentra todas las películas que pertenecen al menos a ambos Comedy y Romance categorías.

Solución

Esta pregunta puede ser muy complicada a veces. Puede parecer que una consulta como esta será la respuesta: -

SELECT  DISTINCT a.MovieName
FROM    MovieList a
        INNER JOIN CategoryList b
            ON a.ID = b.MovieID
WHERE   b.CategoryName = 'Comedy' AND
        b.CategoryName = 'Romance'

SQLFiddle Demo

Lo cual es definitivamente muy incorrecto porque no produce ningún resultado. El 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 true, la segunda condición siempre es false. Por lo tanto, al usar el operador AND, ambas condiciones deben ser verdaderas; de lo contrario, será falsa. Otra pregunta es como esta,

SELECT  DISTINCT a.MovieName
FROM    MovieList a
        INNER JOIN CategoryList b
            ON a.ID = b.MovieID
WHERE   b.CategoryName IN ('Comedy','Romance')

SQLFiddle Demo

Y el resultado sigue siendo incorrecto porque coincide con el registro que tiene al menos una coincidencia en el categoryName. El solución real sería contando el número de instancias de registro por película. El número de instancia debe coincidir con el número total de los valores suministrados en la condición.

SELECT  a.MovieName
FROM    MovieList a
        INNER JOIN CategoryList b
            ON a.ID = b.MovieID
WHERE   b.CategoryName IN ('Comedy','Romance')
GROUP BY a.MovieName
HAVING COUNT(*) = 2

SQLFiddle Demo (la respuesta)


Truco No. 2 (registro máximo para cada entrada)

Dado esquema,

CREATE TABLE Software
(
    ID INT,
    SoftwareName VARCHAR(25),
    Descriptions VARCHAR(150),
    CONSTRAINT sw_pk PRIMARY KEY (ID),
    CONSTRAINT sw_uq UNIQUE (SoftwareName)  
);

INSERT INTO Software VALUES (1,'PaintMe','used for photo editing');
INSERT INTO Software VALUES (2,'World Map','contains map of different places of the world');
INSERT INTO Software VALUES (3,'Dictionary','contains description, synonym, antonym of the words');

CREATE TABLE VersionList
(
    SoftwareID INT,
    VersionNo INT,
    DateReleased DATE,
    CONSTRAINT sw_uq UNIQUE (SoftwareID, VersionNo),
    CONSTRAINT sw_fk FOREIGN KEY (SOftwareID) REFERENCES Software(ID)
);

INSERT INTO VersionList VALUES (3, 2, '2009-12-01');
INSERT INTO VersionList VALUES (3, 1, '2009-11-01');
INSERT INTO VersionList VALUES (3, 3, '2010-01-01');
INSERT INTO VersionList VALUES (2, 2, '2010-12-01');
INSERT INTO VersionList VALUES (2, 1, '2009-12-01');
INSERT INTO VersionList VALUES (1, 3, '2011-12-01');
INSERT INTO VersionList VALUES (1, 2, '2010-12-01');
INSERT INTO VersionList VALUES (1, 1, '2009-12-01');
INSERT INTO VersionList VALUES (1, 4, '2012-12-01');

PREGUNTA

Encontrar la última versión de cada software. Mostrar las siguientes columnas: SoftwareName,Descriptions,LatestVersion (de la columna VersionNo),DateReleased

Solución

Algunos desarrolladores SQL usan erróneamente la función MAX() aggregate. Tienden a crear así,

SELECT  a.SoftwareName, a.Descriptions,
        MAX(b.VersionNo) AS LatestVersion, b.DateReleased
FROM    Software a
        INNER JOIN VersionList b
            ON a.ID = b.SoftwareID
GROUP BY a.ID
ORDER BY a.ID

SQLFiddle Demo

(la mayoría de RDBMS genera un error de sintaxis en esto debido a no especificar algunas de las columnas no agregadas en la cláusula group by ) el resultado produce LatestVersion correcto en cada software pero obviamente el DateReleased son incorrectos. MySQL no soporta Window Functions y Common Table Expression todavía como algunos RDBMS ya lo hacen. La solución para este problema es crear un subquery que obtenga el máximo individual versionNo en cada software y luego unirse a las otras tablas.

SELECT  a.SoftwareName, a.Descriptions,
        b.LatestVersion, c.DateReleased
FROM    Software a
        INNER JOIN
        (
            SELECT  SoftwareID, MAX(VersionNO) LatestVersion
            FROM    VersionList
            GROUP BY SoftwareID
        ) b ON a.ID = b.SoftwareID
        INNER JOIN VersionList c
            ON  c.SoftwareID = b.SoftwareID AND
                c.VersionNO = b.LatestVersion
GROUP BY a.ID
ORDER BY a.ID

SQLFiddle Demo (la respuesta)


Así que eso fue todo. Publicaré otro tan pronto como recuerde cualquier otro FAQ en la etiqueta MySQL. 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

CREATE TABLE userList
(
    ID INT,
    NAME VARCHAR(20),
    CONSTRAINT us_pk PRIMARY KEY (ID),
    CONSTRAINT us_uq UNIQUE (NAME)  
);

INSERT INTO userList VALUES (1, 'Fluffeh');
INSERT INTO userList VALUES (2, 'John Woo');
INSERT INTO userList VALUES (3, 'hims056');

CREATE TABLE CONVERSATION
(
    ID INT,
    FROM_ID INT,
    TO_ID INT,
    MESSAGE VARCHAR(250),
    DeliveryDate DATE
);

INSERT INTO CONVERSATION VALUES (1, 1, 2, 'hi john', '2012-01-01');
INSERT INTO CONVERSATION VALUES (2, 2, 1, 'hello fluff', '2012-01-02');
INSERT INTO CONVERSATION VALUES (3, 1, 3, 'hey hims', '2012-01-03');
INSERT INTO CONVERSATION VALUES (4, 1, 3, 'please reply', '2012-01-04');
INSERT INTO CONVERSATION VALUES (5, 3, 1, 'how are you?', '2012-01-05');
INSERT INTO CONVERSATION VALUES (6, 3, 2, 'sample message!', '2012-01-05');

PREGUNTA

Encuentra la última conversación entre dos usuarios.

Solución

SELECT    b.Name SenderName,
          c.Name RecipientName,
          a.Message,
          a.DeliveryDate
FROM      Conversation a
          INNER JOIN userList b
            ON a.From_ID = b.ID
          INNER JOIN userList c
            ON a.To_ID = c.ID
WHERE     (LEAST(a.FROM_ID, a.TO_ID), GREATEST(a.FROM_ID, a.TO_ID), DeliveryDate)
IN
(
    SELECT  LEAST(FROM_ID, TO_ID) minFROM,
            GREATEST(FROM_ID, TO_ID) maxTo,
            MAX(DeliveryDate) maxDate
    FROM    Conversation
    GROUP BY minFROM, maxTo
)

SQLFiddle Demo

 94
Author: John Woo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:38

Parte 2-Subconsultas

Bien, ahora el jefe ha irrumpido de nuevo - Quiero una lista de todos nuestros coches 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 extras 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 maneras diferentes de usarlos.

Para nuestra solicitud, primero hagamos una simple consulta que enumerará cada coche y la marca:

select
    a.ID,
    b.brand
from
    cars a
        join brands b
            on a.brand=b.ID

Ahora, si simplemente quisiéramos obtener un recuento de autos ordenados por marca, podríamos, por supuesto, escribir esto:

select
    b.brand,
    count(a.ID) as countCars
from
    cars a
        join brands b
            on a.brand=b.ID
group by
    b.brand

+--------+-----------+
| brand  | countCars |
+--------+-----------+
| BMW    |         2 |
| Ford   |         2 |
| Nissan |         1 |
| Smart  |         1 |
| Toyota |         5 |
+--------+-----------+

Entonces, deberíamos ser capaces de simplemente agregar la función count a nuestra consulta original ¿verdad?

select
    a.ID,
    b.brand,
    count(a.ID) as countCars
from
    cars a
        join brands b
            on a.brand=b.ID
group by
    a.ID,
    b.brand

+----+--------+-----------+
| ID | brand  | countCars |
+----+--------+-----------+
|  1 | Toyota |         1 |
|  2 | Ford   |         1 |
|  3 | Nissan |         1 |
|  4 | Smart  |         1 |
|  5 | Toyota |         1 |
|  6 | BMW    |         1 |
|  7 | Ford   |         1 |
|  8 | Toyota |         1 |
|  9 | Toyota |         1 |
| 10 | BMW    |         1 |
| 11 | Toyota |         1 |
+----+--------+-----------+
11 rows in set (0.00 sec)

Tristemente, no, no podemos hacer eso. La razón es que cuando añadimos en la identificación del coche (columna a.ID) tenemos que agregarlo al grupo por - así que ahora, cuando la función count funciona, solo hay un ID coincidente por ID.

Sin embargo, aquí es donde podemos usar una subconsulta; de hecho, podemos hacer dos tipos completamente diferentes de subconsulta que devolverán los mismos resultados que necesitamos para esto. La primera es simplemente poner la subconsulta en la cláusula select. Esto significa que cada vez que obtenemos una fila de datos, la subconsulta se ejecutará, obtendrá una columna de datos y luego la colocará en nuestra fila de datos.

select
    a.ID,
    b.brand,
    (
    select
        count(c.ID)
    from
        cars c
    where
        a.brand=c.brand
    ) as countCars
from
    cars a
        join brands b
            on a.brand=b.ID

+----+--------+-----------+
| ID | brand  | countCars |
+----+--------+-----------+
|  2 | Ford   |         2 |
|  7 | Ford   |         2 |
|  1 | Toyota |         5 |
|  5 | Toyota |         5 |
|  8 | Toyota |         5 |
|  9 | Toyota |         5 |
| 11 | Toyota |         5 |
|  3 | Nissan |         1 |
|  4 | Smart  |         1 |
|  6 | BMW    |         2 |
| 10 | BMW    |         2 |
+----+--------+-----------+
11 rows in set (0.00 sec)

Y Bam!, esto nos serviría. Si lo notaste, sin embargo, esta consulta secundaria tendrá que ejecutarse para todos y cada uno una sola 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 la forma más eficiente de escribir código.

Para un enfoque diferente, ejecutemos una subconsulta y finjamos que es una tabla:

select
    a.ID,
    b.brand,
    d.countCars
from
    cars a
        join brands b
            on a.brand=b.ID
        join
            (
            select
                c.brand,
                count(c.ID) as countCars
            from
                cars c
            group by
                c.brand
            ) d
            on a.brand=d.brand

+----+--------+-----------+
| ID | brand  | countCars |
+----+--------+-----------+
|  1 | Toyota |         5 |
|  2 | Ford   |         2 |
|  3 | Nissan |         1 |
|  4 | Smart  |         1 |
|  5 | Toyota |         5 |
|  6 | BMW    |         2 |
|  7 | Ford   |         2 |
|  8 | Toyota |         5 |
|  9 | Toyota |         5 |
| 10 | BMW    |         2 |
| 11 | Toyota |         5 |
+----+--------+-----------+
11 rows in set (0.00 sec)

Bien, así que tenemos los mismos resultados (ordenados ligeramente diferente-parece que la base de datos quería devolver los resultados ordenados por el primera columna que elegimos 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 entender cómo funciona esa segunda consulta. Seleccionamos dos tablas en la cláusula from 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. Hay puede ser algunos beneficios de usar este método (así como algunos limitacion). Lo más importante es que esta subconsulta se ejecutó una vez. Si nuestra base de datos contenía 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 traer filas adicionales de datos, para que puedan unirse de nuevo a nuestras filas de datos. También tenemos que estar seguros de que hay suficientes filas de datos si vamos a usar una combinación simple como en la consulta anterior. Si recuerdas, la unión solo tirará filas posteriores 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 cars 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 recuperando datos en una sola fila, podemos SOLO recuperar una fila de datos. Las subconsultas utilizadas en la cláusula select de una consulta muy a menudo usan solo una función aggregate tales como sum, count, max u otra función agregada similar. No tienen que, pero así es a menudo como se escriben.

Así que, antes de seguir adelante, echemos un vistazo rápido a dónde más podemos usar una subconsulta. Podemos usarlo en la cláusula where - ahora, este ejemplo es un poco artificial como en nuestra base de datos, hay mejores formas de obtener los siguientes datos, pero viendo que es solo para un ejemplo, echemos un vistazo:

select
    ID,
    brand
from
    brands
where
    brand like '%o%'

+----+--------+
| ID | brand  |
+----+--------+
|  1 | Ford   |
|  2 | Toyota |
|  6 | Holden |
+----+--------+
3 rows in set (0.00 sec)

Esto nos devuelve una lista de marca IDs 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:

select
    a.ID,
    b.brand
from
    cars a
        join brands b
            on a.brand=b.ID
where
    a.brand in
        (
        select
            ID
        from
            brands
        where
            brand like '%o%'
        )

+----+--------+
| ID | brand  |
+----+--------+
|  2 | Ford   |
|  7 | Ford   |
|  1 | Toyota |
|  5 | Toyota |
|  8 | Toyota |
|  9 | Toyota |
| 11 | Toyota |
+----+--------+
7 rows in set (0.00 sec)

Como puede ver, a pesar de que la subconsulta estaba devolviendo los tres identificadores de marca, nuestra tabla cars solo tenía entradas para dos de ellos.

En este caso, para más detalles, la subconsulta funciona como si hubiéramos escrito el siguiente código:

select
    a.ID,
    b.brand
from
    cars a
        join brands b
            on a.brand=b.ID
where
    a.brand in (1,2,6)

+----+--------+
| ID | brand  |
+----+--------+
|  1 | Toyota |
|  2 | Ford   |
|  5 | Toyota |
|  7 | Ford   |
|  8 | Toyota |
|  9 | Toyota |
| 11 | Toyota |
+----+--------+
7 rows in set (0.00 sec)

De nuevo, se puede ver cómo un subconsulta vs entradas manuales ha cambiado el orden de las filas al regresar de la base de datos.

Mientras estamos discutiendo subconsultas, veamos qué más podemos hacer con una subconsultas:

  • Puede colocar una subconsulta dentro de otra subconsulta, y así sucesivamente. Hay un límite que depende de su base de datos, pero a falta de funciones recursivas de algún programador loco y maníaco, la mayoría de la gente nunca llegará a ese límite.
  • Puede colocar un número de subconsultas en un una sola consulta, unas pocas en la cláusula select, algunas en la cláusula from y un par más en la cláusula where - solo recuerde que cada una de ellas hace que su consulta sea más compleja y es probable que tarde más en ejecutarse.

Si necesita escribir un código eficiente, puede ser beneficioso escribir la consulta de varias maneras y ver (ya sea cronometrándola o utilizando 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 de hacerlo.

 59
Author: Fluffeh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-19 09:47:16

Parte 3-Trucos y Código Eficiente

MySQL in() efficiency

Pensé en agregar 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 (basado en nuestra tabla de autos y marcas, que tiene Holden listado como una marca, pero no aparece en cuadro):

select
    a.ID,
    a.brand
from
    brands a
where
    a.ID not in(select brand from cars)

Y funcionará.

+----+--------+
| ID | brand  |
+----+--------+
|  6 | Holden |
+----+--------+
1 row in set (0.00 sec)

Sin embargo es no eficiente en alguna base de datos. Aquí hay un enlace a una pregunta de desbordamiento de pilapreguntando al respecto, y aquí hay un excelente artículo en profundidad si quieres entrar en lo esencial.

La respuesta corta es, si el optimizador no lo maneja de manera eficiente, puede ser mucho mejor usar una consulta como la siguiente para obtener filas no coincidentes:

select
    a.brand
from
    brands a
        left join cars b
            on a.id=b.brand
where
    b.brand is null

+--------+
| brand  |
+--------+
| Holden |
+--------+
1 row in set (0.00 sec)

Actualizar Tabla con la misma tabla en subconsulta

Ahhh, otro viejo pero bueno - el viejo No se puede especificar la tabla de destino 'marcas' para la actualización en la cláusula FROM.

MySQL no le permitirá ejecutar una consulta update... con una subselección en la misma tabla. Ahora, usted podría estar pensando, ¿por qué no sólo la bofetada en la cláusula dónde derecha? Pero lo que si desea actualizar solo la fila con la fecha max() amoung un montón de otras filas? No puedes hacer eso exactamente en un lugar clausula.

update 
    brands 
set 
    brand='Holden' 
where 
    id=
        (select 
            id 
        from 
            brands 
        where 
            id=6);
ERROR 1093 (HY000): You can't specify target table 'brands' 
for update in FROM clause

Entonces, no podemos hacer eso ¿eh? Bueno, no exactamente. Hay una solución furtiva que un número sorprendentemente grande de usuarios no conoce, aunque incluye algo de hacker a lo que deberá prestar atención.

Puede pegar la subconsulta dentro de otra subconsulta, lo que pone suficiente espacio entre las dos consultas para que funcione. Sin embargo, tenga en cuenta que podría ser más seguro para pegar la consulta dentro de una transacción-esto evitará que cualquier otro cambio sea realizado en las tablas mientras se está ejecutando la consulta.

update 
    brands 
set 
    brand='Holden' 
where id=
    (select 
        id 
    from 
        (select 
            id 
        from 
            brands 
        where 
            id=6
        ) 
    as updateTable);

Query OK, 0 rows affected (0.02 sec)
Rows matched: 1  Changed: 0  Warnings: 0
 55
Author: Fluffeh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:32

Puede utilizar el concepto de múltiples consultas en la palabra clave FROM. Permítanme mostrarles un ejemplo:

SELECT DISTINCT e.id,e.name,d.name,lap.lappy LAPTOP_MAKE,c_loc.cnty COUNTY    
FROM  (
          SELECT c.id cnty,l.name
          FROM   county c, location l
          WHERE  c.id=l.county_id AND l.end_Date IS NOT NULL
      ) c_loc, emp e 
      INNER JOIN dept d ON e.deptno =d.id
      LEFT JOIN 
      ( 
         SELECT l.id lappy, c.name cmpy
         FROM   laptop l, company c
         WHERE l.make = c.name
      ) lap ON e.cmpy_id=lap.cmpy

Puede utilizar tantas tablas como desee. Use uniones externas y unión donde sea necesario, incluso dentro de subconsultas de tabla.

Ese es un método muy fácil de involucrar tantos como tablas y campos.

 16
Author: prashant1988,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-27 04:27:04

Espera que esto haga que encuentre las tablas mientras lee la cosa:

Jsfiddle

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    |                |
+-------+-------------+------+-----+---------+----------------+
 5
Author: Anton Chan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-19 09:33:40