La query SQL restituisce dati da più tabelle


434

Vorrei sapere quanto segue:

  • come ottenere dati da più tabelle nel mio database?
  • che tipi di metodi ci sono per farlo?
  • cosa sono i join e i sindacati e in che cosa differiscono l'uno dall'altro?
  • Quando dovrei usare ognuno rispetto agli altri?

Sto pensando di usarlo nella mia (ad esempio - PHP) applicazione, ma non voglio eseguire più query sul database, quali opzioni devo avere per ottenere dati da più tabelle in una singola query?

Nota: sto scrivendo questo come vorrei essere in grado di collegarmi a una guida ben scritta sulle numerose domande che incontro costantemente nella coda di PHP, quindi posso collegarmi a questo per ulteriori dettagli quando invio una risposta.

Le risposte coprono quanto segue:

  1. Parte 1 - Associazioni e sindacati
  2. Parte 2 - Sottoquery
  3. Parte 3 - Trucchi e codice efficiente
  4. Parte 4 - Sottoquery nella clausola From
  5. Parte 5 - Borsa mista di John's Tricks

Risposte:


469

Parte 1 - Associazioni e sindacati

Questa risposta riguarda:

  1. Parte 1
  2. Parte 2
    • Sottoquery: cosa sono, dove possono essere utilizzate e a cosa prestare attenzione
    • Cartesian si unisce ad AKA - Oh, la miseria!

Esistono diversi modi per recuperare dati da più tabelle in un database. In questa risposta, userò la sintassi del join ANSI-92. Questo potrebbe essere diverso da un numero di altri tutorial là fuori che usano la vecchia sintassi ANSI-89 (e se sei abituato a 89, può sembrare molto meno intuitivo - ma tutto ciò che posso dire è provarlo) in quanto è molto più facile per capire quando le query iniziano a diventare più complesse. Perché usarlo C'è un guadagno in termini di prestazioni? La risposta breve è no, ma è più facile da leggere quando ci si abitua. È più facile leggere le query scritte da altre persone che utilizzano questa sintassi.

Userò anche il concetto di un piccolo cortile con un database per tenere traccia di quali auto ha a disposizione. Il proprietario ti ha assunto come suo informatico informatico e si aspetta che tu sia in grado di rilasciargli i dati che chiede al volo di un cappello.

Ho creato una serie di tabelle di ricerca che verranno utilizzate dal tavolo finale. Questo ci darà un modello ragionevole su cui lavorare. Per iniziare, eseguirò le mie query su un database di esempio che ha la seguente struttura. Proverò a pensare agli errori comuni che vengono fatti all'inizio e spiegherò cosa non va in loro - oltre ovviamente a mostrare come correggerli.

La prima tabella è semplicemente un elenco di colori in modo da sapere quali colori abbiamo nel cortile dell'auto.

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 tabella dei marchi identifica le diverse marche di auto che il cantiere potrebbe eventualmente vendere.

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 tabella dei modelli coprirà diversi tipi di auto, sarà più semplice per questo utilizzare diversi tipi di auto piuttosto che modelli di auto reali.

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)

E infine, per legare tutti questi altri tavoli, il tavolo che lega tutto insieme. Il campo ID è in realtà il numero di lotto univoco utilizzato per identificare le auto.

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)

Questo ci fornirà dati sufficienti (spero) per coprire gli esempi seguenti dei diversi tipi di join e anche dati sufficienti per renderli utili.

Quindi, entrando in gioco, il capo vuole conoscere gli ID di tutte le auto sportive che ha .

Questo è un semplice join a due tabelle. Abbiamo una tabella che identifica il modello e la tabella con lo stock disponibile al suo interno. Come puoi vedere, i dati nella modelcolonna della carstabella si riferiscono alla modelscolonna della carstabella che abbiamo. Ora sappiamo che la tabella dei modelli ha un ID di 1for Sportsquindi scriviamo il join.

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

Quindi questa query sembra buona, vero? Abbiamo identificato le due tabelle e contenente le informazioni di cui abbiamo bisogno e utilizziamo un join che identifichi correttamente su quali colonne unire.

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

Oh no! Un errore nella nostra prima query! Sì, ed è una prugna. Vedete, la query ha effettivamente le colonne giuste, ma alcune di esse esistono in entrambe le tabelle, quindi il database si confonde su quale colonna reale intendiamo e dove. Esistono due soluzioni per risolvere questo problema. Il primo è carino e semplice, possiamo usare tableName.columnNameper dire al database esattamente cosa intendiamo, in questo modo:

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)

L'altro è probabilmente più spesso usato e si chiama aliasing della tabella. Le tabelle in questo esempio hanno nomi semplici belli e brevi, ma digitare qualcosa del genere KPI_DAILY_SALES_BY_DEPARTMENTprobabilmente invecchierebbe rapidamente, quindi un modo semplice è soprannominare la tabella in questo modo:

select
    a.ID,
    b.model
from
    cars a
        join models b
            on a.model=b.ID

Ora, torniamo alla richiesta. Come puoi vedere, abbiamo le informazioni di cui abbiamo bisogno, ma abbiamo anche informazioni che non sono state richieste, quindi dobbiamo includere una clausola where nella dichiarazione per ottenere solo le auto sportive come richiesto. Dato che preferisco il metodo alias di tabella piuttosto che usare i nomi delle tabelle più e più volte, da questo punto in poi mi atterrò.

Chiaramente, dobbiamo aggiungere una clausola where alla nostra query. Siamo in grado di identificare le auto sportive da ID=1o model='Sports'. Poiché l'ID è indicizzato e la chiave primaria (e sembra essere meno digitante), usiamola nella nostra query.

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! Il capo è felice. Certo, essendo un capo e non essere mai contento di ciò che ha chiesto, guarda le informazioni, poi dice che voglio anche i colori .

Ok, quindi abbiamo già scritto buona parte della nostra query, ma dobbiamo usare una terza tabella che è i colori. Ora, la nostra tabella di informazioni principale carsmemorizza l'ID colore dell'auto e questo rimanda alla colonna ID colori. Quindi, in modo simile all'originale, possiamo unire un terzo tavolo:

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)

Dannazione, sebbene la tabella sia stata correttamente unita e le relative colonne siano state collegate, abbiamo dimenticato di estrarre le informazioni effettive dalla nuova tabella che abbiamo appena collegato.

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)

Bene, questo è il capo che ci sta alle spalle per un momento. Ora, per spiegare alcuni di questi in modo un po 'più dettagliato. Come puoi vedere, la fromclausola nella nostra dichiarazione collega la nostra tabella principale (utilizzo spesso una tabella che contiene informazioni anziché una tabella di ricerca o dimensione. La query funzionerebbe altrettanto bene con le tabelle tutte invertite, ma avrebbe meno senso quando torniamo a questa query per leggerla tra qualche mese, quindi è spesso meglio provare a scrivere una query che sia piacevole e facile da capire - disponila in modo intuitivo, usa un rientro piacevole in modo che tutto sia chiaro come Se continui a insegnare agli altri, prova a instillare queste caratteristiche nelle loro domande, specialmente se le risolverai.

È del tutto possibile continuare a collegare sempre più tabelle in questo modo.

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

Anche se ho dimenticato di includere una tabella in cui potremmo voler unire più di una colonna joinnell'istruzione, ecco un esempio. Se la modelstabella avesse modelli specifici del marchio e quindi avesse anche una colonna chiamata brandche si collegava alla brandstabella sul IDcampo, si potrebbe fare come segue:

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

Come puoi vedere, la query sopra non solo collega le tabelle unite alla carstabella principale , ma specifica anche i join tra le tabelle già unite. Se ciò non è stato fatto, il risultato si chiama join cartesiano - che è dba che parla male. Un join cartesiano è quello in cui vengono restituite le righe perché le informazioni non indicano al database come limitare i risultati, quindi la query restituisce tutte le righe che soddisfano i criteri.

Quindi, per dare un esempio di join cartesiano, eseguiamo la seguente query:

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)

Buon Dio, è brutto. Tuttavia, per quanto riguarda il database, è esattamente ciò che è stato richiesto. Nella query, abbiamo chiesto il IDda carse il modelda models. Tuttavia, poiché non abbiamo specificato come unire le tabelle, il database ha abbinato ogni riga della prima tabella con ogni riga della seconda tabella.

Ok, quindi il capo è tornato e vuole di nuovo ulteriori informazioni. Voglio la stessa lista, ma includo anche 4 ruote motrici .

Questo, tuttavia, ci offre un'ottima scusa per esaminare due modi diversi per raggiungere questo obiettivo. Potremmo aggiungere un'altra condizione alla clausola where in questo modo:

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

Mentre quanto sopra funzionerà perfettamente, guardiamolo in modo diverso, questa è un'ottima scusa per mostrare come funzionerà una unionquery.

Sappiamo che quanto segue restituirà tutte le auto sportive:

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

E quanto segue restituirebbe tutti i 4 ruote motrici:

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

Quindi aggiungendo una union allclausola tra loro, i risultati della seconda query verranno aggiunti ai risultati della prima query.

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)

Come puoi vedere, i risultati della prima query vengono restituiti per primi, seguiti dai risultati della seconda query.

In questo esempio, ovviamente sarebbe stato molto più semplice utilizzare semplicemente la prima query, ma le unionquery possono essere ottime per casi specifici. Sono un ottimo modo per restituire risultati specifici da tabelle da tabelle che non sono facilmente unibili tra loro - o del resto tabelle completamente non correlate. Ci sono alcune regole da seguire comunque.

  • I tipi di colonna della prima query devono corrispondere ai tipi di colonna di ogni altra query di seguito.
  • I nomi delle colonne della prima query verranno utilizzati per identificare l'intero set di risultati.
  • Il numero di colonne in ciascuna query deve essere lo stesso.

Ora, ti starai chiedendo quale sia la differenza tra l'utilizzo di unione union all. Una unionquery rimuoverà i duplicati, mentre union allnon lo farà. Questo significa che c'è un piccolo successo prestazionale quando si usa unionover union allma i risultati potrebbero valerne la pena - non speculerò su quel genere di cose in questo.

In questa nota, potrebbe valere la pena notare alcune note aggiuntive qui.

  • Se volessimo ordinare i risultati, possiamo usare un order byma non puoi più usare l'alias. Nella query sopra, l'aggiunta e la visualizzazione order by a.IDcomporterebbe un errore - per quanto riguarda i risultati, viene chiamata la colonna IDanziché a.ID- anche se lo stesso alias è stato utilizzato in entrambe le query.
  • Possiamo avere solo order byun'istruzione e deve essere come l'ultima istruzione.

Per i prossimi esempi, sto aggiungendo alcune righe extra alle nostre tabelle.

Ho aggiunto Holdenalla tabella dei marchi. Ho anche aggiunto una riga carsche ha il colorvalore di 12- che non ha alcun riferimento nella tabella dei colori.

Ok, il capo è tornato di nuovo, abbaiando richieste - * Voglio un conteggio di ogni marchio che trasportiamo e il numero di auto in esso! `- Tipico, arriviamo a una sezione interessante della nostra discussione e il capo vuole più lavoro .

Bene, quindi la prima cosa che dobbiamo fare è ottenere un elenco completo di possibili marchi.

select
    a.brand
from
    brands a

+--------+
| brand  |
+--------+
| Ford   |
| Toyota |
| Nissan |
| Smart  |
| BMW    |
| Holden |
+--------+
6 rows in set (0.00 sec)

Ora, quando ci uniamo a questo al tavolo delle nostre auto, otteniamo il seguente risultato:

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)

Il che è ovviamente un problema: non stiamo vedendo alcuna menzione dell'adorabile Holdenmarchio che ho aggiunto.

Questo perché un join cerca le righe corrispondenti in entrambe le tabelle. Poiché non vi sono dati nelle auto di tipo Holdennon vengono restituiti. Qui è dove possiamo usare un outerjoin. Ciò restituirà tutti i risultati da una tabella indipendentemente dal fatto che siano stati trovati nell'altra tabella o meno:

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)

Ora che ce l'abbiamo, possiamo aggiungere un'adorabile funzione aggregata per ottenere un conteggio e toglierci il capo dalle spalle per 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)

E con ciò, via il boss si masturba.

Ora, per spiegarlo in modo più dettagliato, i join esterni possono essere del tipo lefto right. Sinistra o Destra definisce quale tabella è completamente inclusa. A left outer joinincluderà tutte le righe dalla tabella a sinistra, mentre (hai indovinato) a right outer joinporta tutti i risultati dalla tabella a destra nei risultati.

Alcuni database consentiranno un risultato full outer joinche restituirà risultati (corrispondenti o meno) da entrambe le tabelle, ma questo non è supportato in tutti i database.

Ora, probabilmente immagino a questo punto nel tempo, ti stai chiedendo se puoi unire i tipi di join in una query - e la risposta è sì, puoi assolutamente farlo.

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)

Quindi, perché non sono i risultati previsti? È perché, sebbene abbiamo selezionato l'unione esterna dalle automobili alle marche, non è stata specificata nell'unione ai colori, quindi quella particolare unione restituirà solo risultati che corrispondono in entrambe le tabelle.

Ecco la query che funzionerebbe per ottenere i risultati previsti:

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)

Come possiamo vedere, abbiamo due join esterni nella query e i risultati stanno arrivando come previsto.

Ora, che ne dici di quegli altri tipi di join che chiedi? Che dire di intersezioni?

Bene, non tutti i database supportano intersectionma praticamente tutti i database ti permetteranno di creare un'intersezione attraverso un join (o almeno un'istruzione dove ben strutturata).

Un'intersezione è un tipo di unione in qualche modo simile a unionquella descritta sopra, ma la differenza è che restituisce solo file di dati identici (e intendo identici) tra le varie singole query unite dall'unione. Verranno restituite solo righe identiche sotto ogni aspetto.

Un semplice esempio sarebbe come tale:

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

Mentre una unionquery normale restituirebbe tutte le righe della tabella (la prima query restituirà qualsiasi cosa ID>2e la seconda qualsiasi cosa abbia ID<4) che comporterebbe un set completo, una query intersecata restituirebbe solo la corrispondenza delle righe id=3poiché soddisfa entrambi i criteri.

Ora, se il tuo database non supporta una intersectquery, è possibile integrare facilmente quanto sopra con la seguente query:

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)

Se si desidera eseguire un'intersezione su due diverse tabelle utilizzando un database che non supporta intrinsecamente una query di intersezione, sarà necessario creare un join su ogni colonna delle tabelle.


2
@Fluffeh Nice risposte. Ho un suggerimento: se vuoi renderlo un killer tutorial SQL, ti manca solo aggiungere diagrammi di Venn; Ho capito subito i join destro e sinistro grazie a loro. Richiesta personale: hai qualche tutorial su errori comuni / messa a punto delle prestazioni?
StrayChild01,

25
Oh mio. La mia rotella di scorrimento è rotta. Ottima domanda e risposta. Vorrei poter votare questo 10 volte.
Amal Murali,

3
Hehe, grazie per il feedback positivo. Continua a scorrere, questa è stata solo la prima risposta. SO ha detto che la mia risposta era troppo lunga per inserirla in una "risposta", quindi ho dovuto usarne alcune :)
Fluffeh,

7
Onestamente, penso che questa risposta debba essere abbreviata in qualche modo.
einpoklum,

Articolo eccellente. Database si unisce a 101.
maq

101

Ok, ho trovato questo post molto interessante e vorrei condividere alcune delle mie conoscenze sulla creazione di una query. Grazie per questo Fluffeh . Altri che potrebbero leggere questo e ritenere che mi sbagli sono liberi al 101% di modificare e criticare la mia risposta. ( Onestamente, mi sento molto grato per aver corretto i miei errori. )

Pubblicherò alcune delle domande più frequenti nel MySQLtag.


Trucco n. 1 ( righe che corrispondono a più condizioni )

Dato questo schema

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');

DOMANDA

Trova tutti i film che appartengono ad almeno entrambi Comedy e Romancecategorie.

Soluzione

Questa domanda può essere molto complicata a volte. Può sembrare che una domanda come questa sia la risposta: -

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

Demo SQLFiddle

che è decisamente molto sbagliato perché non produce alcun risultato . La spiegazione di ciò è che esiste un solo valore valido CategoryNameper ogni riga . Ad esempio, la prima condizione restituisce true , la seconda condizione è sempre false. Quindi, usando l' ANDoperatore, entrambe le condizioni dovrebbero essere vere; altrimenti, sarà falso. Un'altra query è così,

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

Demo SQLFiddle

e il risultato è ancora errato perché corrisponde a un record che ha almeno una corrispondenza su categoryName. La vera soluzione sarebbe contando il numero di istanze di registrazione per film . Il numero di istanza deve corrispondere al numero totale dei valori forniti nella condizione.

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 risposta)


Trucco n. 2 ( record massimo per ogni voce )

Schema dato,

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');

DOMANDA

Trova la versione più recente su ciascun software. Visualizzare le seguenti colonne: SoftwareName, Descriptions, LatestVersion( dalla colonna VersionNo ),DateReleased

Soluzione

Alcuni sviluppatori SQL usano erroneamente la MAX()funzione aggregata. Tendono a creare in questo modo,

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

Demo SQLFiddle

(la maggior parte di RDBMS genera un errore di sintassi a causa della mancata specificazione di alcune colonne non aggregate nella group byclausola ) il risultato produce il corretto LatestVersionsu ciascun software ma ovviamente DateReleasedsono errati. MySQLnon supporta Window Functionse Common Table Expressiontuttavia come alcuni RDBMS già fanno. La soluzione a questo problema consiste nel creare un oggetto subqueryche ottenga il massimo individuale versionNosu ciascun software e che successivamente venga unito alle altre tabelle.

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 risposta)


Così è stato. Ne posterò un altro non appena ricordo altre FAQ sul MySQLtag. Grazie per aver letto questo piccolo articolo. Spero che possiate avere almeno una piccola conoscenza da questo.

AGGIORNAMENTO 1


Trucco n. 3 ( Trovare l'ultimo record tra due ID )

Schema dato

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');

DOMANDA

Trova l'ultima conversazione tra due utenti.

Soluzione

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
)

Demo SQLFiddle


Eccezionale! Un avvertimento John, la tua prima soluzione funziona solo perché c'è un vincolo unico sui due campi. Avresti potuto usare una soluzione più generale per risolvere un problema comune. Secondo me l'unica soluzione è fare selezioni individuali per comedye romance. Havingnon va bene allora ..
nawfal

@nawfal non proprio, se non è stato aggiunto un vincolo univoco, è necessario aggiungere distinctla clausola avendo Demo SQLFiddle : D
John Woo

63

Parte 2 - Sottoquery

Bene, ora il capo è scoppiato di nuovo: voglio un elenco di tutte le nostre auto con il marchio e un totale di quante di quel marchio abbiamo!

Questa è una grande opportunità per usare il prossimo trucco nella nostra borsa di goodies SQL: la subquery. Se non si ha familiarità con il termine, una sottoquery è una query che viene eseguita all'interno di un'altra query. Esistono molti modi diversi per usarli.

Per la nostra richiesta, prima mettiamo insieme una semplice query che elencherà ogni auto e il marchio:

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

Ora, se volessimo semplicemente ottenere un conteggio delle auto ordinate per marchio, potremmo ovviamente scrivere questo:

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 |
+--------+-----------+

Quindi, dovremmo essere in grado di aggiungere semplicemente la funzione di conteggio alla nostra query originale, giusto?

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)

Purtroppo no, non possiamo farlo. Il motivo è che quando aggiungiamo l'ID auto (colonna a.ID) dobbiamo aggiungerlo al gruppo per - quindi ora, quando la funzione di conteggio funziona, c'è un solo ID corrispondente per ID.

È qui che possiamo comunque usare una sottoquery - in effetti possiamo fare due tipi completamente diversi di sottoquery che restituiranno gli stessi risultati di cui abbiamo bisogno per questo. Il primo è semplicemente inserire la subquery nella selectclausola. Ciò significa che ogni volta che otteniamo una riga di dati, la sottoquery scapperà, otterrà una colonna di dati e quindi la inserirà nella nostra riga di dati.

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)

E Bam !, questo ci farebbe. Se hai notato, tuttavia, questa query secondaria dovrà essere eseguita per ogni singola riga di dati che restituiamo. Anche in questo piccolo esempio, abbiamo solo cinque diversi marchi di auto, ma la sottoquery ha funzionato undici volte poiché abbiamo undici file di dati che stiamo restituendo. Quindi, in questo caso, non sembra il modo più efficiente di scrivere codice.

Per un approccio diverso, eseguiamo una sottoquery e facciamo finta che sia una tabella:

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)

Ok, quindi abbiamo gli stessi risultati (ordinati in modo leggermente diverso - sembra che il database volesse restituire i risultati ordinati dalla prima colonna che abbiamo scelto questa volta) - ma gli stessi numeri giusti.

Quindi, qual è la differenza tra i due - e quando dovremmo usare ogni tipo di subquery? Innanzitutto, assicuriamoci di capire come funziona quella seconda query. Abbiamo selezionato due tabelle nella fromclausola della nostra query, quindi abbiamo scritto una query e detto al database che in realtà era una tabella - di cui il database è perfettamente soddisfatto. L' utilizzo di questo metodo può comportare alcuni vantaggi (nonché alcune limitazioni). Il primo è che questa subquery è stata eseguita una volta . Se il nostro database contenesse un grande volume di dati, potrebbe esserci un notevole miglioramento rispetto al primo metodo. Tuttavia, poiché lo stiamo utilizzando come tabella, dobbiamo includere ulteriori righe di dati, in modo che possano effettivamente essere ricollegati alle nostre righe di dati. Dobbiamo anche essere sicuri che ce ne siano abbastanzarighe di dati se utilizzeremo un semplice join come nella query sopra. Se ricordi, il join arretrerà solo le righe con dati corrispondenti su entrambi i lati del join. Se non stiamo attenti, ciò potrebbe comportare la restituzione di dati validi dalla tabella delle nostre auto se non vi fosse una riga corrispondente in questa sottoquery.

Ora, guardando indietro alla prima sottoquery, ci sono anche alcune limitazioni. poiché stiamo recuperando i dati in una singola riga, possiamo SOLO ritirare una riga di dati. Sottoquery utilizzati nella selectclausola di una query utilizzano molto spesso solo una funzione di aggregazione come sum, count, maxo un'altra funzione di aggregazione simile. Non devono , ma è così che vengono scritti.

Quindi, prima di andare avanti, diamo un'occhiata a dove altro possiamo usare una subquery. Possiamo usarlo nella whereclausola - ora, questo esempio è un po 'inventato come nel nostro database, ci sono modi migliori per ottenere i seguenti dati, ma visto che è solo per un esempio, diamo un'occhiata:

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

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

Questo ci restituisce un elenco di ID marchio e nomi di marchi (la seconda colonna viene aggiunta solo per mostrarci i marchi) che contengono la lettera onel nome.

Ora, potremmo usare i risultati di questa query in una clausola 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)

Come puoi vedere, anche se la sottoquery restituiva i tre ID del marchio, il nostro tavolo delle auto aveva solo voci per due di essi.

In questo caso, per ulteriori dettagli, la sottoquery funziona come se avessimo scritto il seguente codice:

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)

Ancora una volta, puoi vedere come una subquery rispetto agli input manuali ha cambiato l'ordine delle righe quando ritorna dal database.

Mentre discutiamo delle sottoquery, vediamo cos'altro possiamo fare con una sottoquery:

  • È possibile posizionare una sottoquery all'interno di un'altra sottoquery e così via e così via. C'è un limite che dipende dal tuo database, ma a parte le funzioni ricorsive di alcuni programmatori pazzi e maniacali, la maggior parte delle persone non raggiungerà mai quel limite.
  • Puoi inserire un numero di sottoquery in una singola query, alcune nella selectclausola, alcune nella fromclausola e un paio in più nella whereclausola - ricorda solo che ognuna che hai inserito sta rendendo la tua query più complessa e probabilmente impiegherà più tempo a eseguire.

Se hai bisogno di scrivere un codice efficiente, può essere utile scrivere la query in diversi modi e vedere (o programmandolo o utilizzando un piano di spiegazione) qual è la query ottimale per ottenere i risultati. Il primo modo in cui funziona potrebbe non essere sempre il modo migliore per farlo.


Molto importante per i nuovi sviluppatori: le sottoquery probabilmente verranno eseguite una volta per ogni risultato a meno che non sia possibile utilizzare la sottoquery come join (mostrato sopra).
Xeoncross,

59

Parte 3 - Trucchi e codice efficiente

MySQL in () efficienza

Ho pensato di aggiungere alcuni bit extra, per suggerimenti e trucchi che sono emersi.

Una domanda che vedo sorgere abbastanza, è Come posso ottenere righe non corrispondenti da due tabelle e vedo la risposta più comunemente accettata come qualcosa di simile al seguente (basato sulla tabella delle nostre auto e marchi - che ha Holden elencato come un marchio, ma non appare nella tabella delle automobili):

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

E , funzionerà.

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

Tuttavia è non è efficace in alcuni database. Ecco un link a una domanda Stack Overflow che ti chiede, ed ecco un eccellente articolo di approfondimento se vuoi entrare nel nocciolo della questione.

La risposta breve è che se l'ottimizzatore non lo gestisce in modo efficiente, potrebbe essere molto meglio utilizzare una query come la seguente per ottenere righe non corrispondenti:

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)

Aggiorna tabella con la stessa tabella nella sottoquery

Ahhh, un altro vecchio ma buono - il vecchio Non puoi specificare la tabella target "marchi" per l'aggiornamento nella clausola FROM .

MySQL non ti consentirà di eseguire una update...query con una sottoselezione nella stessa tabella. Ora, potresti pensare, perché non limitarti a schiaffeggiarlo nella clausola Where, giusto? Ma cosa succede se si desidera aggiornare solo la riga con la max()data tra un gruppo di altre righe? Non puoi farlo esattamente in una clausola where.

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

Quindi, non possiamo farlo eh? Bene, non esattamente. C'è una soluzione subdola che un numero sorprendentemente elevato di utenti non conosce, sebbene includa alcuni hacker a cui dovrai prestare attenzione.

È possibile inserire la sottoquery all'interno di un'altra sottoquery, che crea uno spazio sufficiente tra le due query in modo che funzioni. Tuttavia, si noti che potrebbe essere più sicuro incollare la query all'interno di una transazione: ciò impedirà qualsiasi altra modifica apportata alle tabelle mentre la query è in esecuzione.

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

3
Voglio solo notare che la costruzione WHERE NOT EXISTS () è praticamente identica dal punto di vista dell'efficienza, ma a mio avviso molto più facile da leggere / comprendere. Inoltre, la mia conoscenza è limitata a MSSQL e non posso giurare se lo stesso è vero su altre piattaforme.
deroby,

L'altro giorno ho provato questo tipo di confronto, dove NOT IN () aveva un elenco di diverse centinaia di ID e non vi era alcuna differenza tra esso e la versione di join della query. Forse fa la differenza quando ti alzi in migliaia o miliardi.
Buttle Butkus,

18

È possibile utilizzare il concetto di più query nella parola chiave FROM. Lascia che ti mostri un esempio:

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

Puoi usare tutte le tabelle che vuoi. Usa join esterni e unione dove mai è necessario, anche all'interno delle sottoquery della tabella.

Questo è un metodo molto semplice per coinvolgere tante tabelle e campi.


8

Spero che questo lo faccia trovare i tavoli mentre stai leggendo 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    |                |
+-------+-------------+------+-----+---------+----------------+
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.