none
Estrazione raggruppata particolare RRS feed

  • Domanda

  • Ciao a tutti,
    ho una Select di join su varie tabelle che mi restituisce qualcosa del tipo:


    Data - Ordinale - Prezzo - Costo

    00:15:00 - 0 - 55 - 24
    00:15:00 - 1 - 57 - 25
    00:30:00 - 0 - 55 - 24
    00:45:00 - 5 - 64 - 34
    00:45:00 - 6 - 65 - 34
    00:45:00 - 7 - 75 - 35

    In questo resultset ci possono essere delle ore duplicate: ci sono 2 record per il blocco delle ore 00:15
    uno solo per le 00:30 e tre per le 00:45.

    Dovrei estrarre solo un record per ogni blocco di ora, che abbia il Max(ordinale), ma poi recuperare anche le altre colonne.

    Se faccio un GroupBy per le ora e uso il Max per l'ordinale, non posso poi recuperare gli altri valori.

    Come posso risolvere questo problema?

    Grazie

    Luigi


    PS
    Questi campi non fanno parte di una tabella fisica, ma solo il result set di una SELECT abbastanza complessa che opera in Join su più tabelle.

    • Modificato Ciupaz venerdì 7 ottobre 2011 14:15
    venerdì 7 ottobre 2011 14:13

Risposte

  • Dovrei estrarre solo un record per ogni blocco di ora, che abbia il Max(ordinale), ma poi recuperare anche le altre colonne.

    ...

    PS
    Questi campi non fanno parte di una tabella fisica, ma solo il result set di una SELECT abbastanza complessa che opera in Join su più tabelle.

    Ciao Luis,

    Che sia una tabella fisica o una query complessa la situazione non cambia, devi sempre passare da una tabella derivata che restituisca la tua chiave di interrogazione (Data e Ordinale più alto) da mettere in JOIN con la tabella/query come nel seguente esempio:

    USE tempdb;
    
    CREATE TABLE dbo.foo(
    Data time NOT NULL,
    Ordinale tinyint NOT NULL,
    Prezzo tinyint NOT NULL,
    Costo tinyint NOT NULL
    )
    
    INSERT dbo.foo
    VALUES ('00:15:00', 0, 55, 24)
         , ('00:15:00', 1, 57, 25)
         , ('00:30:00', 0, 55, 24)
         , ('00:45:00', 5, 64, 34)
         , ('00:45:00', 6, 65, 34)
         , ('00:45:00', 7, 75, 35);
    
    WITH CTE_GetKey(Data, Ordinale) AS
    (
        SELECT Data, MAX(Ordinale)
        FROM dbo.foo
        GROUP BY Data
    )
    SELECT F.*
    FROM dbo.foo AS F
    JOIN CTE_GetKey AS C
    ON F.Data = C.Data
    AND F.Ordinale = C.Ordinale
    ORDER BY F.Data;
    
    /* Output:
    
    Data             Ordinale Prezzo Costo
    ---------------- -------- ------ -----
    00:15:00.0000000 1        57     25
    00:30:00.0000000 0        55     24
    00:45:00.0000000 7        75     35
    
    (3 row(s) affected)
    
    */
    
    DROP TABLE dbo.foo;
    

    Ciao!


    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://social.technet.microsoft.com/Forums/it-IT/sqlserverit
    • Contrassegnato come risposta Ciupaz venerdì 7 ottobre 2011 14:34
    venerdì 7 ottobre 2011 14:23
    Moderatore
  • Sì lo so cosa dicono i BOL, la mia era solo un'osservazione "filosofica", nel senso che mi sembrava una carenza intrinseca del SQL il fatto di non poter recuperare anche le altre colonne (non appartenenti al Group By), dato che comunque il motore relazionale ha già recuperato i record che soddisfano la condizione. Tutto qua.

    Perdonami Luis,

    Ma non sono d'accordo. :-)

    Tu hai scritto: "Dovrei estrarre solo un record per ogni blocco di ora, che abbia il Max(ordinale), ma poi recuperare anche le altre colonne".

    Come fai raggruppare per ogni ora e Max(ordinale) e nel contempo ottenere anche le altre colonne? E' logicamente impossibile dato che se vuoi recuperare anche le altre colonne dovrai specificarle nella SELECT list e nella clausola GROUP BY, non ottenendo quindi il risultato che chiedi.

    Ciao!


    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://social.technet.microsoft.com/Forums/it-IT/sqlserverit
    • Contrassegnato come risposta Ciupaz lunedì 10 ottobre 2011 07:43
    lunedì 10 ottobre 2011 07:34
    Moderatore

Tutte le risposte

  • Dovrei estrarre solo un record per ogni blocco di ora, che abbia il Max(ordinale), ma poi recuperare anche le altre colonne.

    ...

    PS
    Questi campi non fanno parte di una tabella fisica, ma solo il result set di una SELECT abbastanza complessa che opera in Join su più tabelle.

    Ciao Luis,

    Che sia una tabella fisica o una query complessa la situazione non cambia, devi sempre passare da una tabella derivata che restituisca la tua chiave di interrogazione (Data e Ordinale più alto) da mettere in JOIN con la tabella/query come nel seguente esempio:

    USE tempdb;
    
    CREATE TABLE dbo.foo(
    Data time NOT NULL,
    Ordinale tinyint NOT NULL,
    Prezzo tinyint NOT NULL,
    Costo tinyint NOT NULL
    )
    
    INSERT dbo.foo
    VALUES ('00:15:00', 0, 55, 24)
         , ('00:15:00', 1, 57, 25)
         , ('00:30:00', 0, 55, 24)
         , ('00:45:00', 5, 64, 34)
         , ('00:45:00', 6, 65, 34)
         , ('00:45:00', 7, 75, 35);
    
    WITH CTE_GetKey(Data, Ordinale) AS
    (
        SELECT Data, MAX(Ordinale)
        FROM dbo.foo
        GROUP BY Data
    )
    SELECT F.*
    FROM dbo.foo AS F
    JOIN CTE_GetKey AS C
    ON F.Data = C.Data
    AND F.Ordinale = C.Ordinale
    ORDER BY F.Data;
    
    /* Output:
    
    Data             Ordinale Prezzo Costo
    ---------------- -------- ------ -----
    00:15:00.0000000 1        57     25
    00:30:00.0000000 0        55     24
    00:45:00.0000000 7        75     35
    
    (3 row(s) affected)
    
    */
    
    DROP TABLE dbo.foo;
    

    Ciao!


    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://social.technet.microsoft.com/Forums/it-IT/sqlserverit
    • Contrassegnato come risposta Ciupaz venerdì 7 ottobre 2011 14:34
    venerdì 7 ottobre 2011 14:23
    Moderatore
  • Avevo qualche vago sospetto che avrei dovuto per forza passare da una tabella derivata.

    Grazie Lorenzo, anche per la velocità di risposta.

    Luigi

    venerdì 7 ottobre 2011 14:34
  • Ma non è un limite del SQL il fatto di non potersi "portare appresso" anche gli altri campi quando effettuo una funzione di raggruppamento?

    Alla fin fine deve comunque individuare le righe che mi deve restituire, e cosa ci vorrebbe a darmi anche gli altri campi di queste stesse righe?

    L

    venerdì 7 ottobre 2011 14:38
  • Ma non è un limite del SQL il fatto di non potersi "portare appresso" anche gli altri campi quando effettuo una funzione di raggruppamento?

    Alla fin fine deve comunque individuare le righe che mi deve restituire, e cosa ci vorrebbe a darmi anche gli altri campi di queste stesse righe?


    No, non è una limitazione di SQL Server. Il discorso è molto semplice, basta leggere la documentazione della clausola GROUP BY, in particolare: Each table or view column in any nonaggregate expression in the <select> list must be included in the GROUP BY list

    In altre parole, tutte le colonne specificate nel comando di SELECT sulle quali non sono applicate funzioni di aggregazione DEVONO essere specificate nella clausola GROUP BY.

    Ora, come pensi di ottenere il risultato richiesto senza ricorrere ad una tabella derivata? :-)


    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://social.technet.microsoft.com/Forums/it-IT/sqlserverit
    sabato 8 ottobre 2011 10:04
    Moderatore
  • Sì lo so cosa dicono i BOL, la mia era solo un'osservazione "filosofica", nel senso che mi sembrava una carenza intrinseca del SQL il fatto di non poter recuperare anche le altre colonne (non appartenenti al Group By), dato che comunque il motore relazionale ha già recuperato i record che soddisfano la condizione. Tutto qua.
    E questa mancanza, come giustamente hai segnalato tu, fa sì che bisogna ricorrere a tabelle derivate per raggiungere lo scopo di questo post.


    Luigi

    lunedì 10 ottobre 2011 07:20
  • Sì lo so cosa dicono i BOL, la mia era solo un'osservazione "filosofica", nel senso che mi sembrava una carenza intrinseca del SQL il fatto di non poter recuperare anche le altre colonne (non appartenenti al Group By), dato che comunque il motore relazionale ha già recuperato i record che soddisfano la condizione. Tutto qua.

    Perdonami Luis,

    Ma non sono d'accordo. :-)

    Tu hai scritto: "Dovrei estrarre solo un record per ogni blocco di ora, che abbia il Max(ordinale), ma poi recuperare anche le altre colonne".

    Come fai raggruppare per ogni ora e Max(ordinale) e nel contempo ottenere anche le altre colonne? E' logicamente impossibile dato che se vuoi recuperare anche le altre colonne dovrai specificarle nella SELECT list e nella clausola GROUP BY, non ottenendo quindi il risultato che chiedi.

    Ciao!


    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://social.technet.microsoft.com/Forums/it-IT/sqlserverit
    • Contrassegnato come risposta Ciupaz lunedì 10 ottobre 2011 07:43
    lunedì 10 ottobre 2011 07:34
    Moderatore