Le subquery aggiungono potenza espressiva alle query SQL?


29

SQL ha bisogno di subquery?

Immagina un'implementazione sufficientemente generalizzata del linguaggio di query strutturato per i database delle relazioni. Dal momento che la struttura dell'istruzione canonica SQL SELECTè in realtà abbastanza importante perché ciò abbia un senso, non mi rivolgo direttamente all'algebra relazionale, ma potresti inquadrarla in quei termini facendo appropriate restrizioni sulla forma delle espressioni.

Uno SQL SELECTinterrogazione è generalmente costituito da una sporgenza (la SELECTparte) un numero di JOINoperazioni (la JOINparte), un numero di SELECTION operazioni (in SQL, le WHEREclausole), e quindi impostare-wise operazioni ( UNION, EXCEPT, INTERSECT, ecc), seguita da un'altra SELECTQuery SQL .

Le tabelle che vengono unite possono essere i risultati calcolati delle espressioni; in altre parole, possiamo avere una dichiarazione come:

SELECT t1.name, t2.address
  FROM table1 AS t1 
  JOIN (SELECT id, address 
          FROM table2 AS t3 
         WHERE t3.id = t1.id) AS t2
 WHERE t1.salary > 50,000;

Faremo riferimento all'uso di una tabella calcolata come parte di una query SQL come sottoquery. Nell'esempio sopra, il secondo (rientrato) SELECTè una sottoquery.

Tutte le query SQL possono essere scritte in modo da non utilizzare le query secondarie? L'esempio sopra può:

SELECT t1.name, t2.address
  FROM table1 AS t1 
  JOIN table2 AS t2
    ON t1.id = t2.id
 WHERE t1.salary > 50,000;

Questo esempio è in qualche modo spurio o banale, ma si possono immaginare casi in cui potrebbe essere necessario uno sforzo considerevolmente maggiore per recuperare un'espressione equivalente. In altre parole, è possibile che per ogni query SQL con subquery, esista una query q senza subquery tale che q e q garantiscano che producano gli stessi risultati per le stesse tabelle sottostanti? Limitiamo le query SQL al seguente modulo:qq'qq'

SELECT <attribute>,
      ...,
      <attribute>
 FROM <a table, not a subquery>
 JOIN <a table, not a subquery>
  ...
 JOIN <a table, not a subquery>
WHERE <condition>
  AND <condition>
  ...
  AND <condition>

UNION
 -or-
EXCEPT
 -or-
<similar>

SELECT ...

E così via. Penso che i join esterni destro e sinistro non aggiungano molto, ma se sbaglio, sentitevi liberi di segnalarlo ... in ogni caso, sono anche un gioco leale. Per quanto riguarda le operazioni impostate, suppongo che tutte vadano bene ... unione, differenza, differenza simmetrica, intersezione, ecc ... qualsiasi cosa sia utile. Esistono moduli noti a cui è possibile ridurre tutte le query SQL? Qualcuno di questi elimina le subquery? Oppure ci sono alcuni casi in cui non esiste una query equivalente e senza subquery? I riferimenti sono apprezzati ... o una dimostrazione (per prova) che sono o non sono richiesti sarebbe fantastica. Grazie e scusate se questo è un risultato celebrato (o banale) di cui sono dolorosamente ignorante.


5
Il mio istinto mi dice che puoi sempre unire tutto e selezionare da lì finché non hai bisogno di valori aggregati. La selezione di tutte le voci con un valore maggiore della media della sua colonna sembra richiedere prima il calcolo della media, pertanto è necessaria una sottoquery.
Raffaello

@Raphael Sono abbastanza certo che puoi anche fare valori aggregati, devi solo fare più self-join e raggruppamenti (rendendolo esponenzialmente più grande, ma ancora possibile). Non sono sicuro di come proverei formalmente che puoi fare tutto in quel modo, però.
Kevin

@Kevin Sei sicuro che il numero di operazioni necessarie non dipenda dal numero di righe? Perché non possiamo averlo, vero?
Raffaello

1
L'esempio normale ho per richiedere una sottoquery conta duplicati: select count(*) from (select id from sometable group by id having count(*)>1) d. Perché include group bynon ho inserito questo come una risposta.
Mark Hurd,

A proposito AFAIK in SQL normale la ONclausola è richiesta per JOINs, sebbene un prodotto incrociato sia ottenuto con solo una virgola.
Mark Hurd,

Risposte:


9

C'è un po 'di confusione terminologica; il blocco di query tra parentesi

SELECT t1.name, t2.address
  FROM table1 
  JOIN (SELECT id, address 
          FROM table2 AS t3 
         WHERE t3.id = t1.id) 

si chiama vista interiore . Una sottoquery è un blocco di query all'interno della clausola WHERE o SELECT, ad es

select deptno from dept
where 3 < (select count(1) from emp 
           where dept.deptno=emp.deptno)

In entrambi i casi, la vista interna o la sottoquery possono essere non annidate in un progetto "flat" Limit-Limit-Join. La sottoquery correlata con aggregazione si annulla nelle viste interne con raggruppamento, che quindi si annulla nella query flat.

select deptno from dept d
    where 3 < (select avg(sal) from emp e
               where d.deptno=e.deptno)

select d.deptno from dept d, ( 
    select deptno from emp e
    group by deptno
    having avg(sal) > 3
) where d.deptno=e.deptno

select d.deptno from dept d, emp e
where d.deptno=e.deptno 
group by d.deptno
having avg(sal) > 3

Per quanto riguarda le regole algebriche per l'ottimizzazione delle query, è noto che l'algebra relazionale è assiomatizzata in Lattice relazionale che semplifica le trasformazioni delle query, come dimostrato qua e .


Io sono curioso. Potete aggiungere un esempio di una query che utilizza una media di alcuni campi, ad esempio selezionando tutte le voci con un valore superiore alla media? Non mi è chiaro come sarebbe dopo l'appiattimento.
Raffaello

16

Per tradurre la tua affermazione nell'algebra relazionale, penso che chieda:

σUN(UN)σB(B)σUN(σB(UNB))

σ

La risposta è "Sì" ed è un'ottimizzazione delle query standard. Ad essere onesti, non sono sicuro di come dimostrarlo in modo non mendicante, è solo una proprietà di selezione e di partecipazione. Puoi argomentare induttivamente per aggiungere quanti livelli di query nidificate desideri.

Inoltre, potresti chiedere:

UNBC...(UNB)(CD)

Ancora una volta la risposta è sì, perché join è associativo. Dichiarazioni simili possono essere fatte anche sulla proiezione.

Un tipo notevole di "subquery" che penso non possa essere "appiattito" è with. Un modo per vederlo è notare che se si dispone di withun'istruzione, è possibile disporre di una funzione ricorsiva, che non può essere scritta senza l'uso di subquery.

Quindi, per riassumere: nel caso specifico che hai citato, no, SQL non ha bisogno di subquery e puoi dimostrarlo induttivamente. In generale, tuttavia, ci sono funzionalità che richiedono subquery.


Il comportamento ricorsivo via è withstato introdotto in SQL: 1999 e rende il linguaggio risultante strettamente più espressivo.
András Salamon,

1

"Le subquery aggiungono potenza espressiva alle query SQL?"

Lo hanno fatto, almeno prima dell'introduzione di EXCEPT nel linguaggio SQL.

Prima dell'introduzione di EXCEPT, non c'era modo di esprimere una differenza relazionale o semidifferenza in SQL senza ricorrere a sottoquery.

In questi giorni, tutti gli operatori primitivi "tipici" dell'algebra relazionale possono essere espressi senza subquery:

NATURAL JOIN può essere eseguito tramite NATURAL JOIN oppure JOIN ON
UNION può essere eseguito tramite UNION
MINUS può essere eseguito tramite EXCEPT
PROJECT / RENAME / EXTEND può essere eseguito tramite SELECT
RESTRICT può essere eseguito tramite DOVE i
valori letterali relazionali possono essere eseguiti tramite VALUES
chiusure transitive possono essere eseguito con il metodo ricorsivo WITH

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.