Newsgroup: it.comp.software.database
Titolo: problema con una query

Ciao a tutti.
Sono di fronte ad una query che proprio non riesco a scrivere.
Supponiamo di avere, in una semplice gestione di fatture, due tabelle, una
che elenca le fatture e l'altra che elenca i prodotti fatturati. Ovviamente
con una relazione "uno a molti":
tabella fatture:
+------------+--------+------------+
| id_fattura | numero | data       |
+------------+--------+------------+
|          1 |     12 | 2004-12-07 |
|          2 |     45 | 2004-12-07 |
+------------+--------+------------+
tabella prodotti:
+------------+-----------------+--------+
| id_fattura | codice_prodotto | prezzo |
+------------+-----------------+--------+
|          1 | A               |     10 |
|          1 | B               |     11 |
|          2 | A               |     10 |
|          2 | B               |     11 |
|          2 | C               |      9 |
+------------+-----------------+--------+
Ora la situazione in esempio rappresenta due fatture (numeri 12 e 45), con 2
e 3 prodotti, rispettivamente A,B e A,B,C.
La query che vorrei scrivere dovrebbe selezionarmi tutte le fatture che
contengono il prodotto A e B e nient'altro. Ovvero dovrebbe dare come
risultato la sola fattura num. 12 (id_fattura = 1) e non la 45, visto che
questa contiene anche il prodotto C.
Ovviamente
SELECT * FROM fatture INNER JOIN prodotti ON id_fattura WHERE
codice_prodotto = 'A' AND codice_prodotto = 'B';
ritorna entrambe le fatture.
Qualche idea?
Ciao e grazie,
Luca

 contengono il prodotto A e B e nient'altro.
Quindi, numero righe=2. Se una fattura ha piu' di 2 righe non puo'
"entrare".
select * from fatture,prodotti where
	fatture.id_fattura=prodotti.id_fattura
	and prodotti.codice_prodotto in (A,B)
	and count(prodotti.id_fattura) = 2;
O qualche cosa di simile?
Davide
-- 
My Win98 installation has been doing that for months.. German,
English, and Dutch, all intermingled. What's so frightening about 
that? -- Jasper Janssen
You mean seeing "Reboot Macht Frei" on your screen? -- Greg Andrews
-- from alt.sysadmin.recovery

 -- 
Ho ragionato un po' sul tuo suggerimento, piuttosto furbo direi.
Ma questo mi ha fatto capire che effettivamente i termini del problema sono
leggermente diversi da quelli che ho descritto:
l'obbiettivo č selezionare le fatture i cui prodotti (tutti) facciano parte
di un gruppo di elementi dato.
Esempio chiarificatore:
data la tabella di fatture:
+------------+--------+------------+
| id_fattura | numero | data       |
+------------+--------+------------+
|          1 |     12 | 2004-12-07 |
|          2 |     45 | 2004-12-07 |
|          3 |     98 | 2004-12-07 |
+------------+--------+------------+
e dati i prodotti:
+------------+-----------------+--------+
| id_fattura | codice_prodotto | prezzo |
+------------+-----------------+--------+
|          1 | A               |     10 |
|          1 | B               |     11 |
|          2 | C               |     10 |
|          2 | B               |     11 |
|          3 | C               |      9 |
+------------+-----------------+--------+
e dato l'elenco di prodotti:
B
C
la query dovrebbe selezionare le fatture con id = 2 e 3 poichč i prodotti
dell'elenco dato appaiono in queste fatture. La fattura  con id = 1 non
dovrebbe essere selezionata poichč appare anche il prodotto A che non č
presente nell'elenco.
Luca

 ha scritto nel messaggio
news:cp4doe$4ab$1...@atlantis.cu.mi.it...

umm complicatina.....
io la farei cosě
-----------------
SELECT   F.Id_fattura,Numero,Data
FROM     fatture f
  INNER JOIN
         prodotti P1 ON F.id_fattura = P1.id_fattura
                    AND P1.Codice_Prodotto='A'
  INNER JOIN
         prodotti P2 ON F.id_fattura = P2.id_fattura
                    AND P2.Codice_Prodotto='B'
WHERE    1=ALL(Select CASE WHEN  Codice_Prodotto='A'
                              OR Codice_Prodotto='B'
                           THEN 1 ELSE 0 END
                FROM   Prodotti Where Id_Fattura=F.Id_Fattura)
------------------
Ciao Giorgio


in questo caso.... visto che entrambi gli elementi non devono
necessariamente esistere contemporaneamente
-------------
SELECT   DISTINCT F.Id_fattura,Numero,Data
FROM     fatture f
  INNER JOIN
         prodotti P1 ON F.id_fattura = P1.id_fattura
WHERE    (codice_prodotto = 'B' OR
         codice_prodotto = 'C')
  AND    1=ALL(Select CASE WHEN  Codice_Prodotto='B'
                              OR Codice_Prodotto='C'
                           THEN 1 ELSE 0 END
                FROM   Prodotti Where Id_Fattura=f.Id_Fattura)
------------
ps (la query è per Ms Sql Server se usi altri motori direi che l'unica
funzione che potrebbe cambiare è la CASE)
Ciao Giorgio

 [CUT]
umm.... puoi fare anche a meno della Inner Join , serve solo a dare una
prima scrematura, vedi tu in base al tuo motore SQL quale è la più
performante.
-----------------------
SELECT   F.Id_fattura,Numero,Data
FROM     fatture f
WHERE    1=ALL(Select CASE WHEN  Codice_Prodotto='B'
                              OR Codice_Prodotto='C'
                           THEN 1 ELSE 0 END
                FROM   Prodotti Where Id_Fattura=f.Id_Fattura)
------------------------
Ciao Giorgio

 > [CUT]
eliminando la funzione CASE per renderla compatibile con il linguaggio Sql
standard
--------------------
SELECT   F.Id_fattura,Numero,Data
FROM     fatture f
WHERE    NOT EXISTS(Select *
                    FROM   Prodotti
                    Where  Id_Fattura=f.Id_Fattura
                    AND  NOT (Codice_Prodotto='B' OR
                              Codice_Prodotto='C'))
----------------------
quindi applicando De Morgan
------------------------
SELECT   F.Id_fattura,Numero,Data
FROM     fatture f
WHERE    NOT EXISTS(Select *
                    FROM   Prodotti
                    Where  Id_Fattura=f.Id_Fattura
                      AND  Codice_Prodotto<>'B'
                      AND  Codice_Prodotto<>'C')
-------------------------
o se vogliamo usare una query di dati non corrispondenti
---------------------------
SELECT   F.Id_fattura,Numero,Data
FROM     fatture f
 LEFT JOIN
         (SELECT Id_Fattura
          FROM   Prodotti
          Where  Codice_Prodotto<>'B'
            AND   Codice_Prodotto<>'C') P
         ON F.Id_Fattura= P.Id_Fattura
WHERE P.Id_Fattura Is Null
----------------------------
quindi ... (ma non so se con motori diversi da Ms SqlServer funziona)
-----------------------------
SELECT   F.Id_fattura,Numero,Data
FROM     fatture f
 LEFT JOIN Prodotti P
        ON F.Id_Fattura= P.Id_Fattura
      AND  P.Codice_Prodotto<>'B'
      AND  P.Codice_Prodotto<>'C'
WHERE P.Id_Fattura Is Null
-----------------------------
naturalmente possono esserci altre soluzioni, al momento non me ne vengono
in mente altre.
Ciao Giorgio


urka! che valanga di suggerimenti!
Ti ringrazio davvero, mi metto subito al lavoro per cercare quella che mi dà
prestazioni migliori.
Ciao
Luca

 Perche' "id" e "numero" ? numero+anno non e' gia' una chiave univoca?
E' fortemente consigliato l'uso di chiavi surrogate (come id) e non chiavi 
primarie magari composte e con significato di business come anno + numero.