2009-12-23 13 views
15

Sto cercando un modo per gestire il seguente scenario. Ho una tabella di database che ho bisogno di restituire solo un record per ogni "id di gruppo" che è contenuto all'interno della tabella, inoltre il record che è selezionato all'interno di ciascun gruppo dovrebbe essere la persona più anziana nella famiglia.Query SQL per restituire solo 1 record per ID di gruppo

ID Group ID Name    Age 
1 134  John Bowers  37 
2 134  Kerri Bowers  33 
3 135  John Bowers  44 
4 135  Shannon Bowers  42 

Così nei dati di esempio forniti sopra avrei bisogno di ID 1 e 3 restituito, in quanto sono il popolo più antico all'interno di ogni gruppo id.

Questo è interrogato in un database SQL Server 2005.

+0

Se si desidera il nome, è ancora possibile scegliere> 1 riga se si dispone di> 1 persona con l'età più vecchia. Dovresti anche stabilire dei criteri su quale nome scegliere in quel caso. –

+0

Buon punto Chris. Stavo cercando di semplificare la domanda un po ', ma questo lascia dei buchi come questi :-) In realtà ho un altro campo per il genere, quindi sto cercando di selezionare il maschio più anziano all'interno di una famiglia. se c'è un maschio, allora la donna più anziana. Nel caso in cui ci siano due maschi nella stessa famiglia con la stessa età, allora devo selezionare solo 1 dei record. Questo potrebbe essere basato su qualcosa di semplice come la persona con il numero ID più basso per il tie breaker. –

+1

C'è una buona discussione di questo tipo di problema nella sezione 21.4, "Funzioni estreme", dell'eccellente libro di Joe Celko "SQL for Smarties". Se hai intenzione di imbatterti in qualcosa di più complicato di semplici SELECT e INSERT, consiglio vivamente questo libro. – shoover

risposta

21
SELECT t.* 
FROM (
     SELECT DISTINCT groupid 
     FROM mytable 
     ) mo 
CROSS APPLY 
     (
     SELECT TOP 1 * 
     FROM mytable mi 
     WHERE mi.groupid = mo.groupid 
     ORDER BY 
       age DESC 
     ) t 

o questo:

SELECT * 
FROM (
     SELECT *, ROW_NUMBER() OVER (PARTITION BY groupid ORDER BY age DESC) rn 
     FROM mytable 
     ) 
WHERE rn = 1 

Ciò restituirà al massimo un record per ogni gruppo, anche in caso di parità.

veda questo articolo nel mio blog per il confronto delle prestazioni di entrambi i metodi:

+0

+1: Sì, ho dimenticato il mio disclaimer sui legami. Fuochi di combattimento troppo occupati. –

+0

Grazie Quassnoi. Sono stato in grado di aggiungere la colonna di genere in aggiunta alla colonna età nella tua clausola ORDER By e ottenere i risultati che stavo cercando! (La colonna di genere è stata discussa solo in un commento dopo la mia domanda iniziale) La tua soluzione è perfetta e adattabile! –

+0

Domanda successiva. Questi saranno gestiti contro 175 milioni di record. L'una o l'altra query è più efficiente? –

0
SELECT GroupID, Name, Age 
FROM table 
INNER JOIN 
(
SELECT GroupID, MAX(Age) AS OLDEST 
FROM table 
) AS OLDESTPEOPLE 
ON 
table.GroupID = OLDESTPEOPLE.GroupID 
AND 
table.Age = OLDESTPEOPLE.OLDEST 
3

Usa:

SELECT DISTINCT 
     t.groupid, 
     t.name 
    FROM TABLE t 
    JOIN (SELECT t.groupid, 
       MAX(t.age) 'max_age' 
      FROM TABLE t 
     GROUP BY t.groupid) x ON x.groupid = t.groupid 
          AND x.max_age = t.age 

Che importa se non c'è 2+ persone con la stessa età per un gruppo? Sarebbe meglio memorizzare la data di nascita anziché l'età: puoi sempre calcolare la data di nascita per la presentazione.

+0

Attenzione ai legami! – Quassnoi

0

Prova questo (supponendo Gruppo è sinonimo di domestica)

Select * From Table t 
Where Age = (Select Max(Age) 
      From Table 
      Where GroupId = t.GroupId) 

Se ci sono due o più "antiche" la gente in alcuni domestici (sono tutti della stessa età e non c'è nessun altro più vecchio), quindi questo restituirà tutti, non solo uno a caso.

Se questo è un problema, allora avete bisogno di aggiungere un altro sottoquery per restituire un valore chiave arbitrario per una persona in quel set.

Select * From Table t 
Where Id = 
    (Select Max(Id) Fom Table 
    Where GroupId = t.GroupId 
     And Age = 
     (Select(Max(Age) From Table 
      Where GroupId = t.GroupId)) 
Problemi correlati