PDA

View Full Version : [SQL] Problema con raggruppamento


simoneart
25-03-2008, 18:17
Salve a tutti, qualcuno saprebbe aiutarmi con questa query?

SELECT TOP 5 ArtWC_Eventi.ID_Evento, ArtWC_Eventi.Nome, ArtWC_Eventi.Descrizione, ArtWC_Eventi.DataInizio, ArtWC_MediaCatalogue.FileName, ArtWC_MediaCatalogue.Titolo
FROM ArtWC_Eventi
LEFT JOIN ArtWC_MediaLinks ON ArtWC_Eventi.ID_Evento = ArtWC_MediaLinks.ID_Item
LEFT JOIN ArtWC_MediaCatalogue ON ArtWC_MediaLinks.ID_Media = ArtWC_MediaCatalogue.ID_Media
WHERE ArtWC_Eventi.DataInizio > GetDate() AND (ArtWC_MediaLinks.ID_ItemCategory = 2 OR ISNULL(ArtWC_MediaLinks.ID_ItemCategory,0) = 0)
GROUP BY ArtWC_Eventi.ID_Evento
ORDER BY ArtWC_Eventi.DataInizio DESC

La query gira su SQL Server 2005, funziona se tolgo la riga group by ma mi restituisce troppi risultati (mi ripete chiaramente un evento tante volte quanti sono i record collegati nella tabella MediaLinks). Aggiungendo l'istruzione group by mi restituisce l'errore:

Column 'ArtWC_Eventi.Nome' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause


Sapreste aiutarmi?

cionci
25-03-2008, 20:06
Nella select puoi selezionare solo gli attributi che metti nel group by o puoi attuare una funzione di aggregazione sugli attributi non presenti nel group by.

gugoXX
25-03-2008, 20:46
Nella select puoi selezionare solo gli attributi che metti nel group by o puoi attuare una funzione di aggregazione sugli attributi non presenti nel group by.

Confermo.

Ma cosa avresti voluto fare?

simoneart
26-03-2008, 09:53
La teoria l'ho capita ma non la pratica... quale funzione di aggregazione posso usare per prendere solo il primo valore per ogni condizione soddisfatta? In Access mi pare fosse First() ma in t-sql non conosco l'equivalente.

La query dovrebbe funzionare così:
ho 3 tabelle, eventi, immagini e una tabella che lega immagini ed eventi.
Eventi, MediaCatalogue e MediaLinks.

Chiaramente ad ogni record nella tabella eventi (Evento) possono essere legate più immagini. Senza una funzione di raggruppamento, la query mi restituisce come risultato un elenco di eventi ma mi ripete ogni evento n volte quante sono le immagini collegate ad esso.

Invece avrei bisogno di elencare una sola volta ogni evento e portarmi appresso eventualmente una sola foto collegata.

gugoXX
26-03-2008, 09:55
OK.
e quando invece per un dato evento le foto sono 2 (o piu'), cosa vorresti che venisse fuori?
Di quali colonne comunque hai bisogno, nel risultato finale?

cionci
26-03-2008, 10:01
Invece avrei bisogno di elencare una sola volta ogni evento e portarmi appresso eventualmente una sola foto collegata.
Scusa, ma se hai fatto un Join perché ti dovrebbe portare tutte le fotografie ? E in con quale criterio dovresti scegliere la fotografia ?

simoneart
26-03-2008, 10:05
Scusa, ma se hai fatto un Join perché ti dovrebbe portare tutte le fotografie ? E in con quale criterio dovresti scegliere la fotografia ?

Che domanda è? mi porta tutte le fotografie che rispettano la condizione del join. Eventi e foto sono legati attraverso i rispettivi id nella tabella medialinks.

In questa query non ho bisogno di elencare le foto, quando ne avrò bisogno farò una join tra medialinks e mediacatalogue dove l'id del legame che cerco è uguale all'evento (o altro elemento) che mi interessa

simoneart
26-03-2008, 10:07
OK.
e quando invece per un dato evento le foto sono 2 (o piu'), cosa vorresti che venisse fuori?
Di quali colonne comunque hai bisogno, nel risultato finale?

Se le foto sono più di una, vorrei che comunque mi venisse listata solo la prima, le info di cui ho bisogno sono quelle elencate nella prima parte della select:

SELECT TOP 5 ArtWC_Eventi.ID_Evento, ArtWC_Eventi.Nome, ArtWC_Eventi.Descrizione, ArtWC_Eventi.DataInizio, ArtWC_MediaCatalogue.FileName, ArtWC_MediaCatalogue.Titolo

Quindi i dati base dell'evento più il percorso all'immagine e il titolo della stessa.

cionci
26-03-2008, 10:16
Allora il Join non ha senso: seleziona solo ArtWC_Eventi.ID_Evento, ArtWC_Eventi.Nome, ArtWC_Eventi.Descrizione, ArtWC_Eventi.DataInizio dalla tabella eventi...no ?
Poi la foto te la selezioni a parte successivamente con l'ID Evento nel Where.

gugoXX
26-03-2008, 10:22
Allora il Join non ha senso: seleziona solo ArtWC_Eventi.ID_Evento, ArtWC_Eventi.Nome, ArtWC_Eventi.Descrizione, ArtWC_Eventi.DataInizio dalla tabella eventi...no ?
Poi la foto te la selezioni a parte successivamente con l'ID Evento nel Where.

Sono d'accordo.
Resta comunque l'ultima parte, che sarebbe:
Per ciascun evento, selezionare la foto piu' recente (o la piu' vecchia, o la piu' grossa. Boh? Solo "la prima" non ha senso detta cosi'. La prima se li avessi ordinati per???), con tutti i suoi dati a disposizione.

Poi tirare fuori tutto insieme oppure in 2 query separate sta poi a te.

Comunque per quest'ultima parte dovresti:
Una prima subquery per tirare fuori, per ciascun evento, quel e' il codice (PK) della foto interessata. (ovvero una subquery con GroupBy, e una funzione di gruppo tipo max)
Tale subquery andra' messa in join con la tabella dalle foto, per tirare fuori i dati interessati, per ciascuna foto.

Poi, se vorrai andare in join anche con la tabella degli eventi, per tirare fuori anche i dati interessanti per ciascun evento, quello stara' poi a te.

simoneart
26-03-2008, 10:34
Non so se ho capito la vostra soluzione :(

A me serve (servirebbe) di ottenere quei dati con un'unica interrogazione. Vorrei ottenere come risultato un recordset del tipo:

ID_Evento | Titolo | Descrizione | Data | PercorsoFoto

In maniera tale da poter poi visualizzare i risultati con un semplice repeater.

Non conosco l'id dell'evento che sto estraendo e l'id dell'evento non è legato all'immagine se non attraverso la tabella dei links per cui non saprei come mettere un uguaglianza del tipo id_evento = id_item nel WHERE.

Per quanto riguarda le immagini, al momento non ha importanza l'ordine, mi basta tirarne fuori una qualsiasi.

gugoXX
26-03-2008, 10:46
Una prima subquery per tirare fuori, per ciascun evento, quel e' il codice (PK) della foto interessata. (ovvero una subquery con GroupBy, e una funzione di gruppo tipo max)


SELECT id_evento,max(id_media) maxmedia
FROM mediaLinks
GROUP BY id_evento


Tale subquery andra' messa in join con la tabella dalle foto, per tirare fuori i dati interessati, per ciascuna foto.


SELECT pippo.id_evento,MediaCatalogue.* FROM
(SELECT id_evento,max(id_media) maxmedia
FROM mediaLinks
GROUP BY id_evento) AS pippo
JOIN MediaCatalogue ON (pippo.maxmedia=MediaCatalogue.id_media)


E se vuoi prendi a questo punto anche i dati degli eventi, che sono da prendere in outerjoin, poiche' e' possibile che un evento non abbia foto.


SELECT * FROM Eventi
LEFT OUTER JOIN
(tutta la sbrodolata di prima) AS menata
ON (menata.id_evento = Eventi.id_evento)


E tutto questo perche' si vuole restare con il SQL Standard.
Con le funzioni analitiche di SQL-Server 2005+ la cosa e' piu' semplice (ma forse meno leggibile se non ci si e' abituati)

PS: Sbrodolata e' un termine tecnico, in uso anche in ambiente sistemistico, dove pero' si tende ad usare solo per i log-file.
Qui e' usata impropriamente, in quanto una Query inizia ad essere una sbrodolata quando ci vogliono almeno un paio di pagine per leggerla. A quel punto chi non usa le viste non ha capito molto cosa vuol dire manutenere il codice.

simoneart
26-03-2008, 15:09
Grazie mille per la disponibilità e l'aiuto che mi avete dato ;)