Pourquoi ne SELECT DISTINCT * FROM tablefonctionne pas pour vous?
ypercubeᵀᴹ
19
Si votre table a un PK, toutes les lignes doivent l'être distinctpar définition. Si vous essayez simplement de sélectionner DISTINCT field1mais de renvoyer toutes les autres colonnes, que doit-il se passer pour les colonnes qui ont plus d'une valeur pour une field1valeur particulière ? Vous auriez besoin d'utiliser GROUP BYet une sorte d'agrégation sur les autres colonnes par exemple.
Martin Smith,
1
Si vous voulez des lignes répétées et pas seulement des lignes distinctes, supprimez le mot clé distinct.
Hyperboreus
2
Pourriez-vous donner un exemple de ce que vous attendez des résultats? Jusqu'à présent, je ne peux donner aucun sens à votre requête souhaitée.
Qui peut parfois être écrit avec une déclaration distincte:
selectdistincton field1 *fromtable
Sur la plupart des plates-formes, cependant, aucun des éléments ci-dessus ne fonctionnera car le comportement sur les autres colonnes n'est pas spécifié. (Le premier fonctionne dans MySQL, si c'est ce que vous utilisez.)
Vous pouvez récupérer les champs distincts et vous contenter de choisir une seule ligne arbitraire à chaque fois.
Sur certaines plates-formes (par exemple PostgreSQL, Oracle, T-SQL), cela peut être fait directement en utilisant des fonctions de fenêtre:
Sur d'autres (MySQL, SQLite), vous devrez écrire des sous-requêtes qui vous feront joindre la table entière avec elle-même ( exemple ), donc pas recommandé.
La requête n'analysera pas pour moi et donne une erreur: The ranking function "row_number" must have an ORDER BY clause. Nous devons ajouter la clause order by après la partition par field1. Donc, la bonne requête sera select * from ( select *, row_number() over (partition by field1 order by orderbyFieldName) as row_number from table ) as rows where row_number = 1
Ankur-m
1
Merci! J'étais dans le même problème et la solution était le GROUP BY
Joaquin Iurchuk
2
Également dans Oracle (Oracle SQL Developer), vous ne pouvez pas spécifier select *, row_number() over (partition by field1 order by field2) as row_number from table. Vous devez utiliser explicitement le nom / alias de table dans la requête de sélectionselect **table**.*, row_number() over (partition by field1 order by field2) as row_number from table
meta4
1
@jarlh: Peut-être ... aujourd'hui. Comme vous pouvez le remarquer, cette réponse a presque 7 ans, un moment où ce n'était pas le cas dans la mesure où je me souviens de l'arrière quand j'étais actif. Vous êtes invités à retagger et / ou modifier la réponse si vous le jugez nécessaire.
Denis de Bernardy
2
select distinct on (field1) * from table; fonctionne aussi dans PostgreSQL
Chilianu Bogdan
61
D'après la formulation de votre question, je comprends que vous souhaitez sélectionner les valeurs distinctes pour un champ donné et pour chacune de ces valeurs avoir toutes les autres valeurs de colonne dans la même ligne répertoriées. La plupart des SGBD ne permettent pas cela avec ni DISTINCTni GROUP BY, car le résultat n'est pas déterminé.
Pensez-y comme ceci: si votre field1se produit plus d'une fois, quelle valeur de field2sera répertoriée (étant donné que vous avez la même valeur pour field1dans deux lignes mais deux valeurs distinctes de field2dans ces deux lignes).
Vous pouvez cependant utiliser des fonctions d'agrégation (explicitement pour chaque champ que vous souhaitez afficher) et utiliser un GROUP BYau lieu de DISTINCT:
+1 pour cette solution. Donc, nous pouvons le faire SELECT field1, MIN(field2), MIN(field3), MIN(field4), .... FROM table GROUP BY field1, et les champs2, 3, 4 ,,, ne doivent pas nécessairement être des entiers (ou d'autres chiffres), ils peuvent également être des champs char
traquer le
Fonctionnait bien jusqu'à ce que je sois coincé dans une colonne booléenne. Les valeurs de colonne MIN (Dynamique) sont modifiées en false même si c'était vrai. Toute autre fonction d'agrégation disponible pour adresser boolean - signonsridhar il y a 6 minutes. Sum (dynamic) changé false en 1
signonsridhar
1
Grande suggestion, m'a conduit à ma solution qui, je pense, est plus universelle - jetez un coup d'œil!
Garrett Simpson
@signonsridhar transforme votre booléen en entier et utilise la somme; par exemplesum(cast(COL as int)) > 0
Drew
26
Si j'ai bien compris votre problème, il est similaire à celui que je viens d'avoir. Vous voulez pouvoir 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 fonction d'agrégation, quel champ que vous regroupez GROUP BY sera votre fichier DISTINCT.
Si vous faites votre requête:
SELECT*fromtableGROUPBY field1;
Il affichera tous vos résultats sur la base d'une seule instance de field1.
Par exemple, si vous avez une table avec nom, adresse et ville. Une seule personne a plusieurs adresses enregistrées, mais vous voulez juste une seule adresse pour la personne, vous pouvez interroger comme suit:
SELECT*FROM persons GROUPBY name;
Le résultat sera qu'une seule instance de ce nom apparaîtra avec son adresse, et l'autre sera omise de la table résultante. Attention: si vos fichiers ont des valeurs atomiques telles que firstName, lastName que vous souhaitez regrouper par les deux.
SELECT*FROM persons GROUPBY lastName, firstName;
car si deux personnes ont le même nom de famille et que vous ne les regroupez que par nom, l'une de ces personnes sera omise des résultats. Vous devez garder ces choses en considération. J'espère que cela t'aides.
Pourquoi y a-t-il Caliasquand il peut fonctionner sans lui? en ligneFROM dbo.TABLE AS C
Talha
2
Je pense que cela est dû à mon utilisation de RedGate SQLPrompt. De la façon dont je l'ai configuré, il ajoute toujours des alias - même si cela n'est pas nécessaire. C'est là "juste au cas où"
Stormy
Cela semblait prometteur pour moi, mais cela a toujours ramené toutes les lignes, pas le champ distinct1. :(
Michael Fever
13
Voilà une très bonne question. J'ai déjà lu quelques réponses utiles ici, mais je peux probablement ajouter une explication plus précise.
La réduction du nombre de résultats de requête avec une instruction GROUP BY est facile tant que vous ne recherchez pas d'informations supplémentaires. Supposons que vous obteniez le tableau suivant «emplacements».
--country-- --city--
France Lyon
Poland Krakow
France Paris
France Marseille
Italy Milano
Maintenant, la requête
SELECT country FROM locationsGROUPBY country
aura pour résultat:
--country--
France
Poland
Italy
Cependant, la requête suivante
SELECT country, city FROM locationsGROUPBY country
... lance 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 dans le champ à droite de "France"?
Afin de corriger la deuxième requête, vous devez ajouter ces informations. Pour ce faire, vous pouvez utiliser les fonctions MAX () ou MIN () en sélectionnant la valeur la plus grande ou la plus petite parmi tous les candidats. MAX () et MIN () ne s'appliquent pas seulement aux valeurs numériques, mais comparent également l'ordre alphabétique des valeurs de chaîne.
SELECT country, MAX(city)FROM locationsGROUPBY country
aura pour résultat:
--country-- --city--
France Paris
Poland Krakow
Italy Milano
ou:
SELECT country, MIN(city)FROM locationsGROUPBY country
aura pour résultat:
--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 dans les 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 l'intégralité de votre requête dans une sous-requête et de construire la colonne supplémentaire en dehors d'elle à la main:
SELECT
countrylist.*,(SELECTTOP1 cityFROM locationsWHERE
country = countrylist.countryAND city like'M%')FROM(SELECT country FROM locationsGROUPBY country) countrylist
aura pour résultat:
--country-- --city--
France Marseille
Poland NULL
Italy Milano
Grande question @aryaxt - vous pouvez dire que c'était une excellente question parce que vous l'avez posée il y a 5 ans et je suis tombée dessus aujourd'hui en essayant de trouver la réponse!
J'ai juste essayé de modifier la réponse acceptée pour l'inclure, mais au cas où ma modification ne se ferait pas dans:
Si votre table n'était pas si grande et en supposant que votre clé primaire était un entier à incrémentation automatique, vous pourriez faire quelque chose comme ceci:
SELECTtable.*FROMtable--be able to take out dupes laterLEFTJOIN(SELECT field, MAX(id)as id
FROMtableGROUPBY field
)as noDupes on noDupes.id =table.id
WHERE//this will result in only the last instance being seen
noDupes.id isnotNULL
Pour SQL Server, vous pouvez utiliser le dense_rank et les fonctions de fenêtrage supplémentaires pour obtenir toutes les lignes ET les colonnes avec des valeurs dupliquées sur les colonnes spécifiées. Voici un exemple...
with t as(select col1 ='a', col2 ='b', col3 ='c', other ='r1'unionallselect col1 ='c', col2 ='b', col3 ='a', other ='r2'unionallselect col1 ='a', col2 ='b', col3 ='c', other ='r3'unionallselect col1 ='a', col2 ='b', col3 ='c', other ='r4'unionallselect col1 ='c', col2 ='b', col3 ='a', other ='r5'unionallselect col1 ='a', col2 ='a', col3 ='a', other ='r6'), tdr as(select*,
total_dr_rows = count(*)over(partitionby dr)from(select*,
dr = dense_rank()over(orderby col1, col2, col3),
dr_rn = row_number()over(partitionby col1, col2, col3 orderby 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.
Cela a fonctionné pour moi !! Cela vaut la peine de le noter, si vous utilisez fetch_array (), vous devrez alors appeler chaque ligne via une étiquette d'index plutôt que d'appeler implicitement le nom de la ligne. Il n'y a pas assez de caractères pour écrire l'exemple que j'ai: X désolé !!
Comme mentionné dans la réponse acceptée, fonctionnerait pour la plupart des incarnations de SQL - uniquement pour MYSQL
Garrett Simpson
0
J'ai trouvé cela ailleurs ici, mais c'est une solution simple qui fonctionne:
WITH cte AS/* Declaring a new table named 'cte' to be a clone of your table */(SELECT*, ROW_NUMBER()OVER(PARTITIONBY id ORDERBY val1 DESC)AS rn
FROM MyTable /* Selecting only unique values based on the "id" field */)SELECT*/* Here you can specify several columns to retrieve */FROM cte
WHERE rn =1
Cela ne répond pas à la question, l'OP tentait d'obtenir toutes les données de la table mais supprimait les lignes contenant des doublons d'un seul champ
Garrett Simpson
-3
SELECT*fromtablewhere field in(SELECTdistinct field fromtable)
Cela ne fera pas l'affaire. Vous avez sélectionné la colonne distincte dans la sous-requête, mais la clause where obtient toutes ces colonnes avec cette valeur. Ainsi, la requête équivaut à écrire «sélectionner * dans la table», à moins que la colonne «champ» ne soit une colonne unique, auquel cas le distinct sur cette colonne n'est pas du tout requis.
Ankur-m
-3
SELECT DISTINCT FIELD1, FIELD2, FIELD3 FROM TABLE1 fonctionne si les valeurs des trois colonnes sont uniques dans la table.
Si, par exemple, vous avez plusieurs valeurs identiques pour le prénom, mais que le nom et les autres informations dans les colonnes sélectionnées sont différents, l'enregistrement sera inclus dans le jeu de résultats.
Cela ne répond pas à la question, l'OP tentait d'obtenir toutes les données de la table mais supprimait les lignes contenant des doublons d'un seul champ
SELECT DISTINCT * FROM table
fonctionne pas pour vous?distinct
par définition. Si vous essayez simplement de sélectionnerDISTINCT field1
mais de renvoyer toutes les autres colonnes, que doit-il se passer pour les colonnes qui ont plus d'une valeur pour unefield1
valeur particulière ? Vous auriez besoin d'utiliserGROUP BY
et une sorte d'agrégation sur les autres colonnes par exemple.Réponses:
Vous recherchez un groupe par:
Qui peut parfois être écrit avec une déclaration distincte:
Sur la plupart des plates-formes, cependant, aucun des éléments ci-dessus ne fonctionnera car le comportement sur les autres colonnes n'est pas spécifié. (Le premier fonctionne dans MySQL, si c'est ce que vous utilisez.)
Vous pouvez récupérer les champs distincts et vous contenter de choisir une seule ligne arbitraire à chaque fois.
Sur certaines plates-formes (par exemple PostgreSQL, Oracle, T-SQL), cela peut être fait directement en utilisant des fonctions de fenêtre:
Sur d'autres (MySQL, SQLite), vous devrez écrire des sous-requêtes qui vous feront joindre la table entière avec elle-même ( exemple ), donc pas recommandé.
la source
The ranking function "row_number" must have an ORDER BY clause
. Nous devons ajouter la clause order by après la partition par field1. Donc, la bonne requête seraselect * from ( select *, row_number() over (partition by field1 order by orderbyFieldName) as row_number from table ) as rows where row_number = 1
GROUP BY
select *, row_number() over (partition by field1 order by field2) as row_number from table
. Vous devez utiliser explicitement le nom / alias de table dans la requête de sélectionselect **table**.*, row_number() over (partition by field1 order by field2) as row_number from table
select distinct on (field1) * from table
; fonctionne aussi dans PostgreSQLD'après la formulation de votre question, je comprends que vous souhaitez sélectionner les valeurs distinctes pour un champ donné et pour chacune de ces valeurs avoir toutes les autres valeurs de colonne dans la même ligne répertoriées. La plupart des SGBD ne permettent pas cela avec ni
DISTINCT
niGROUP BY
, car le résultat n'est pas déterminé.Pensez-y comme ceci: si votre
field1
se produit plus d'une fois, quelle valeur defield2
sera répertoriée (étant donné que vous avez la même valeur pourfield1
dans deux lignes mais deux valeurs distinctes defield2
dans ces deux lignes).Vous pouvez cependant utiliser des fonctions d'agrégation (explicitement pour chaque champ que vous souhaitez afficher) et utiliser un
GROUP BY
au lieu deDISTINCT
:la source
SELECT field1, MIN(field2), MIN(field3), MIN(field4), .... FROM table GROUP BY field1
, et les champs2, 3, 4 ,,, ne doivent pas nécessairement être des entiers (ou d'autres chiffres), ils peuvent également être des champs charsum(cast(COL as int)) > 0
Si j'ai bien compris votre problème, il est similaire à celui que je viens d'avoir. Vous voulez pouvoir 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 fonction d'agrégation, quel champ que vous regroupez GROUP BY sera votre fichier DISTINCT.
Si vous faites votre requête:
Il affichera tous vos résultats sur la base d'une seule instance de field1.
Par exemple, si vous avez une table avec nom, adresse et ville. Une seule personne a plusieurs adresses enregistrées, mais vous voulez juste une seule adresse pour la personne, vous pouvez interroger comme suit:
Le résultat sera qu'une seule instance de ce nom apparaîtra avec son adresse, et l'autre sera omise de la table résultante. Attention: si vos fichiers ont des valeurs atomiques telles que firstName, lastName que vous souhaitez regrouper par les deux.
car si deux personnes ont le même nom de famille et que vous ne les regroupez que par nom, l'une de ces personnes sera omise des résultats. Vous devez garder ces choses en considération. J'espère que cela t'aides.
la source
la source
C
alias
quand il peut fonctionner sans lui? en ligneFROM dbo.TABLE AS C
Voilà une très bonne question. J'ai déjà lu quelques réponses utiles ici, mais je peux probablement ajouter une explication plus précise.
La réduction du nombre de résultats de requête avec une instruction GROUP BY est facile tant que vous ne recherchez pas d'informations supplémentaires. Supposons que vous obteniez le tableau suivant «emplacements».
Maintenant, la requête
aura pour résultat:
Cependant, la requête suivante
... lance 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 dans le champ à droite de "France"?
Afin de corriger la deuxième requête, vous devez ajouter ces informations. Pour ce faire, vous pouvez utiliser les fonctions MAX () ou MIN () en sélectionnant la valeur la plus grande ou la plus petite parmi tous les candidats. MAX () et MIN () ne s'appliquent pas seulement aux valeurs numériques, mais comparent également l'ordre alphabétique des valeurs de chaîne.
aura pour résultat:
ou:
aura pour résultat:
Ces fonctions sont une bonne solution tant que vous êtes d'accord avec la sélection de votre valeur dans les 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 l'intégralité de votre requête dans une sous-requête et de construire la colonne supplémentaire en dehors d'elle à la main:
aura pour résultat:
la source
Grande question @aryaxt - vous pouvez dire que c'était une excellente question parce que vous l'avez posée il y a 5 ans et je suis tombée dessus aujourd'hui en essayant de trouver la réponse!
J'ai juste essayé de modifier la réponse acceptée pour l'inclure, mais au cas où ma modification ne se ferait pas dans:
Si votre table n'était pas si grande et en supposant que votre clé primaire était un entier à incrémentation automatique, vous pourriez faire quelque chose comme ceci:
la source
Essayer
la source
Vous pouvez le faire avec une
WITH
clause.Par exemple:
Cela vous permet également de sélectionner uniquement les lignes sélectionnées dans la
WITH
requête de clauses.la source
Pour SQL Server, vous pouvez utiliser le dense_rank et les fonctions de fenêtrage supplémentaires pour obtenir toutes les lignes ET les colonnes avec des valeurs dupliquées sur les colonnes spécifiées. Voici un exemple...
Cela prend un nombre de lignes pour chaque combinaison distincte de col1, col2 et col3.
la source
la source
dans
ORDER BY
je viens de mettre l'exemple ici, vous pouvez également ajouter un champ ID dans cela source
J'ai trouvé cela ailleurs ici, mais c'est une solution simple qui fonctionne:
la source
Ajoutez GROUP BY au champ que vous souhaitez vérifier pour les doublons auxquels votre requête pourrait ressembler
field1 sera vérifié pour exclure les enregistrements en double
ou vous pouvez interroger comme
les enregistrements en double du champ1 sont exclus de SELECT
la source
filed2 must appear in the GROUP BY clause or be used in an aggregate function
Incluez simplement tous vos champs dans la clause GROUP BY.
la source
Cela peut être fait par requête interne
la source
la source
SELECT DISTINCT FIELD1, FIELD2, FIELD3 FROM TABLE1 fonctionne si les valeurs des trois colonnes sont uniques dans la table.
Si, par exemple, vous avez plusieurs valeurs identiques pour le prénom, mais que le nom et les autres informations dans les colonnes sélectionnées sont différents, l'enregistrement sera inclus dans le jeu de résultats.
la source
Je suggère d'utiliser
De cette façon, si vous avez la même valeur dans field1 sur plusieurs lignes, tous les enregistrements seront retournés.
la source
SELECT * FROM table;
. Encore plus C'est lent.