sql >> Base de Datos >  >> RDS >> Mysql

Consulta SQL devuelve datos de varias tablas

Parte 1:uniones y uniones

Esta respuesta cubre:

  1. Parte 1
  2. Parte 2
    • Subconsultas:qué son, dónde se pueden usar y a qué prestar atención
    • 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 combinación ANSI-92. Esto puede ser diferente a una serie de otros tutoriales que usan la sintaxis ANSI-89 más antigua (y si está acostumbrado a 89, puede parecer mucho menos intuitivo, pero todo lo que puedo decir es que lo intente) como es mucho más fácil de entender cuando las consultas comienzan a volverse 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. Es más fácil leer consultas escritas por otras personas usando esta sintaxis.

También voy a usar el concepto de un patio pequeño que tiene una base de datos para realizar un seguimiento de los autos que tiene disponibles. El propietario lo ha contratado como su informático informático y espera que pueda enviarle los datos que solicita en un abrir y cerrar de ojos.

He creado una serie de tablas de búsqueda que se utilizarán en la tabla final. Esto nos dará un modelo razonable a partir del cual 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é es lo que falla con ellos, y, 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 autos.

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 autos que el astillero 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 autos, será más sencillo usar diferentes tipos de autos en lugar de modelos de autos 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 atar todas estas otras mesas, la mesa que une todo. El campo ID es en realidad el número de lote único que se utiliza para identificar los 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 brindará suficientes datos (espero) para cubrir los siguientes ejemplos de diferentes tipos de uniones y también brindará suficientes datos para que valgan la pena.

Entonces, para entrar en materia, el jefe quiere saber Las identificaciones de todos los autos deportivos que tiene .

Esta es una combinación simple de dos tablas. Disponemos de una tabla que identifica el modelo y la tabla con el stock disponible en ella. Como puede ver, los datos en el model columna de los cars la tabla se relaciona con los models columna de los cars mesa que tenemos. Ahora, sabemos que la tabla de modelos tiene una ID de 1 para Sports así que escribamos 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 contienen la información que necesitamos y usamos una unión que identifica correctamente en qué columnas unirse.

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 de hecho tiene las columnas correctas, pero algunas de ellas existen en ambas tablas, por lo que la base de datos se confunde sobre a qué columna real nos referimos y dónde. Hay dos soluciones para solucionar esto. El primero es bueno 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 más a menudo y se llama creación de alias de tabla. Las tablas de este ejemplo tienen nombres sencillos, breves y agradables, pero escribe algo como KPI_DAILY_SALES_BY_DEPARTMENT probablemente envejecería rápidamente, por lo que una forma simple es apodar 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 que se solicitaron. Como prefiero el método de alias de tabla en lugar de usar los nombres de las tablas una y otra vez, me ceñiré a él 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 resulta que se escribe 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 está feliz. Por supuesto, siendo un jefe y nunca contento con lo que pidió, mira la información y luego dice Yo también quiero los colores. .

Bien, ya tenemos una buena parte de nuestra consulta escrita, pero necesitamos usar una tercera tabla que es colors. Ahora, nuestra tabla de información principal cars almacena la identificación del color del automóvil y esto se vincula de nuevo a la columna de identificación de colores. Entonces, 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 se unió correctamente y las columnas relacionadas estaban vinculadas, 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 nuestra espalda por un momento. Ahora, para explicar algo de esto con un poco más de detalle. Como puede ver, el from La 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 leerlo dentro de unos meses, por lo que a menudo es mejor tratar de escribir una consulta que sea agradable y fácil de entender:dispóngala de manera intuitiva, use una buena sangría para que todo sea lo más claro posible. continúe enseñando a otros, intente inculcar estas características en sus consultas, especialmente si las solucionará.

Es totalmente 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

Aunque olvidé incluir una tabla en la que podríamos querer unir más de una columna en join declaración, aquí hay un ejemplo. Si los models la tabla tenía modelos específicos de la marca y, por lo tanto, también tenía una columna llamada brand que se vinculaba con las 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

Como puede ver, la consulta anterior no solo vincula las tablas unidas a los cars principales tabla, pero también especifica uniones entre las tablas ya unidas. Si esto no se hizo, el resultado se denomina unión cartesiana, que es dba hablar mal. Una unió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 todos. 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 pidió. En la consulta, solicitamos el ID de cars y el model de models . Sin embargo, debido a que no especificamos cómo para unir las tablas, la base de datos ha hecho coincidir cada fila de la primera tabla con every fila de la segunda tabla.

Bien, el jefe ha vuelto y quiere más información de nuevo. Quiero la misma lista, pero también incluir 4WD en ella .

Sin embargo, esto nos da una gran excusa para buscar 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, mirémoslo de otra manera, esta es una gran excusa para mostrar cómo una union la consulta funcionará.

Sabemos que los siguientes devolverán 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, agregando un 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 union las consultas pueden ser excelentes para casos específicos. Son una excelente manera de devolver resultados específicos de tablas que no se pueden unir 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 todas las demás consultas a continuación.
  • Los nombres de las columnas de la primera consulta se utilizarán para identificar todo el conjunto de resultados.
  • El número de columnas en cada consulta debe ser el mismo.

Ahora, es posible que se esté preguntando qué el la diferencia es entre usar union y union all . Un union la consulta eliminará los duplicados, mientras que una union all no lo haré Esto significa que hay un pequeño impacto en el rendimiento cuando se usa union sobre 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 puedes 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 ID en lugar de a.ID - aunque se haya utilizado el mismo alias en ambas consultas.
  • Solo podemos tener un order by declaración, y debe ser como la última declaración.

Para los siguientes ejemplos, agregaré algunas filas adicionales a nuestras tablas.

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

De acuerdo, el jefe está de regreso, ladrando solicitudes:*¡Quiero un recuento de cada marca que tenemos y la cantidad de autos en ella!' - Típico, acabamos de llegar a una sección interesante de nuestra discusión y el jefe quiere más trabajo. .

Bien, lo primero que debemos hacer es obtener una lista completa de las 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 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 vemos ninguna mención de la adorable Holden. marca que agregué.

Esto se debe a que una unión busca filas coincidentes en ambos mesas. Como no hay datos en los coches que sean de tipo Holden no se devuelve. Aquí es donde podemos usar un outer entrar. 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 agregada para obtener un conteo y quitarnos de encima al jefe 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 de la left o right tipo. La Izquierda o la Derecha define qué tabla es totalmente incluido. Una left outer join incluirá todas las filas de la tabla de la izquierda, mientras que (adivinaste) una 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 que coincidan o no) de ambos tablas, pero esto no es compatible con todas las bases de datos.

Ahora, probablemente me imagino que en este momento, se está preguntando si puede o no fusionar tipos de combinación en una consulta, y la respuesta es sí, definitivamente puede hacerlo.

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? 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 traerá resultados que coincidan en ambas tablas.

Esta es 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 son los esperados.

Ahora, ¿qué hay de esos otros tipos de uniones que preguntas? ¿Qué pasa con las intersecciones?

Bueno, no todas las bases de datos admiten la intersection pero casi todas las bases de datos le permitirán crear una intersección a través de una combinación (o una declaración bien estructurada de where al menos).

Una intersección es un tipo de unión algo similar a una union como se describe arriba, pero la diferencia es que solo devuelve filas de datos que son idénticos (y me refiero a 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 normal la consulta devolvería todas las filas de la tabla (la primera consulta devolvería cualquier cosa sobre ID>2 y el segundo cualquier cosa que tenga ID<4 ) que daría como resultado un conjunto completo, una consulta de intersección solo devolvería la fila que coincide con id=3 ya que cumple con ambos criterios.

Ahora, si su base de datos no admite un intersect consulta, lo anterior se puede lograr 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 de forma inherente una consulta de intersección, deberá crear una unión en cada columna de las mesas.