web-dev-qa-db-fra.com

Requête MySQL, MAX () + GROUP BY

Question Daft SQL. J'ai une table comme ça ('pid' est l'incrémentation primaire du col primaire)

CREATE TABLE theTable (
    `pid` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    `timestamp` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    `cost` INT UNSIGNED NOT NULL,
    `rid` INT NOT NULL,
) Engine=InnoDB;

Données de table réelles:

INSERT INTO theTable (`pid`, `timestamp`, `cost`, `rid`)
VALUES
  (1, '2011-04-14 01:05:07', 1122, 1),
  (2, '2011-04-14 00:05:07', 2233, 1),
  (3, '2011-04-14 01:05:41', 4455, 2),
  (4, '2011-04-14 01:01:11', 5566, 2),
  (5, '2011-04-14 01:06:06', 345, 1),
  (6, '2011-04-13 22:06:06', 543, 2),
  (7, '2011-04-14 01:14:14', 5435, 3),
  (8, '2011-04-14 01:10:13', 6767, 3)
;

Je veux obtenir le PID de la dernière ligne pour chaque débarras (1 résultat par RID unique). Pour les exemples de données, j'aimerais:

pid | MAX(timestamp)      | rid
-----------------------------------
5   | 2011-04-14 01:06:06 | 1
3   | 2011-04-14 01:05:41 | 2
7   | 2011-04-14 01:14:14 | 3

J'ai essayé d'exécuter la requête suivante:

SELECT MAX(timestamp),rid,pid FROM theTable GROUP BY rid

et je reçois:

max(timestamp)     ; rid; pid
----------------------------
2011-04-14 01:06:06; 1  ; 1
2011-04-14 01:05:41; 2  ; 3
2011-04-14 01:14:14; 3  ; 7

Le PID renvoyé est toujours la première apparition de PID pour un RID (row/pid 1 est la première fois que rid 1 est utilisé, row/pid 3 la première fois que le RID 2 est utilisé, row/pid 7 est la première fois que rid 3 est utilisé. ). Bien qu'ils renvoient l'horodatage maximal pour chaque suppression, les pids ne sont pas les pids des horodatages de la table d'origine. Quelle requête me donnerait les résultats que je cherche?

26
codinghands

(Testé dans PostgreSQL 9.quelque chose)

Identifiez le débarras et l'horodatage.

select rid, max(timestamp) as ts
from test
group by rid;

1   2011-04-14 18:46:00
2   2011-04-14 14:59:00

Rejoignez-le.

select test.pid, test.cost, test.timestamp, test.rid
from test
inner join 
    (select rid, max(timestamp) as ts
    from test
    group by rid) maxt
on (test.rid = maxt.rid and test.timestamp = maxt.ts)
select *
from (
    select `pid`, `timestamp`, `cost`, `rid`
    from theTable 
    order by `timestamp` desc
) as mynewtable
group by mynewtable.`rid`
order by mynewtable.`timestamp`

J'espère que j'ai aidé! 

7
anzize
SELECT t.pid, t.cost, to.timestamp, t.rid
FROM test as t
JOIN (
    SELECT rid, max(tempstamp) AS maxtimestamp
    FROM test GROUP BY rid
) AS tmax
    ON t.pid = tmax.pid and t.timestamp = tmax.maxtimestamp
4
dkretz

J'ai créé un index sur débarrasser et horodatage.

SELECT test.pid, test.cost, test.timestamp, test.rid
FROM theTable AS test
LEFT JOIN theTable maxt 
ON maxt.rid = test.rid
AND maxt.timestamp > test.timestamp
WHERE maxt.rid IS NULL 

Afficher les lignes 0 - 2 (3 au total, Requête prise en 0.0104 sec)

Cette méthode sélectionnera toutes les valeurs souhaitées parmi theTable (test), en se laissant se joindre (maxt) sur tous les horodatages supérieurs à celui testé avec le même paramètre. Lorsque l'horodatage est déjà le plus élevé du test, il n'y a pas de correspondance sur maxt - c'est ce que nous recherchons - les valeurs sur maxt deviennent NULL. Nous utilisons maintenant la clause WHERE maxt.rid IS NULL ou toute autre colonne sur maxt.

2
Caio Iglesias

Si vous voulez éviter une jointure, vous pouvez utiliser:

SELECT pid, rid FROM theTable t1 WHERE t1.pid IN ( SELECT MAX(t2.pid) FROM theTable t2 GROUP BY t2.rid);
0
Nicolás Previale

Vous pourriez aussi avoir des sous-requêtes comme ça:

SELECT ( SELECT MIN(t2.pid)
         FROM test t2
         WHERE t2.rid = t.rid
           AND t2.timestamp = maxtimestamp
       ) AS pid 
     , MAX(t.timestamp) AS maxtimestamp
     , t.rid
FROM test t
GROUP BY t.rid

Mais de cette façon, vous aurez besoin d’une sous-requête supplémentaire si vous souhaitez que cost soit inclus dans les colonnes affichées, etc. 

Donc, group by et join est la meilleure solution.

0
ypercubeᵀᴹ