Newsgroup: it.comp.software.database
Titolo: una query particolare

Ciao a tutti.
Supponiamo una tabella con tre campi così popolata:
Nome    Cognome     DataAccesso
------------------------------------
Mario    Rossi            15/09/04
Luca      Verdi            17/09/04
Mario    Rossi            12/06/04
Gigi       Banchi           10/04/04
Mario    Rossi             05/03/03
avrei la necessità di estrarre i record che hanno DataAccesso più recente ma
uno solo per Nome e Cognome, ovvero sapere per ogni utente la data di
accesso più recente.
Sostanzialmente dovrei ottenere:
Nome    Cognome     DataAccesso
------------------------------------
Mario    Rossi            15/09/04
Luca      Verdi            17/09/04
Gigi       Banchi           10/04/04
Qualche idea?
Grazie,
Luca

 ha scritto nel messaggio
news:ciu37n$i9n$1...@atlantis.cu.mi.it...

Una cosa tipo:
SELECT Nome, Cognome, MAX(DataAccesso) FROM Tabella GROUP BY Nome, Cognome;
a me funziona...
+-------+---------+------------+
| nome  | cognome | MAX(data)  |
+-------+---------+------------+
| Gigi  | Banchi  | 2004-04-10 |
| Luca  | Verdi   | 2004-09-17 |
| Mario | Rossi   | 2004-09-15 |
+-------+---------+------------+

 
SELECT nome, cognome, MAX(dataaccesso) FROM miatabella GROUP BY nome, 
cognome;

 Luca
cosi a prima vista sembra una tabella strutturata male
Mi attenderei due tabelle
Persone
ID
Nome
Cognome
e
Accessi
ID
DataAccesso
in questo caso basterebbe fare
select ID,max(dataAccesso)
from accessi
group by ID
Nel tuo caso occorre concatenare i primi due campi(un trucco per bypassare
l'errore di design delle tabelle)
select nome || cognome,max(dataAccesso)
from tabella
group by nome || cognome
(|| è l'operatore di concatenazione)

l'errore di design delle tabelle)
Trucco che mi sembra non necessario (altri hanno dato esempi funzionanti
che non ne fanno uso), e non sufficiente (può essere incredibilmente raro,
ma non si può teoricamente escludere che nome1 || cognome1 == nome2 ||
cognome2, per qualche nome1, nome2, cognome1, cognome2 diversi).
Ciao.


La tabella era solo un esempio creato ad hoc per fare la domanda.
La reale tabella č diversa: non prevede nomi e cognomi ne' date di accesso,
ma č un log di modifiche a determinati campi di una seconda tabella, ed č
cosě strutturata:
ID    NomeCampo    DataModifica     Valore
dove ID si riferisce al record della seconda tabella, NomeCampo al campo
modificato, e Valore al valore di detto campo prima della modifica.
Con la query suggerita da Mauro e Martino posso quindi capire qual'era il
valore, per ciascun campo di ciscun record, prima che questo valore fosse
modificato o ad una certa data.
Luca
ps: grazie a tutti per i suggerimenti

 difendibile.
IMHO una cosa del genere è malstrutturata a prescindere...
Chi dice che Mario Rossi è lo stesso Mario Rossi di un altro record?

Chi dice che Mario Rossi è lo stesso Mario Rossi di un altro record?
Chi dice che, nell'universo, non ci sia che uno e un solo Mario Rossi
(nell'universo a cui si applica il database, ovviamente)? Se non conosci
l'ambito di applicazione come fai a dire qualcosa di certo?
Inoltre, possiamo definire la nostra tabella
 Persone
   ID
   Nome
   Cognome
e dirci contenti perché l'"ambiguità è risolta"; o cominciare proprio ora a
lamentarci perché comunque l'utente umano continua a non capirci nulla: ID
per lui non ha alcun significato, e fra i due "Mario Rossi" continua a non
sapere quale scegliere. Sicché, abbiamo risolto o complicato senza
risolvere?
Se impedisci che ci possano essere due utenti con nome e cognome uguale,
hai risolto l'ambiguità in un modo che potrebbe essere più conveniente, in
un universo in cui la collisione fra i nomi è infrequente.
Se la collisione è frequente, potrebbe continuare ad essere conveniente, se
gli utenti sono disposti ad aggiustare un po' il proprio nome ("Franco I",
"Franco IV"), pur di potersi riconoscere in chiaro; ovvero, si può pensare
di usare qualcosa di significativo per l'utente (un nick, o qualche altro
elemento identificativo) piuttosto che un generico ID, generato dal
database (non è così che funziona, spesso, in una compagnia di amici, con
soprannomi e diminutivi, quando per avventura il nome è uguale?).
Ciao.

 Luca
Forse non ho capito bene, ma supponendo che possano essere fatte
piu' modifice ad ogni campo di ogni record, applicando solo la
funzione di aggregazione MAX sulla data, e raggruppando per nome,
ottieni solo la data piu' recente di aggiornamento del campo,
per recuperare il valore devi fare un'altra operazione.
Esempio:
CREATE TABLE TabellaLog (
             IDRecord        int         NOT NULL
,            NomeCampo       varchar(50) NOT NULL
,            DataModifica    datetime    NOT NULL
,            Valore          varchar(50) NOT NULL
,            CONSTRAINT      pkTabellaLog
             PRIMARY KEY    (
                                IDRecord
             ,                  NomeCampo
             ,                  DataModifica
                            )
)
INSERT TabellaLog
VALUES (1, 'NomeContatto', '2004-09-25 15:30', 'Mairio')
INSERT TabellaLog
VALUES (2, 'NomeContatto', '2004-09-25 16:40', 'Polo')
INSERT TabellaLog
VALUES (2, 'NomeContatto', '2004-09-27 14:50', 'Palo')
INSERT TabellaLog
VALUES (3, 'CognomeContatto', '2004-09-27 11:00', 'Bianci')
-- la tabella contiene i seguenti record:
--
-- +----------+-----------------+-------------------------+--------+
-- | IDRecord | NomeCampo       | DataModifica            | Valore |
-- +==========+=================+=========================+--------+
-- | 1        | NomeContatto    | 2004-09-25 15:30:00.000 | Mairio |
-- | 2        | NomeContatto    | 2004-09-25 16:40:00.000 | Polo   |
-- | 2        | NomeContatto    | 2004-09-27 14:50:00.000 | Palo   |
-- | 3        | CognomeContatto | 2004-09-27 11:00:00.000 | Bianci |
-- +----------+-----------------+-------------------------+--------+
--
-- seguendo l'esempio fatto precedentemente:
SELECT
        T1.IDRecord
,       T1.NomeCampo
,       MAX(T1.DataModifica) AS DataModifica
FROM    TabellaLog AS T1
GROUP BY
        T1.IDRecord
,       T1.NomeCampo
-- la query ritorna i seguenti record:
--
-- +----------+-----------------+-------------------------+
-- | IDRecord | NomeCampo       | DataModifica            |
-- +==========+=================+-------------------------+
-- | 1        | NomeContatto    | 2004-09-25 15:30:00.000 |
-- | 2        | NomeContatto    | 2004-09-27 14:50:00.000 |
-- | 3        | CognomeContatto | 2004-09-27 11:00:00.000 |
-- +----------+-----------------+-------------------------+
--
-- puoi estrarre direttamente anche i valori con una delle
-- seguenti richieste:
SELECT
        T1.IDRecord
,       T1.NomeCampo
,       T1.DataModifica
,       T1.Valore
FROM    TabellaLog AS T1
WHERE   T1.DataModifica = (
            SELECT  MAX(T2.DataModifica)
            FROM    TabellaLog AS T2
            WHERE   T2.IDRecord = T1.IDRecord
              AND   T2.NomeCampo = T1.NomeCampo
         )
SELECT
        T1.IDRecord
,       T1.NomeCampo
,       T1.DataModifica
,       T1.Valore
FROM    TabellaLog AS T1
JOIN    (
            SELECT
                    T2.IDRecord
            ,       T2.NomeCampo
            ,       MAX(T2.DataModifica) AS DataModifica
            FROM    TabellaLog AS T2
            GROUP BY
                    T2.IDRecord
            ,       T2.NomeCampo
        ) AS T3
  ON    T3.IDRecord = T1.IDRecord
 AND    T3.NomeCampo = T1.NomeCampo
 AND    T3.DataModifica = T1.DataModifica
-- in entrambi i casi il risultato e' il seguente:
-- 
-- +----------+-----------------+-------------------------+--------+
-- | IDRecord | NomeCampo       | DataModifica            | Valore |
-- +==========+=================+-------------------------+--------+
-- | 1        | NomeContatto    | 2004-09-25 15:30:00.000 | Mairio |
-- | 2        | NomeContatto    | 2004-09-27 14:50:00.000 | Palo   |
-- | 3        | CognomeContatto | 2004-09-27 11:00:00.000 | Bianci |
-- +----------+-----------------+-------------------------+--------+
--
-- attenzione a non fare l'errore di applicare una condizione sulla
-- data nel posto sbagliato (magari mettendo la query in una vista)
--
-- se ad esempio voglio sapere tutte le ultime modifiche, a tutti i
-- record ed a tutti i campi, avvenute precedentemente alla data
-- 2004-09-26 00:00:00.000 mi aspetto come risultato:
--
-- +----------+-----------------+-------------------------+--------+
-- | IDRecord | NomeCampo       | DataModifica            | Valore |
-- +==========+=================+-------------------------+--------+
-- | 1        | NomeContatto    | 2004-09-25 15:30:00.000 | Mairio |
-- | 2        | NomeContatto    | 2004-09-25 16:40:00.000 | Polo   |
-- +----------+-----------------+-------------------------+--------+
--
-- se applico la condizione, ad esempio con la prima versione della
-- query, come segue:
SELECT
        T1.IDRecord
,       T1.NomeCampo
,       T1.DataModifica
,       T1.Valore
FROM    TabellaLog AS T1
WHERE   T1.DataModifica = (
            SELECT  MAX(T2.DataModifica)
            FROM    TabellaLog AS T2
            WHERE   T2.IDRecord = T1.IDRecord
              AND   T2.NomeCampo = T1.NomeCampo
         )
  AND    T1.DataModifica <= '2004-09-26 00:00:00'
-- ottengo come risultato:
--
-- +----------+-----------------+-------------------------+--------+
-- | IDRecord | NomeCampo       | DataModifica            | Valore |
-- +==========+=================+-------------------------+--------+
-- | 1        | NomeContatto    | 2004-09-25 15:30:00.000 | Mairio |
-- +----------+-----------------+-------------------------+--------+
--
-- che e' corretto, ma non necessariamente intuitivo (specialmente
-- se faccio una vista ed applico la condizione alla vista)
--
-- la query corretta e' la seguente:
SELECT
        T1.IDRecord
,       T1.NomeCampo
,       T1.DataModifica
,       T1.Valore
FROM    TabellaLog AS T1
WHERE   T1.DataModifica = (
            SELECT  MAX(T2.DataModifica)
            FROM    TabellaLog AS T2
            WHERE   T2.IDRecord = T1.IDRecord
              AND   T2.NomeCampo = T1.NomeCampo
              AND   T2.DataModifica <= '2004-09-26 00:00:00'
         )
Ciao,
-- 
Gianluca Hotz - SQL Server MVP
http://italy.mvps.org
 - 
http://www.solidqualitylearning.com
http://www.ugiss.org
  - 
http://www.ugidotnet.org
http://www.ghotz.com
  - 
http://blogs.ugidotnet.org/ghotz