2011-04-06 4 views
1

En donnant un exemple de table 'Users', qui a une colonne int nommée 'UserID' (et un nombre arbitraire d'autres colonnes), quelle est la meilleure façon de sélectionner toutes les lignes apparaît plus d'une fois?Tsql, retournant des lignes avec des valeurs de colonnes identiques

Jusqu'à présent, je suis venu avec

select * from Users where UserID in 
(select UserID from Users group by UserID having COUNT(UserID) > 1) 

Cela semble tout à fait un moyen innefficient de le faire bien, est-il une meilleure façon?

+2

Dans quel sens inefficace? Avez-vous des millions d'utilisateurs ou quoi? Je pense que votre requête est très bien; Si vous avez des milions de lignes, alors bien sûr, UserID doit être indexé pour ce type de requête. – Arvo

+0

Je pense intuitivement qu'il doit y avoir un moyen de le faire sans utiliser de sous-requête. Bien sûr, je pourrais me tromper totalement. – John

+5

Plus précisément: pourquoi l'ID utilisateur apparaîtrait-il plus d'une fois dans une table Utilisateurs? –

Répondre

2

Dans SQL Server 2005+ vous pouvez utiliser cette approche:

;WITH UsersNumbered AS (
    SELECT 
    UserID, 
    rownum = ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY UserID) 
    FROM Users 
) 
SELECT u.* 
FROM Users u 
    INNER JOIN UsersNumbered n ON u.UserID = n.UserID AND n.rownum = 2 

sous réserve qu'il existe un index non cluster sur UserID, on obtient un plan d'exécution légèrement pire que votre approche. Pour mieux (en fait, même que le vôtre), vous aurez besoin d'utiliser ... une sous-requête, il peut sembler cependant contre-intuitif:

;WITH UsersNumbered AS (
    SELECT 
    UserID, 
    rownum = ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY UserID) 
    FROM Users 
) 
SELECT u.* 
FROM Users u 
WHERE EXISTS (
    SELECT * 
    FROM UsersNumbered n 
    WHERE u.UserID = n.UserID AND n.rownum = 2 
); 

Dans le cas d'un index ordonné en clusters sur UserID les trois solutions donne le même plan.

0

Cela ferait la même chose mais évaluer la performance et il serait probablement plus rapide/plus efficace. Bien sûr, il devrait y avoir un index sur cette colonne UserID.

select u.* 
from Users u 
join (select UserID,count(UserID) as CUserID from Users group by UserID) u1 on u1.UserID = u.UserID 
where CUserID > 1 
Questions connexes