2010-01-12 5 views
2

Je cherche à obtenir l'écart maximal entre deux tables par jour, par identifiant. J'ai les données suivantes dans une base de données MySQLSous-requêtes SQL pour essayer d'obtenir la différence maximale de la même colonne dans deux tables

insert into test.foo values ('2010-01-10', 1, 10); 
insert into test.foo values ('2010-01-10', 1, 5); 
insert into test.foo values ('2010-01-10', 2, 10); 
insert into test.foo values ('2010-01-10', 2, 10); 
insert into test.foo values ('2010-01-10', 3, 15); 
insert into test.foo values ('2010-01-10', 3, 15); 
insert into test.foo values ('2010-01-11', 1, 5); 
insert into test.foo values ('2010-01-11', 1, 5); 
insert into test.foo values ('2010-01-11', 2, 5); 
insert into test.foo values ('2010-01-11', 2, 5); 
insert into test.foo values ('2010-01-11', 3, 5); 
insert into test.foo values ('2010-01-11', 3, 5); 

insert into test.bar values ('2010-01-10', 1, 5); 
insert into test.bar values ('2010-01-10', 1, 5); 
insert into test.bar values ('2010-01-10', 2, 5); 
insert into test.bar values ('2010-01-10', 2, 5); 
insert into test.bar values ('2010-01-10', 3, 5); 
insert into test.bar values ('2010-01-10', 3, 5); 
insert into test.bar values ('2010-01-11', 1, 10); 
insert into test.bar values ('2010-01-11', 1, 10); 
insert into test.bar values ('2010-01-11', 2, 5); 
insert into test.bar values ('2010-01-11', 2, 5); 
insert into test.bar values ('2010-01-11', 3, 5); 
insert into test.bar values ('2010-01-11', 3, 5); 

Voici ma question:

SELECT t1.`date`, t1.id, t1.sums, t2.sums, max(t1.sums - t2.sums) FROM 
    (select `date`, id, sum(val) sums 
    from test.foo 
    group by `date`, id) as t1, 
    (select `date`, id, sum(val) sums 
    from test.bar 
    group by `date`, id) as t2 
WHERE t1.`date` = t2.`date` AND t1.id = t2.id 
group by t1.`date` 

Je reçois ce résultat:

+---------------------+----+------+------+------------------------+ 
| date    | id | sums | sums | max(t1.sums - t2.sums) | 
+---------------------+----+------+------+------------------------+ 
| 2010-01-10 00:00:00 | 1 | 15 | 10 |      20 | 
| 2010-01-11 00:00:00 | 1 | 10 | 20 |      0 | 
+---------------------+----+------+------+------------------------+ 
2 rows in set (0.00 sec) 

Je voudrais être obtenir ce résultat: J'obtiens ce résultat:

+---------------------+----+------+------+------------------------+ 
| date    | id | sums | sums | max(t1.sums - t2.sums) | 
+---------------------+----+------+------+------------------------+ 
| 2010-01-10 00:00:00 | 1 | 15 | 10 |      20 | 
| 2010-01-11 00:00:00 | 2 | 10 | 10 |      0 | <----- 
+---------------------+----+------+------+------------------------+ 

Quelqu'un peut-il m'aider? J'aimerais obtenir la différence maximale, puis la ligne qui va avec. Cette requête me donne la différence correcte, mais pas l'id et les sommes qui vont avec. Un collègue a également suggéré de regrouper par id, mais comme je le pensais, cela a simplement aplati le résultat et chaque identifiant a été listé à la place du seul id pour le jour qui avait la différence maximale.

Merci beaucoup à l'avance

+0

Quelle base de données et quelle version? – RedFilter

+0

Ne devrait pas id = 3 être aussi dans vos résultats? – RedFilter

+0

mysql Ver 14.14 Distrib 5.1.39, pour Win32 (ia32) –

Répondre

1

Celui-ci devrait fonctionner pour vous.

Il trie les sommes dans l'ordre décroissant, en leur attribuant un rang, puis n'obtient que celles dont le rang est égal à 1.

SELECT id, `date`, sums FROM (
    SELECT id, `date`, sums, 
    CASE 
    WHEN @d != `date` THEN @rownum := 1 
    ELSE @rownum := @rownum + 1 
    END AS rank, 
    @d := `date` 
FROM 
(
    SELECT t1.`date`, t1.id, t1.sums t1_sums, t2.sums t2_sums, (t1.sums - t2.sums) sums 
    FROM 
    (select `date`, id, sum(val) sums 
    from foo 
    group by `date`, id) as t1, 
    (select `date`, id, sum(val) sums 
    from bar 
    group by `date`, id) as t2, 
    (SELECT @rownum := 0, @d := NULL) r 
    WHERE t1.`date` = t2.`date` AND t1.id = t2.id 
    GROUP BY t1.`date`, t1.id, t2.`date`, t2.id 
    ORDER BY t1.`date`, (t1.sums - t2.sums) DESC, t1.id 
) x 
) y 
WHERE rank = 1 
+0

Merci beaucoup pour l'aide! –

1
SELECT t1.`date`, t1.id, t1.sums, t2.sums, max(t1.sums - t2.sums) FROM 
    (select `date`, id, sum(val) sums 
    from test.foo 
    group by `date`, id) as t1, 
    (select `date`, id, sum(val) sums 
    from test.bar 
    group by `date`, id) as t2 
WHERE t1.`date` = t2.`date` AND t1.id = t2.id 
group by t1.`date` 

Dans la requête externe que vous regroupez par la date, mais pas l'identifiant, donc vous ne reçoivent pas l'ID que vous attendiez. Si vous voulez trouver l'ID associé à l'écart le plus élevé, vous devez d'abord trouver la plus grande divergence, puis utiliser une autre requête pour déterminer quel ID (ou ID) est associé à cela. Vous devrez décider ce que vous voulez faire avec les doublons. Quelque chose comme ceci (non testé) ...

SELECT t3.`date`, t3.id, t3.diff 
    (SELECT t1.`date`, t1.id, t1.sums, t2.sums, max(t1.sums - t2.sums) as diff FROM 
    (select `date`, id, sum(val) sums 
    from test.foo 
    group by `date`, id) as t1, 
    (select `date`, id, sum(val) sums 
    from test.bar 
    group by `date`, id) as t2 
    WHERE t1.`date` = t2.`date` AND t1.id = t2.id) as t3 
WHERE t3.diff = (correlated subquery to get maximum value of diff for each date) 

Ou utilisez des requêtes séparées.

+0

Celui-ci renvoie l'id '1' pour les deux lignes. –

0

sortie de la requête suivante est:

+----------+- ---+------+------+-------+ 
|date  |id |sumf |sumb |maxdiff| 
+----------+- ---+------+------+-------+ 
|2010-01-10| 1| 30| 20|  10| 
|2010-01-10| 2| 40| 20|  20| 
|2010-01-10| 3| 60| 20|  40| 
|2010-01-11| 1| 20| 40|  20| 
|2010-01-11| 2| 20| 20|  0| 
|2010-01-11| 3| 20| 20|  0| 
+----------+- ---+------+------+-------+ 


select m.date, m.id, s.sumf, s.sumb, m.maxdiff 
from (
    --subquery2: get the maximum different absolute sum between foo and bar for each date/id combination 
    select s.date, s.id, max(abs(s.sumf - s.sumb)) as maxdiff 
    from (
     --subquery1: get the sum of values for each date/id combination 
     select f.date, f.id, sum(f.val) as sumf, sum(b.val) as sumb 
     from foo f 
     inner join bar b on f.date = b.date and f.id = b.id 
     group by f.date, f.id 
    ) s 
    group by s.date, s.id 
) m 
--join back against subquery1 to find out which sums gave us the max difference 
inner join (
    select f.date, f.id, sum(f.val) as sumf, sum(b.val) as sumb 
    from foo f 
    inner join bar b on f.date = b.date and f.id = b.id 
    group by f.date, f.id 
) s on m.date = s.date and m.id = s.id and m.maxdiff = abs(s.sumf - s.sumb) 

Note: ce sera de retour plus d'une ligne dans le cas de double maxdiff s où les sommes sous-jacentes étant soustraites des valeurs différentes. Je crois que c'est le comportement correct si vous devez retourner sumf et sumb, sinon vous n'obtenez pas nécessairement les valeurs qui ont créé maxdiff.

+0

N'a pas essayé, mais je suppose que cela retournerait plus d'une ligne par date si elles partagent le même max-diff? Comme le comportement dans ce cas n'est pas défini, je suis curieux de savoir si c'est l'intention de l'OP :) –

+0

J'ai mis à jour avec la sortie de la requête. – RedFilter

+0

Merci! C'est évidemment un exemple, et traduire cela en un problème «réel» peut prendre du temps. Seule raison, je ne l'ai pas marqué comme la réponse. C'est, après tout, une requête droite alors que la réponse utilise ces variables sales ... :) –

Questions connexes