Newsgroup: it.comp.software.database
Titolo: Query SQL che con MySql non funziona...

Perchè questa interrogazione con mysql non funziona? Qual'e' la sintassi
giusta?
SELECT i.nome, i.cognome, s.provincia, s.nomescuola
FROM insegnanti i, scuole s, lezioni
WHERE i.IDinsegnante = lezioni.IDinsegnante AND
              s.IDscuola = lezioni.IDscuola AND
              s.provincia = ANY (SELECT Provincia FROM province
                                           WHERE Regione = 'Lazio')
ORDER BY s.nomescuola
premetto che le due interrogazioni 'SELECT' prese una alla volta
funzionano...

 giusta?
Perche' MySQL non supporta le SubQuery (SELECT ... SELECT).
SELECT i.nome, i.cognome, s.provincia, s.nomescuola
FROM insegnanti i, scuole s, lezioni l, province p
WHERE i.IDinsegnante = l.IDinsegnante AND
      s.IDscuola = l.IDscuola AND
      s.provincia = p.IDprovincia AND
      p.regione = 'Lazio'
ORDER BY s.nomescuola
NOTA: usare una subquery per fare un filtro con un campo chiave fisso
('Lazio') e' uno spreco mostruoso di memoria e tempo di processore, il
database non e' in grado di ottimizzare la query e dovra' fare un
tablescan quando potrebbe bastare un indexscan.
Davide

giusta?
Come noto, detto e ripetuto, le subqueries in mysql non ci sono.
Vedi sul manuale possibili metodi di aggirare il problema (o fai due
queries distinte o usi una tabella temporanea).
Comunque non so come è strutturato il tuo db, ma non puoi fare
semplicemente
WHERE . . .
  s.provincia = province.Provincia AND
  province.Regione = Lazio
aggiungendo ovviamente province alla clausola FROM?

 tablescan quando potrebbe bastare un indexscan.
In effetti ho messo 'Lazio' nel codice, ma nelle interrogazioni l'utente puo'
inserire qualsiasi altra regione. O intendevi un'altra cosa? Scusami ma sono
agli inizi con SQL.

 aggiungendo ovviamente province alla clausola FROM?
Si, cosi' funziona, ma e' meno *leggibile*, pazienza! Grazie.
Cmq non sapevo di tutte queste limitazioni in mySql il quale non
sembra giustificare tutta la sua diffusione...Non credete?

 puo' inserire qualsiasi altra regione.
Stessa cosa, il db deve eseguire la query interna (che ritorna un numero
ridicolo di risultati) e poi la query piu' esterna, pero' riesegue la
query esterna ogni volta!
Davide

 Non credete?
Ho appena avuto una "discussione" con il suo inventore, quindi ti
risparmio, vedi le FAQ su 
www.soft-land.org/faq/icsdfaq.html
Davide

 Davide
Lette. Grazie.

 ha scritto nel messaggio news:abuc2q$klnci$4...@ID-18487.news.dfncis.de...

Bah... pensavo che toccasse al motore SQL ottimizzare la ricerca (ora
non sto parlando di mySql). Su 'Basi di dati' di Atzeni, Ceri ... non c'e'
menzione di questa ridondanza di calcolo. Anzi a pag. 128 si consiglia
proprio il codice che ho riportato ad inizio thread! Leggi:
"Questa interrogazione poteva anche essere espressa mediante un join tra
le tabelle xxxxx e yyyyyy, e in effetti gli ottimizzatori sono generalmente in
grado di trattare allo stesso modo le due diverse formulazioni di questa
interrogazione. la scelta tra l'una e l'altra rappresentazione puo' essere
dettata dal grado di leggibilità della soluzione. In casi cosi' semplici non vi
sono differenze, ma per interrogazioni piu' complicate la scomposizione in
interrogazioni distinte puo'  migliorare la leggibilita'."
Enrico

sembra giustificare tutta la sua diffusione...Non credete?
Beh, è una questione che è stata mooolto dibattuta.
In sintesi (ma sappi che rischio che tutti gli altri utenti urlino
bastaaaaaaa!!! e mi blacklistino) l'alternativa per gli sviluppatori
di MySQL era: velocità vs nested queries. O l'una o l'altra.
Quindi database che vai, usanze che trovi, ad ogni esigenza il suo
database, a database donato non si guarda in bocca.
M

fermat wrote:

bastaaaaaaa!!!
(non ti blacklisto, però)
:-)

 proprio il codice che ho riportato ad inizio thread! Leggi:
In effetti e' proprio cosi', *se riesce* un motore di ottimizzazione
converte la subquery in una join.
In SQL Server per esempio se consideri questa query
SELECT O.*
FROM   dbo.Orders AS O
WHERE  O.CustomerID = ANY
      (SELECT C.CustomerId
       FROM dbo.Customers AS C
       WHERE C.Country = 'Italy'
      )
ha questo piano di esecuzione (tagliato per convenienza)
  |--Hash Match
       |--Clustered Index Scan
       |--Clustered Index Scan
e questa che fa' la stessa cosa
SELECT O.*
FROM   dbo.Orders AS O
JOIN   dbo.Customers AS C
ON     C.CustomerID = O.CustomerID
WHERE  C.Country = 'Italy'
come vedi ha il piano e' identico
  |--Hash Match
       |--Clustered Index Scan
       |--Clustered Index Scan
nota che hash match e' semplicemente una tecnica per eseguire la join
(sarebbe Hash Match(Right Semi Join ecc.)
Lo stesso vale anche per cose piu' complesse tipo
SELECT O.OrderID, O.CustomerID,
       (SELECT SUM( OD.Quantity * (1-OD.Discount) * OD.UnitPrice)
        FROM dbo.[Order Details] AS OD
        WHERE OD.OrderID = O.OrderID
       ) AS Totale
FROM   dbo.Orders AS O
ha questo piano di esecuzione
  |--Compute Scalar
       |--Merge Join
            |--Stream Aggregate
            |    |--Clustered Index Scan
            |--Clustered Index Scan
e questa che fa' la stessa cosa
SELECT O.OrderID, O.CustomerID,
       SUM(OD.Quantity * (1-OD.Discount) * OD.UnitPrice)
       AS Totale
FROM   dbo.Orders AS O
JOIN   dbo.[Order Details] AS OD
ON     OD.OrderID = O.OrderID
GROUP BY
       O.OrderID, O.CustomerID
ha sempre il piano praticamente identico
  |--Merge Join
       |--Stream Aggregate
       |    |--Clustered Index Scan
       |--Clustered Index Scan
anche in questo caso merge join e' un algoritmo particolare
Va detto anche che se non ci sono le condizioni per utilizzare
algortimi particolari come in questo caso, l'algoritmo di base
per sviluppare una join e' l'inner loop che comunque prevede
una tabella esterna ed un ciclo di ricerca dei valori sulla
tabella interna. (Per renderlo veloce sono necessari degli indici).
Io preferisco scrivere l'SQL in termini di subquery primo per
la chiarezza, secondo per il fatto che comunque in alcuni casi
potrebe scappare errori del tipo:
SELECT C.*
FROM   dbo.Customers AS C
JOIN   dbo.Orders AS O
ON     C.CustomerID = O.CustomerID
WHERE  O.OrderDate > '19960101'
che duplica le righe di customers per ogni ordine
invece che
SELECT C.*
FROM   dbo.Customers AS C
WHERE  C.CustomerID = ANY
       (SELECT O.CustomerId
        FROM dbo.Orders AS O
        WHERE O.OrderDate > '19960101'
        )
Ciao,
--
Gianluca Hotz
Backoffice MVP (SQL Server) MCP SQL Server and MCP Windows
Vice-President of the Italian User Group for SQL Server
Founding Member of the Italian User Group for .NET
http://www.ghotz.com
http://www.ugiss.org

 converte la subquery in una join.
[omissis]
Allora sarei curioso di sapere se il tanto criticato mysql sia capace di
tale
ottimizzazione...
Ciao.

 tale ottimizzazione...
No purtroppo, se lo fosse, allora "supporterebbe" le subquery.
Davide