2
votes

SQL filtre les lignes avec une valeur de cellule en double

J'ai une grosse requête qui renvoie des lignes où l'une des colonnes a des valeurs dupliquées, par exemple:

CREATE TABLE #temp (SysId VARCHAR(10), col1 INT);
INSERT INTO #temp VALUES ('A', 1), ('B', 1), ('A', 1);

WITH cte AS (
   SELECT * FROM #temp
), sysids AS (
   SELECT SysId FROM #temp GROUP BY Sysid HAVING COUNT(*) = 1
)
SELECT * FROM #temp WHERE EXISTS (SELECT SysId FROM sysids);

DROP TABLE #temp;

sysid est la colonne que je veux filtrer par, donc dans l'exemple ci-dessus, je ne veux que la dernière ligne de sortie car A apparaît plus d'une fois. J'ai essayé de le faire pour les filtrer:

| sysid | col1 | col2
| A     |  1   |  2
| A     |  2   |  3
| B     |  1   |  4

Je m'attendais à ce que la sélection finale contienne uniquement la ligne B, dans l'exemple ci-dessus. Cependant, je les reçois toujours tous, et je ne comprends pas pourquoi.

De toute évidence, dans cet exemple spécifique, je n'ai pas besoin de la partie cte mais ma vraie requête est assez complexe avec plusieurs unions.


1 commentaires

Le problème est que vous ne reliez pas le existe à la requête externe (comme where sysids.sysid = # temp.sysid ). Tel qu'il est actuellement écrit, au moins un sysid existe dans sysids , donc la clause where est vraie pour chaque ligne. La requête telle qu'elle est écrite n'est pas différente de, disons, où existe (sélectionnez object_id dans sys.objects) car elle n'a aucune relation avec la requête externe.


3 Réponses :


2
votes

Vous pouvez utiliser une sous-requête agrégée corrélée et NOT EXISTS .

SELECT t1.*
       FROM #temp t1
       WHERE NOT EXISTS (SELECT ''
                                FROM #temp t2
                                WHERE t2.sysid = t1.sysid
                                HAVING count(*) > 1);


2 commentaires

Oh, approche intéressante. J'avais pensé à utiliser un NOT IN. Est-ce que le NON EXISTANT devrait-il être plus performant ou dépend-il du volume?


@Ben: Avec un index sur sysid , je pourrais imaginer que cela soit assez efficace. Au moins, ça vaut le coup d'essayer.



0
votes
CREATE TABLE #temp (SysId VARCHAR(10), col1 INT);
INSERT INTO #temp VALUES ('A', 1), ('B', 1), ('A', 1);

WITH cte AS (
   SELECT * FROM #temp
), sysids AS (
   SELECT SysId FROM #temp GROUP BY Sysid HAVING COUNT(SysId) =1
   )
SELECT * FROM #temp WHERE SysId IN (SELECT SysId FROM sysids);

DROP TABLE #temp;

0 commentaires

1
votes

Veuillez essayer ceci:

;WITH cte AS (
    SELECT t.SysId,t.col1,COUNT(1)OVER(PARTITION BY t.SysID) AS [cnt] 
    FROM #temp t
) 
SELECT c.SysId,c.col1
FROM cte c WHERE c.cnt = 1;


0 commentaires