SQL / mysql-choisir distinct / UNIQUE mais retourner toutes les colonnes?

SELECT DISTINCT field1, field2, field3, ......   FROM table

j'essaie d'accomplir la déclaration sql suivante mais je veux qu'elle retourne toutes les colonnes est-ce possible? Quelque chose comme:

SELECT DISTINCT field1, * from table
300
demandé sur vaibhavcool20 2011-05-25 19:55:16

15 réponses

vous recherchez un groupe par:

select *
from table
group by field1

qui peut parfois être écrit avec un distinct sur la déclaration:

select distinct on field1 *
from table

sur la plupart des plates-formes, cependant, aucun des deux ci-dessus ne fonctionnera parce que le comportement sur les autres colonnes est indéterminée. (Le premier fonctionne avec MySQL, si c'est ce que vous êtes en utilisant.)

vous pourriez aller chercher les champs distincts et vous en tenir à choisir une seule rangée arbitraire à chaque fois.

sur certaines plateformes (par exemple PostgreSQL, Oracle, T-SQL) cela peut être fait directement en utilisant les fonctions de fenêtre:

select *
from (
   select *,
          row_number() over (partition by field1 order by field2) as row_number
   from table
   ) as rows
where row_number = 1

sur d'autres (MySQL, SQLite), vous aurez besoin d'écrire des sous-séries qui vous feront rejoindre la table entière avec lui-même ( exemple ), donc pas recommandé.

335
répondu Denis de Bernardy 2017-05-23 12:34:42

D'après le libellé de votre question, je comprends que vous voulez sélectionner les valeurs distinctes pour un champ donné et pour chacune de ces valeurs d'avoir toutes les autres valeurs de colonne dans la même rangée énumérée. La plupart des DBMSs ne le permettent pas avec ni DISTINCT ni GROUP BY , parce que le résultat n'est pas déterminé.

pensez à cela comme ceci: si votre field1 se produit plus d'une fois, quelle valeur de field2 sera listée (étant donné que vous avez la même valeur pour field1 en deux lignes, mais deux valeurs distinctes de field2 dans ces deux lignes).

vous pouvez cependant utiliser des fonctions agrégées (explicitement pour chaque champ que vous voulez afficher) et en utilisant un GROUP BY au lieu de DISTINCT :

SELECT field1, MAX(field2), COUNT(field3), SUM(field4), .... FROM table GROUP BY field1
47
répondu Costi Ciudatu 2011-05-25 16:13:23

si j'ai bien compris votre problème, il est similaire à celui que je viens d'avoir. Vous voulez être en mesure de limiter L'utilisabilité de DISTINCT à un champ spécifié, plutôt que de l'appliquer à toutes les données.

si vous utilisez GROUP BY sans une fonction agrégée, quel que soit le champ que vous groupez, ce sera votre dépôt DISTINCT.

si vous faites votre requête:

SELECT * from table GROUP BY field1;

il affichera tous vos résultats basés sur une seule instance de champ1.

Par exemple, si vous avez une table avec le nom, l'adresse et la ville. Une seule personne a plusieurs adresses enregistrées, mais vous voulez juste une adresse unique pour la personne, vous pouvez requête comme suit:

SELECT * FROM persons GROUP BY name;

Le résultat sera qu'une seule instance de ce nom apparaîtra avec son adresse, et l'autre sera omis dans le tableau résultant. Attention: si vos fichiers ont des valeurs atomiques telles que firstName, lastName, vous voulez les grouper par les deux.

SELECT * FROM persons GROUP BY lastName, firstName;

parce que si deux personnes ont le même nom de famille et que vous ne groupez que par lastName, une de ces personnes sera omise des résultats. Vous devez garder ces choses en considération. Espérons que cette aide.

16
répondu rocklandcitizen 2013-05-14 17:43:16
SELECT  c2.field1 ,
        field2
FROM    (SELECT DISTINCT
                field1
         FROM   dbo.TABLE AS C
        ) AS c1
        JOIN dbo.TABLE AS c2 ON c1.field1 = c2.field1
10
répondu Stormy 2011-05-25 15:59:28

C'est une très bonne question. J'ai déjà lu quelques réponses utiles, mais je peux probablement ajouter une explication plus précise.

réduire le nombre de résultats de requête avec un groupe par l'énoncé est facile Aussi longtemps que vous n'interrogez pas l'information supplémentaire. Supposons que vous ayez le tableau suivant "emplacements".

--country-- --city--
 France      Lyon
 Poland      Krakow
 France      Paris
 France      Marseille
 Italy       Milano

Maintenant, la requête

SELECT country FROM locations
GROUP BY country

résultera en:

--country--
 France
 Poland
 Italy

cependant, la requête suivante

SELECT country, city FROM locations
GROUP BY country

...une erreur dans MS SQL, car comment votre ordinateur pourrait-il savoir laquelle des trois villes françaises "Lyon", "Paris" ou "Marseille" vous voulez lire sur le terrain à droite de "France"?

afin de corriger la deuxième requête, vous devez ajouter cette information. Une façon de le faire est d'utiliser les fonctions MAX() ou MIN(), en sélectionnant la plus grande ou la plus petite valeur parmi tous les candidats. MAX() et MIN () ne sont pas seulement applicables aux valeurs numériques, mais aussi comparer l'ordre alphabétique des valeurs de chaîne.

SELECT country, MAX(city) FROM locations
GROUP BY country

résultera en:

--country-- --city--
 France      Paris
 Poland      Krakow
 Italy       Milano

ou:

SELECT country, MIN(city) FROM locations
GROUP BY country

résultera en:

--country-- --city--
 France      Lyon
 Poland      Krakow
 Italy       Milano

ces fonctions sont une bonne solution tant que vous êtes d'accord avec la sélection de votre valeur à partir des deux extrémités de l'ordre alphabétique (ou numérique). Mais que faire si ce n'est pas le cas? Supposons que vous ayez besoin d'une valeur avec une certaine caractéristique, par exemple en commençant par la lettre "M". Maintenant, les choses se compliquent.

la seule solution que j'ai pu trouver jusqu'à présent est de mettre toute votre requête dans un sous-jeu, et de construire la colonne supplémentaire à l'extérieur de celui-ci par les mains:

SELECT
     countrylist.*,
     (SELECT TOP 1 city
     FROM locations
     WHERE
          country = countrylist.country
          AND city like 'M%'
     )
FROM
(SELECT country FROM locations
GROUP BY country) countrylist

résultera en:

--country-- --city--
 France      Marseille
 Poland      NULL
 Italy       Milano
5
répondu Ulf Sanne 2017-10-24 16:49:50

grande question @aryaxt -- vous pouvez dire que c'était une grande question parce que vous l'avez posée il y a 5 ans et je suis tombé sur elle aujourd'hui en essayant de trouver la réponse!

j'ai juste essayé d'éditer la réponse acceptée pour inclure ceci, mais au cas où mon édition ne le fait pas dans:

si votre table n'était pas si grande, et en supposant que votre clé primaire était un entier auto-incrémentant vous pourriez faire quelque chose comme ceci:

SELECT 
  table.*
FROM table
--be able to take out dupes later
LEFT JOIN (
  SELECT field, MAX(id) as id
  FROM table
  GROUP BY field
) as noDupes on noDupes.id = table.id
WHERE
  //this will result in only the last instance being seen
  noDupes.id is not NULL
3
répondu Garrett Simpson 2017-11-13 16:53:09

vous pouvez le faire avec une clause WITH .

par exemple:

WITH c AS (SELECT DISTINCT a, b, c FROM tableName)
SELECT * FROM tableName r, c WHERE c.rowid=r.rowid AND c.a=r.a AND c.b=r.b AND c.c=r.c

cela vous permet également de sélectionner uniquement les lignes sélectionnées dans la requête WITH .

2
répondu user2225399 2013-03-29 18:54:13

pour SQL Server vous pouvez utiliser les fonctions dense_rank et windowing supplémentaires pour obtenir toutes les lignes et les colonnes avec des valeurs dupliquées sur les colonnes spécifiées. Ici est un exemple...

with t as (
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r1' union all
    select col1 = 'c', col2 = 'b', col3 = 'a', other = 'r2' union all
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r3' union all
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r4' union all
    select col1 = 'c', col2 = 'b', col3 = 'a', other = 'r5' union all
    select col1 = 'a', col2 = 'a', col3 = 'a', other = 'r6'
), tdr as (
    select 
        *, 
        total_dr_rows = count(*) over(partition by dr)
    from (
        select 
            *, 
            dr = dense_rank() over(order by col1, col2, col3),
            dr_rn = row_number() over(partition by col1, col2, col3 order by other)
        from 
            t
    ) x
)

select * from tdr where total_dr_rows > 1

cela prend un nombre de lignes pour chaque combinaison distincte de col1, col2 et col3.

1
répondu dotjoe 2015-04-02 16:26:07
SELECT *
FROM tblname
GROUP BY duplicate_values
ORDER BY ex.VISITED_ON DESC
LIMIT 0 , 30

dans ORDER BY je viens de mettre l'exemple ici, vous pouvez aussi ajouter le champ ID dans ce

0
répondu SagarPPanchal 2014-03-04 17:17:30

Ajouter groupe par au champ que vous voulez vérifier pour les doublons votre requête peut ressembler à

SELECT field1, field2, field3, ......   FROM table GROUP BY field1

la Zone 1 sera cochée pour exclure les enregistrements en double

ou vous pouvez interroger comme

SELECT *  FROM table GROUP BY field1

les enregistrements en double du Champ 1 sont exclus de SELECT

-1
répondu iCodeCrew 2014-10-05 23:12:35

je suggérerais d'utiliser

SELECT  * from table where field1 in 
(
  select distinct field1 from table
)

de cette façon, si vous avez la même valeur dans champ1 sur plusieurs lignes, tous les dossiers seront retournés.

-1
répondu Ioannis K 2018-01-25 19:31:25

incluez tous vos champs dans le groupe par clause.

-2
répondu wayneh 2013-06-24 21:32:05

Il peut être fait par requête interne

$query = "SELECT * 
            FROM (SELECT field
                FROM table
                ORDER BY id DESC) as rows               
            GROUP BY field";
-2
répondu Zaheer Babar 2016-11-25 15:36:57
SELECT * from table where field in (SELECT distinct field from table)
-3
répondu Andrew 2012-07-20 14:00:19

sélectionnez le champ DISTINCT 1, LE CHAMP 2, le champ 3 du tableau 1 si les valeurs des trois colonnes sont uniques dans le tableau.

Si, par exemple, vous avez plusieurs valeurs identiques pour le prénom, mais le nom de famille et d'autres informations dans les colonnes sélectionnées est différent, l'enregistrement sera inclus dans le jeu de résultats.

-3
répondu Doris Gammenthaler 2014-08-06 15:45:44