Newsgroup: it.comp.appl.access
Titolo: stringa SQL complessa - Lunghissimo e per chi può dedicarci del tempo

Buongiorno a tutti.
Innanzitutto vi ringrazio per l'aiuto ricevuto in merito al problema
sull'anno bisestile: grazie ai vostri consigli sono riuscito a proseguire
nel lavoro.
Mi rivolgo ancora a voi, nella speranza che mi aiutiate di nuovo: sono due
giorni che sto impazzendo su una stringa SQL!
Ecco il problema:
Devo creare un prospetto Presenze e Quietenze circa la gestione degli
Obiettori di Coscienza.
Pesco i dati da due tabelle relazionate (1:N), la prima "ODC" si riferisce
agli obiettori, la seconda "Licenze" si riferisce alle licenze usufruite.
La query SQL allo stato attuale è la seguente:
rsProspetto.Open "SELECT ODC.ID_ODC, ODC.Cognome & ' ' & ODC.Nome AS
Nominativo, ODC.Tipologia," _
    & " SUM((DateDiff('d', Licenze.Data_Inizio, Licenze.Data_Fine) + 1) -
Licenze.GGViaggio) AS [gg licenza]," _
    & " SUM(Licenze.GGViaggio) AS [gg viaggio]" _
    & " FROM ODC LEFT JOIN Licenze ON ODC.ID_ODC = Licenze.ID_ODC" _
    & " WHERE Licenze.Data_Inizio BETWEEN #" & Format("1/" &
MeseDelProspetto & "/" & AnnoDelProspetto, "mm/dd/yyyy") & "#" _
    & " AND #" & Format(GiorniDelMese & "/" & MeseDelProspetto & "/" &
AnnoDelProspetto, "mm/dd/yyyy") & "#" _
    & " OR Licenze.Data_Inizio IS NULL" _
    & " GROUP BY ODC.ID_ODC, ODC.Cognome & ' ' & ODC.Nome, ODC.Tipologia" _
    & " UNION" _
    & " SELECT DISTINCT ODC.ID_ODC, ODC.Cognome & ' ' & ODC.Nome AS
Nominativo, ODC.Tipologia, 0 AS [gg licenza], 0 AS [gg viaggio]" _
    & " FROM ODC INNER JOIN Licenze ON ODC.ID_ODC = Licenze.ID_ODC" _
    & " WHERE Licenze.Data_Inizio NOT BETWEEN #" & Format("1/" &
MeseDelProspetto & "/" & AnnoDelProspetto, "mm/dd/yyyy") & "#" _
    & " AND #" & Format(GiorniDelMese & "/" & MeseDelProspetto & "/" &
AnnoDelProspetto, "mm/dd/yyyy") & "#;"
Semplifichiamo e arriviamoci per gradi:
Devo selezionare la somma dei giorni di licenza e dei viaggi per ciascun
obiettore, quindi:
"SELECT ODC.ID_ODC, ODC.Cognome & ' ' & ODC.Nome AS Nominativo,
ODC.Tipologia," _
    & " SUM((DateDiff('d', Licenze.Data_Inizio, Licenze.Data_Fine) + 1) -
Licenze.GGViaggio) AS [gg licenza]," _
    & " SUM(Licenze.GGViaggio) AS [gg viaggio]" _
    & " FROM ODC LEFT JOIN Licenze ON ODC.ID_ODC = Licenze.ID_ODC" _
    & " GROUP BY ODC.ID_ODC, ODC.Cognome & ' ' & ODC.Nome, ODC.Tipologia"
Qui la LEFT JOIN funziona bene, infatti vengono visualizzati anche gli
obiettori che non hanno preso licenze.
Il problema sorge quando inserisco una restrizione sul periodo, ossia, per
es. "Pesca la somma delle licenze di marzo":
Inserisco una WHERE:
"SELECT ODC.ID_ODC, ODC.Cognome & ' ' & ODC.Nome AS Nominativo,
ODC.Tipologia," _
    & " SUM((DateDiff('d', Licenze.Data_Inizio, Licenze.Data_Fine) + 1) -
Licenze.GGViaggio) AS [gg licenza]," _
    & " SUM(Licenze.GGViaggio) AS [gg viaggio]" _
    & " FROM ODC LEFT JOIN Licenze ON ODC.ID_ODC = Licenze.ID_ODC" _
    & " WHERE Licenze.Data_Inizio BETWEEN #03/01/2000# AND #03/29/2000#" _
    & " GROUP BY ODC.ID_ODC, ODC.Cognome & ' ' & ODC.Nome, ODC.Tipologia"
Tutto funziona, tranne la LEFT: non vengono visualizzati gli obiettori che
non hanno preso licenze in assoluto e quelli che non hanno preso licenze in
quel periodo. Per quelli in assoluto (sono quelli che non hanno occorrenze
nella tabella licenze) si risolve aggiungendo:
    & " OR Licenze.Data_Inizio IS NULL" _
nella WHERE. (La LEFT giustamente non produce niente in quanto applico una
restrizione prima del raggruppamento, ma non si può fare altrimenti).
A questo punto ho provato ad aggiungere la selezione mancante con una UNION
(infilando un NOT al posto giusto), e arriviamo al risultato finale:
"SELECT ODC.ID_ODC, ODC.Cognome & ' ' & ODC.Nome AS Nominativo,
ODC.Tipologia," _
    & " SUM((DateDiff('d', Licenze.Data_Inizio, Licenze.Data_Fine) + 1) -
Licenze.GGViaggio) AS [gg licenza]," _
    & " SUM(Licenze.GGViaggio) AS [gg viaggio]" _
    & " FROM ODC LEFT JOIN Licenze ON ODC.ID_ODC = Licenze.ID_ODC" _
    & " WHERE Licenze.Data_Inizio BETWEEN #03/01/2000# AND #03/29/2000#" _
    & " OR Licenze.Data_Inizio IS NULL" _
    & " GROUP BY ODC.ID_ODC, ODC.Cognome & ' ' & ODC.Nome, ODC.Tipologia" _
    & " UNION" _
    & " SELECT DISTINCT ODC.ID_ODC, ODC.Cognome & ' ' & ODC.Nome AS
Nominativo, ODC.Tipologia, 0 AS [gg licenza], 0 AS [gg viaggio]" _
    & " FROM ODC INNER JOIN Licenze ON ODC.ID_ODC = Licenze.ID_ODC" _
    & " WHERE Licenze.Data_Inizio NOT BETWEEN #03/01/2000# AND
#03/29/2000#;"
Finalmente ottengo tutti i record, compreso gli obiettori che non hanno
preso licenze in quel periodo.
Il problema sono i duplicati degli obiettori che invece hanno preso licenze!
Cioè, la UNION delle due SELECT non mi raggruppa i dati, col risultato che
nel recordset finale l'obiettore Pippo compare 2 volte, come risultato della
prima select (somma Licenze prese nel periodo e raggruppate), e come
risultato della seconda (tutte le licenze non prese nel periodo).
Come posso risolvere quest'ultimo problema? Dove sbaglio?
Scusate la lunghezza ma ho cercato di essere più chiaro possibile.
Grazie
Max

Come posso risolvere quest'ultimo problema? Dove sbaglio?
Se fosse una query normale ti direi di settare la proprietà record univoci a
sì, ma non so se con una query di unione funzionerebbe, prova comunque.
Altrimenti accoda il tutto in una tabella, che avrai prima svuotato, in cui
avrai settato a campo chiave i campi che rendono univoco un record. I record
duplicati saranno scartati. Poi fornisci tutti i record della tabella.
Antonio