2009-12-17 4 views
32

Comme le dit le titre, j'utilise SQL Server 2008. Toutes mes excuses si cette question est très basique. Je n'utilise SQL que depuis quelques jours. En ce moment, je la requête suivante:SQL Server 2008: TOP 10 et distincts ensemble

SELECT TOP 10 p.id, pl.nm, pl.val, pl.txt_val 

from dm.labs pl 
join mas_data.patients p  
    on pl.id = p.id 
    where pl.nm like '%LDL%' 
    and val is not null 

Ce que je veux faire est d'utiliser select top n avec des valeurs distinctes dans la colonne id. Une recherche dans certains forums dit utiliser

SELECT DISTINCT TOP 10 ... 

mais quand je remplace la première ligne avec

SELECT DISTINCT TOP 10 p.id, pl.nm, pl.val, pl.txt_val 

-je obtenir les mêmes résultats que sans le mot distinct. Que devrais-je faire pour ne filtrer que les entrées d'ID en double?

Merci.

+1

Je pense que vous devez énoncer votre question plus explicitement. Si vous avez trois lignes avec p.id = 1, alors quelle ligne voulez-vous? Celui avec le plus haut ou le plus bas pl.nm, pl.val, pl.txt_val, une combinaison, ou quelque chose d'autre entièrement? SQL ne peut pas appliquer DISTINCT() de cette façon, mais il existe des moyens d'obtenir une ligne par p.id. Vous avez juste besoin de définir les exigences, et nous pouvons vous aider ... –

+0

Est-ce que les patients.ID est une clé primaire? – dan

Répondre

9

L'option facile est d'utiliser Grouper par et sélectionnez min/max pour tous les autres champs

SELECT TOP 10 
    p.id, 
    max(pl.nm), 
    max(pl.val), 
    max(pl.txt_val) 
from 
    dm.labs pl 
join 
    mas_data.patients p  
on 
    pl.id = p.id 
    where 
    pl.nm like '%LDL%' 
and 
    val is not null 
group by 
    p.id 

Cela peut devenir assez fastidieux pour la table large que l'autre option consiste à utiliser le rang sur et partiion

SELECT TOP 10 
    p.id, 
    pl.nm, 
    pl.val, 
    pl.txt_val, 
    rank() over(partition by p.id order by p.id) as Rank 
from 
    dm.labs pl 
join 
    mas_data.patients p  
on 
    pl.id = p.id 
    where 
    pl.nm like '%LDL%' 
and 
    val is not null 
and 
    Rank = 1 
+3

Je ne pense pas que cela soit autorisé. Vous ne pouvez pas référencer les colonnes créées dans la liste SELECT dans la clause WHERE. – siride

+1

Découvrez cette réponse par Halim juste ci-dessous: https://stackoverflow.com/a/37642799/4212710 – typoerrpr

+0

'L'option facile' – eddyP23

1
select top 10 * from 
(
    select distinct p.id, .... 
) 

fonctionnera.

+0

il veut des valeurs distinctes pour les ID autant que je peux voir, donc cela ne fonctionnera pas –

0

DISTINCT supprime les lignes si toutes les valeurs sont égales. Apparemment, vous avez des entrées avec le même p.id mais avec différents pl.nm (ou pl.val ou pl.txt_val). La réponse à votre question dépend de laquelle de ces valeurs vous voulez afficher dans la rangée avec votre p.id (la première? La plus petite? Any?).

4

quelques idées:

  1. Vous avez pas mal de champs dans votre instruction select. Toute valeur étant différente de l'autre rendra cette ligne distincte.
  2. Les clauses TOP sont généralement associées aux clauses WHERE. Sinon TOP ne veut pas dire grand chose. Haut de quoi? La façon dont vous spécifiez "top of what" est de trier en utilisant WHERE
  3. Il est tout à fait possible d'obtenir les mêmes résultats même si vous utilisez TOP et DISTINCT et WHERE. Assurez-vous que les données que vous interrogez peuvent effectivement être filtrées et classées comme vous le souhaitez.

Essayez quelque chose comme ceci:

SELECT DISTINCT TOP 10 p.id, pl.nm -- , pl.val, pl.txt_val 
FROM dm.labs pl 
JOIN mas_data.patients p  
on pl.id = p.id 
where pl.nm like '%LDL%' 
and val is not null 
ORDER BY pl.nm 

Notez que je commentais certains des SELECT pour limiter votre jeu de résultats et de la logique DISTINCT.

0

Je pense que le problème est que vous voulez un résultat pour chaque p.id?

Mais vous obtenez des résultats "en double" pour certains p.id, n'est-ce pas? Le mot-clé DISTINCT s'applique à l'ensemble des résultats, donc s'applique à pl.nm, pl.val, pl.txt_val, et pas seulement à p.id.

Vous avez besoin quelque chose comme

SELECT TOP 10 p.id, max(p1.nm), max (p1.val), ... 
FROM ... 
GROUP BY p.id 

n'a pas besoin du mot-clé distinct alors.

+0

-1 Utiliser MAX de cette manière rendra le jeu de résultats arbitraire. –

+0

oui, mais si vous voulez un résultat par p.id, vous devrez faire quelque chose d'arbitraire ou laisser ces colonnes entièrement – MikeW

+1

Pas nécessairement, si vous voulez la ligne qui est associée à une ligne spécifique pour chaque p.id, par exemple celui avec le max (nm) ou le max(), vous voulez la rangée entière, pas des valeurs maximum aléatoires des rangées potentiellement différentes. La solution proposée par Paul Creasey a le potentiel de le faire simplement en modifiant l'ordre à l'intérieur de la clause over(). Je ne sais pas quel lâche a voté sa réponse sans énoncer sa (ses) raison (s). –

0

Vous pouvez utiliser une expression de table commune pour obtenir les 10 ID distincts haut de puis se joindre à ceux du reste de vos données:

;WITH TopTenIDs AS 
( 
    SELECT DISTINCT TOP 10 id 
    FROM dm.labs 
    ORDER BY ...... 
) 
SELECT 
    tti.id, pl.nm, pl.val, pl.txt_val 
FROM 
    TopTenIDs tti 
INNER JOIN 
    dm.labs pl ON pl.id = tti.id 
INNER JOIN 
    mas_data.patients p ON pl.id = p.id 
WHERE 
    pl.nm like '%LDL%' 
    AND val IS NOT NULL 

Cela devrait fonctionner. Rappelez-vous: si vous avez une clause "TOP x", vous avez généralement besoin d'une clause ORDER BY - si vous voulez le TOP 10, vous devez indiquer au système dans quel ordre "TOP" est. PS: pourquoi vous joignez-vous même à la table "patients", si vous ne sélectionnez jamais de champs?

2

Je sais que ce fil est vieux, mais je me suis dit que je mettrais dans ce qui est venu avec depuis que je viens de rencontrer ce même problème. Ce n'est peut-être pas efficace, mais je crois que le travail est fait.

SELECT TOP 10 p.id, pl.nm, pl.val, pl.txt_val 
INTO #yourTempTable 
from dm.labs pl 
join mas_data.patients p on pl.id = p.id 
where pl.nm like '%LDL%' and val is not null 

select p.id, pl.nm, pl.val, pl.txt_val 
from #yourTempTable 
where id IN (select distinct id from #yourTempTable) 
0
SELECT TOP 14 A, B, C 
    FROM MyDatabase 
    Where EXISTS 
    (
    Select Distinct[A] FROM MyDatabase 
    ) 
24
select top 10 p.id from(select distinct p.id from tablename)tablename 
+0

simple et élégant. Devrait être la réponse la plus votée. –

+0

Je ne pense pas que cela fonctionne, en tant que commandes distinctes ids ascendant –

0

C'est la bonne réponse et vous pouvez trouver 3 hauteurs valeur de la table

SELECT TOP(1) T.id FROM (SELECT DISTINCT TOP(3) st.id FROM Table1 AS t1 , Table2 AS t2 WHERE t1.id=t2.id ORDER BY (t2.id) DESC) T ORDER BY(T.id) ASC 
67

bien Try

SELECT distinct TOP 10 MyId FROM sometable 
+7

Ceci est la bonne réponse – Hans

+0

Cela fonctionne dans Sybase 12 ainsi –

+0

Juste dû les changer. Très agréable. –

1

Je ne l'aurais pas attendu ce , mais de Halim CHOISISSEZ TOP TOP 10 MyId FROM Table

est fonctionnellement identique à sélectionner Vaishnavi Kumar top 10 p.id de (sélectionner p.id distinct de nomdetable) tablename

create table #names ([name] varchar(10)) 
insert into #names ([name]) values ('jim') 
insert into #names ([name]) values ('jim') 
insert into #names ([name]) values ('bob') 
insert into #names ([name]) values ('mary') 
insert into #names ([name]) values ('bob') 
insert into #names ([name]) values ('mary') 
insert into #names ([name]) values ('john') 
insert into #names ([name]) values ('mark') 
insert into #names ([name]) values ('matthew') 
insert into #names ([name]) values ('luke') 
insert into #names ([name]) values ('peter') 

select distinct top 5 [name] from #names 

select top 5 * from (select distinct [name] from #names) subquery 

drop table #names 

produit les mêmes résultats pour les deux sélections:

name 
1 bob 
2 jim 
3 john 
4 luke 
5 mark 

il est curieux que select 5 top distinct ne soit pas valide, mais sélectionnez top 5 distinct est et fonctionne comme vous pourriez vous attendre sélectionnez top 5 distinct pour fonctionner.