Aiuto con Query. Ricerca di record che hanno le stesse relazioni (MySQL)
-
16-10-2019 - |
Domanda
Ho una tabella di annunci che ha una relazione molti a molti con un tavolo taxon. L'aspetto di struttura tabella come questa:
listings
----------------
id (int)
name (varchar)
listings_taxons
----------------
listing_id (int)
taxon_id (int)
taxons
----------------
id (int)
name (varchar)
Il mio obiettivo è quello di selezionare tutte le righe della tabella listings
che ha un elenco delle corrispondenze di ID taxon. Ogni record elenca tornato deve avere un rapporto con i due taxon, in modo tale che ottengo il set di record che contiene l'intersezione dei record tra i due taxon.
Esempio: Ho un annuncio chiamato "silenziatore" ed ha le seguenti taxon: "Ford", "Mustang", "scarico". Se domanda che tutto l'elenco con "Ford" e "scarico" dovrei ottenere tutti gli annunci che hanno "Ford" e "scarico", come taxon.
Come potrei costruire questa domanda in modo efficiente?
Soluzione
SELECT B.name
FROM
(
SELECT BB.listing_id id,COUNT(1) taxon_count
FROM
(
SELECT id taxon_id FROM taxons
WHERE name IN ('Ford','Exhaust')
) AA
INNER JOIN listings_taxons BB
USING (taxon_id)
GROUP BY listing_id HAVING COUNT(1) = 2
) A
INNER JOIN listings B USING (id);
Una sottoquery riporterà tutti listing_ids che hanno Ford, scarico, o entrambi. Facendo GROUP BY conteggio entro sottoquery A dà alcun id messa che ha un COUNT (1) di 2 ha sia Ford e ids taxon scarico becasue BB.listing_id Would appare AVERE due volte così COUNT (1) = 2. Quindi sottoquery A ha un INNER JOIN con annunci.
Assicurarsi di avere i seguenti indici
ALTER TABLE listings_taxons ADD INDEX taxon_listing_ndx (taxon_id,listing_id);
ALTER TABLE taxons ADD INDEX name_id_ndx (name,id);
Ecco alcuni dati di esempio
drop database if exists nwwatson;
create database nwwatson;
use nwwatson
create table listings
(id int not null auto_increment,
name varchar(25),
primary key (id),
key (name));
create table taxons like listings;
create table listings_taxons
(
listing_id int,
taxon_id int,
primary key (listing_id,taxon_id),
unique key (taxon_id,listing_id)
);
insert into listings (name) values ('SteeringWheel'),('WindShield'),('Muffler'),('AC');
insert into taxons (name) values ('Ford'),('Escort'),('Buick'),('Exhaust'),('Mustard');
insert into listings_taxons values
(1,1),(1,3),(1,5),(2,1),(2,2),(2,3),(2,5),
(3,1),(3,4),(4,2),(4,3),(4,4),(5,1),(5,5);
SELECT * FROM listings;
SELECT * FROM taxons;
SELECT * FROM listings_taxons;
SELECT B.name
FROM
(
SELECT BB.listing_id id,COUNT(1) taxon_count
FROM
(
SELECT id taxon_id FROM taxons
WHERE name IN ('Ford','Exhaust')
) AA
INNER JOIN listings_taxons BB
USING (taxon_id)
GROUP BY listing_id HAVING COUNT(1) = 2
) A
INNER JOIN listings B USING (id);
Qui si è eseguito
mysql> drop database if exists nwwatson;
Query OK, 3 rows affected (0.09 sec)
mysql> create database nwwatson;
Query OK, 1 row affected (0.00 sec)
mysql> use nwwatson
Database changed
mysql> create table listings
-> (
-> id int not null auto_increment,
-> name varchar(25),
-> primary key (id),
-> key (name)
-> );
Query OK, 0 rows affected (0.08 sec)
mysql> create table taxons like listings;
Query OK, 0 rows affected (0.05 sec)
mysql> create table listings_taxons
-> (
-> listing_id int,
-> taxon_id int,
-> primary key (listing_id,taxon_id),
-> unique key (taxon_id,listing_id)
-> );
Query OK, 0 rows affected (0.08 sec)
mysql> insert into listings (name) values ('SteeringWheel'),('WindShield'),('Muffler'),('AC');
Query OK, 4 rows affected (0.06 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> insert into taxons (name) values ('Ford'),('Escort'),('Buick'),('Exhaust'),('Mustard');
Query OK, 5 rows affected (0.06 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> insert into listings_taxons values
-> (1,1),(1,3),(1,5),(2,1),(2,2),(2,3),(2,5),
-> (3,1),(3,4),(4,2),(4,3),(4,4),(5,1),(5,5);
Query OK, 14 rows affected (0.11 sec)
Records: 14 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM listings;
+----+---------------+
| id | name |
+----+---------------+
| 4 | AC |
| 3 | Muffler |
| 1 | SteeringWheel |
| 2 | WindShield |
+----+---------------+
4 rows in set (0.00 sec)
mysql> SELECT * FROM taxons;
+----+---------+
| id | name |
+----+---------+
| 3 | Buick |
| 2 | Escort |
| 4 | Exhaust |
| 1 | Ford |
| 5 | Mustard |
+----+---------+
5 rows in set (0.00 sec)
mysql> SELECT * FROM listings_taxons;
+------------+----------+
| listing_id | taxon_id |
+------------+----------+
| 1 | 1 |
| 1 | 3 |
| 1 | 5 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
| 2 | 5 |
| 3 | 1 |
| 3 | 4 |
| 4 | 2 |
| 4 | 3 |
| 4 | 4 |
| 5 | 1 |
| 5 | 5 |
+------------+----------+
14 rows in set (0.00 sec)
mysql> SELECT B.name
-> FROM
-> (
-> SELECT BB.listing_id id,COUNT(1) taxon_count
-> FROM
-> (
-> SELECT id taxon_id FROM taxons
-> WHERE name IN ('Ford','Exhaust')
-> ) AA
-> INNER JOIN listings_taxons BB
-> USING (taxon_id)
-> GROUP BY listing_id HAVING COUNT(1) = 2
-> ) A
-> INNER JOIN listings B USING (id);
+---------+
| name |
+---------+
| Muffler |
+---------+
1 row in set (0.00 sec)
mysql>
fare un tentativo !!!
Altri suggerimenti
Se ho capito bene, si desidera eseguire relazionale-divisione. Prova questa domanda con un sacco di modi diversi per realizzare questo: Come per filtrare i risultati di SQL in una ha-molti-through relazione .
Vorrei andare per la (multipla) Soluzione JOIN
ma si può sempre test con i dati e le query:
SELECT
li.*
FROM
listings AS li
JOIN
listings_taxons AS lt1
ON lt1.listing_id = li.id
JOIN
taxons AS t1
ON t1.id = lt1.taxon_id
AND t1.name = 'Ford'
JOIN
listings_taxons AS lt2
ON lt2.listing_id = li.id
JOIN
taxons AS t2
ON t2.id = lt2.taxon_id
AND t2.name = 'Exhaust'
Ci sono molti modi per risolvere questo caso classico di un divisione relazionale .
Per un di taxon (più di pochi), questa forma è uno dei sintatticamente più breve:
SELECT l.*
FROM (
SELECT lt.listing_id
FROM taxons t
JOIN listings_taxons lt ON lt.taxon_id = t.id
WHERE t.name IN ('Ford', 'Mustang', 'Exhaust')
GROUP BY lt.listing_id
HAVING COUNT(*) = 3
) x
JOIN listings l ON l.id = x.listing_id;
Questo presuppone un vincolo UNIQUE
su (listing_id, taxon_id)
nella tabella listings_taxons
.
confronta con gli altri metodi di cui al presente correlati domanda @ypercube già legato alla , per trovare se è tra i più veloci, anche.
SELECT listings.*
FROM listings
INNER JOIN listings_taxons ON listings.id = listings_taxons.listing_id
INNER JOIN taxons ON listing_taxons.taxon_id = taxon.id
WHERE taxon.id in
(SELECT taxon_id
FROM taxon
WHERE name LIKE '%whatever%' OR name LIKE '%another%');
E 'questo che vuoi dire?