2009-12-25 5 views
2

Je veux obtenirproblème sql, défi

id a b  c 
-------------------- 
1 1 100 90 
6 2 50 100 

... à partir de:

id a b  c 
-------------------- 
1 1 100 90 
2 1 300 50 
3 1 200 20 
4 2 200 30 
5 2 300 70 
6 2 50 100 

Il est la ligne avec le groupe le plus petit b par un.

Comment le faire avec sql?

EDIT

je pensais que ce peut être réalisé par

select * from table group by a having min(b); 

que j'ai trouvé plus tard, il est faux.

Mais est-il possible de le faire avec having déclaration?

J'utilise MySQL

+1

Ajout de la balise 'most-n-per-group' parce que cette question est essentiellement la même que des dizaines d'autres demandes sur StackOverflow. –

+1

Et si j'ajoutais la ligne suivante à vos exemples de données: 'insérer dans les valeurs mytable (id, a, b, c) (7, 2, 50, 80);' Quelle ligne vous attendriez-vous dans votre requête: 'id = 6' ou' id = 7'? tous les deux? – Asaph

+1

Bon point - devrait-on rencontrer des liens (où il y a deux rangées avec la même valeur b minimale), comment une rangée serait-elle sélectionnée par rapport à l'autre? –

Répondre

3
SELECT t1.* 
FROM mytable t1 
LEFT OUTER JOIN mytable t2 
    ON (t1.a=t2.a AND t1.b>t2.b) 
WHERE t2.a IS NULL; 

Cela fonctionne parce qu'il devrait y avoir aucune ligne correspondante t2 avec le même a et une moindre b.


mise à jour: Cette solution a le même problème avec les liens que d'autres personnes ont identifiés. Cependant, nous pouvons rompre les liens:

SELECT t1.* 
FROM mytable t1 
LEFT OUTER JOIN mytable t2 
    ON (t1.a=t2.a AND (t1.b>t2.b OR t1.b=t2.b AND t1.id>t2.id)) 
WHERE t2.a IS NULL; 

En supposant par exemple que dans le cas d'égalité, la ligne avec la partie inférieure id doit être la ligne que nous choisissons.


Cela ne fait pas l'affaire:

select * from table group by a having min(b); 

Parce que HAVING MIN(b) teste seulement que la moindre valeur dans le groupe n'est pas faux (ce qui signifie que MySQL zéro). La condition d'une clause HAVING est d'exclure des groupes du résultat, pas de choisir la ligne du groupe à renvoyer.

+0

Bonnes fêtes à toi aussi, Bill. Hélas, je ne peux pas voter plus d'une fois. –

0

Vous avez raison. sélectionnez min (b), a de groupe de table par a. Si vous voulez la ligne entière, alors vous utilisez la fonction d'analyse. Cela dépend de la base de données s/w.

1

Utilisation:

SELECT DISTINCT 
     x.* 
    FROM TABLE x 
    JOIN (SELECT t.a, 
       MIN(t.b) 'min_b' 
      FROM TABLE T 
     GROUP BY t.a) y ON y.a = x.a 
        AND y.min_b = x.b 
+0

Lorsque j'essaie cela en MySQL (en utilisant les instructions 'create table' et' insert' de ma réponse pour configurer et ajuster les noms de tables à faire correspondre), j'obtiens 'ERROR 1054 (42S22): Colonne inconnue 'ta' dans 'sur clause''. – Asaph

+0

Vous devriez probablement utiliser 'ON y.a = x.a AND y.min_b = x.b' dans la jointure. –

+0

Oups - trop de lait de poule, corrigé. –

3

MySQL:

select t1.* from test as t1 
inner join 
(select t2.a, min(t2.b) as min_b from test as t2 group by t2.a) as subq 
on subq.a=t1.a and subq.min_b=t1.b; 

Voici la preuve:

mysql> create table test (id int unsigned primary key auto_increment, a int unsigned not null, b int unsigned not null, c int unsigned not null) engine=innodb; 
Query OK, 0 rows affected (0.55 sec) 

mysql> insert into test (a,b,c) values (1,100,90), (1,300,50), (1,200,20), (2,200,30), (2,300,70), (2,50,100); 
Query OK, 6 rows affected (0.39 sec) 
Records: 6 Duplicates: 0 Warnings: 0 

mysql> select * from test; 
+----+---+-----+-----+ 
| id | a | b | c | 
+----+---+-----+-----+ 
| 1 | 1 | 100 | 90 | 
| 2 | 1 | 300 | 50 | 
| 3 | 1 | 200 | 20 | 
| 4 | 2 | 200 | 30 | 
| 5 | 2 | 300 | 70 | 
| 6 | 2 | 50 | 100 | 
+----+---+-----+-----+ 
6 rows in set (0.00 sec) 

mysql> select t1.* from test as t1 inner join (select t2.a, min(t2.b) as min_b from test as t2 group by t2.a) as subq on subq.a=t1.a and subq.min_b=t1.b; 
+----+---+-----+-----+ 
| id | a | b | c | 
+----+---+-----+-----+ 
| 1 | 1 | 100 | 90 | 
| 6 | 2 | 50 | 100 | 
+----+---+-----+-----+ 
2 rows in set (0.00 sec) 
+1

Essayez à nouveau après avoir fait un "insert into test values ​​(7,2,100,95)" et cela ne fonctionne pas. –

+0

Ceci ne fonctionne que si les MIN (b) pour chaque groupe a, * ne * apparaissent jamais comme des non-MIN() dans les autres groupes-a. Par exemple pour les tableaux {a, b} (1 200), (2 100), (2 200); il retournerait les trois lignes, même s'il n'y a que deux groupes. – RBarryYoung

+0

Pourquoi les gens sont-ils en train d'upvoter cela? C'est clairement l'une des rares réponses incorrectes ici. – RBarryYoung

0

Cela dépend de la mise en œuvre, mais cela est généralement plus rapide que l'auto méthode de jointure:

SELECT id, a, b, c 
FROM 
    (
     SELECT id, a, b, c 
     , ROW_NUMBER() OVER(PARTITION BY a ORDER BY b ASC) AS [b IN a] 
    ) As SubqueryA 
WHERE [b IN a] = 1 

Bien sûr, cela nécessite que votre implémentation SQL soit assez à jour avec la norme.

+0

Intéressant - cela fonctionnerait sur Oracle 9i + et SQL Server 2005 +, mais pas MySQL –

+0

Est-ce que la dernière version de MySQL n'a pas encore la fonction ROW_NUMBER()? C'est vraiment dommage, c'est extrêmement utile (et ça fait un bout de temps que ça existe dans la norme.) – RBarryYoung

+0

Pas de classement du tout:/ –