146 votes

Comment sélectionner uniquement les premières lignes pour chaque valeur unique d'une colonne ?

Supposons que je dispose d'une table d'adresses de clients :

+-----------------------+------------------------+
|         CName         |      AddressLine       |
+-----------------------+------------------------+
|  John Smith           |  123 Nowheresville     |
|  Jane Doe             |  456 Evergreen Terrace |
|  John Smith           |  999 Somewhereelse     |
|  Joe Bloggs           |  1 Second Ave          |
+-----------------------+------------------------+

Dans la table, un client comme Jean Dupont peut avoir plusieurs adresses. J'ai besoin des SELECT pour cette table afin de ne renvoyer que la première ligne trouvée lorsqu'il y a des doublons dans 'CName'. Pour cette table, la requête doit renvoyer toutes les lignes à l'exception de la troisième (ou de la première - n'importe laquelle de ces deux adresses est acceptable, mais une seule peut être renvoyée).

Existe-t-il un mot-clé que je puisse ajouter à la rubrique SELECT pour filtrer en fonction du fait que le serveur a déjà vu la valeur de la colonne auparavant ?

171voto

gbn Points 197263

La réponse est très simple si vous dites que vous ne vous souciez pas de l'adresse utilisée.

SELECT
    CName, MIN(AddressLine)
FROM
    MyTable
GROUP BY
    CName

Si vous souhaitez obtenir le premier résultat en fonction, par exemple, d'une colonne "insérée", la requête est différente.

SELECT
    M.CName, M.AddressLine,
FROM
    (
    SELECT
        CName, MIN(Inserted) AS First
    FROM
        MyTable
    GROUP BY
        CName
    ) foo
    JOIN
    MyTable M ON foo.CName = M.CName AND foo.First = M.Inserted

34voto

Ben Thul Points 7319

Dans SQL 2k5+, vous pouvez faire quelque chose comme :

;with cte as (
  select CName, AddressLine,
  rank() over (partition by CName order by AddressLine) as [r]
  from MyTable
)
select CName, AddressLine
from cte
where [r] = 1

34voto

FatihAkici Points 1420

Vous pouvez utiliser le row_number() over(partition by ...) comme suit :

select * from
(
select *
, ROW_NUMBER() OVER(PARTITION BY CName ORDER BY AddressLine) AS row
from myTable
) as a
where row = 1

Cela permet de créer une colonne appelée row qui est un compteur qui s'incrémente à chaque fois qu'il voit le même CName et indexe ces occurrences par AddressLine . En imposant where row = 1 , on peut sélectionner le CName dont AddressLine vient en premier dans l'ordre alphabétique. Si le order by était desc il choisira alors l'option CName dont AddressLine vient en dernier dans l'ordre alphabétique.

8voto

Frank Points 21

Vous pouvez utiliser row_number() pour obtenir le numéro de la ligne. Il utilise le over la commande partition by spécifie quand redémarrer la numérotation et la clause order by sélectionne ce sur quoi le numéro de ligne doit être ordonné. Même si vous avez ajouté un order by à la fin de votre requête, cela préserverait l'ordre dans le fichier over lors de la numérotation.

select *
from mytable
where row_number() over(partition by Name order by AddressLine) = 1

3voto

netfed Points 108

Vous obtiendrez ainsi une ligne de chaque ligne dupliquée. Vous obtiendrez également les colonnes de type bit, et cela fonctionne au moins dans MS Sql Server.

(select cname, address 
from (
  select cname,address, rn=row_number() over (partition by cname order by cname) 
  from customeraddresses  
) x 
where rn = 1) order by cname

Si vous voulez trouver tous les doublons, remplacez simplement rn= 1 par rn > 1. J'espère que cela vous aidera

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X