2009-08-08 11 views
1

Désolé, je ne suis pas sûr de savoir comment exprimer cela et je ne suis pas très bon avec SQL. Le moteur de base de données SQL Server Compact. J'ai actuellement cette requête:SQL: Sélectionnez la valeur maximale pour chaque clé unique?

SELECT * 
FROM Samples 
WHERE FunctionId NOT IN 
(SELECT CalleeId FROM Callers) 
ORDER BY ThreadId, HitCount DESC 

Ce qui me donne:

ThreadId Function HitCount 
     1  164  6945 
     1  3817   1 
     4  1328  7053 

Maintenant, je veux seulement le résultat avec le nombre maximum atteint pour chaque valeur unique de fil. En d'autres termes, cette deuxième rangée devrait être supprimée. Je ne suis pas sûr de savoir comment l'enlever.

[EDIT] Si elle aide, ceci est une autre forme de la même requête:

SELECT * 
FROM Samples s1 
LEFT OUTER JOIN Callers c1 
    ON s1.ThreadId = c1.ThreadId AND s1.FunctionId = c1.CalleeId 
WHERE c1.ThreadId IS NULL 
ORDER BY ThreadId 

[EDIT] J'ai fini par faire des changements de schéma pour éviter de le faire, comme les questions proposées étaient à la recherche assez cher . Merci pour votre aide.

+0

Est-il possible qu'il y ait deux ThreadIds qui partagent la même functionId, avec le de ceux (ThreadId, FunctionId) dans les appelants, mais pas l'autre? Je demande, parce que les deux requêtes ci-dessus ne disent pas la même chose. –

Répondre

2

Est-ce que SQL Server compact prend en charge les fonctions fenêtrées?

Alternative 1 - Inclut toutes les lignes qui se nouent. Comprendra pas de ligne, si les seules lignes pour un fil donné ont tous null pour HitCount:

SELECT Thread, Function, HitCount 
FROM (SELECT Thread, Function, HitCount, 
     MAX(HitCount) over (PARTITION BY Thread) as MaxHitCount 
    FROM Samples 
    WHERE FunctionId NOT IN 
     (SELECT CalleeId FROM Callers)) t 
WHERE HitCount = MaxHitCount 
ORDER BY ThreadId, HitCount DESC 

Alternative 2 - comprendra toutes les lignes qui lient. S'il n'y a pas de ligne pour un fil donné avec HitCount non nul, retournera toutes les lignes pour ce thread:

SELECT Thread, Function, HitCount 
FROM (SELECT Thread, Function, HitCount, 
     RANK() over (PARTITION BY Thread ORDER BY HitCount DESC) as R 
    FROM Samples 
    WHERE FunctionId NOT IN 
     (SELECT CalleeId FROM Callers)) t 
WHERE R = 1 
ORDER BY ThreadId, HitCount DESC 

Alternative 3 - Est-ce que non-determistically choisir une ligne en cas de liens et jeter les autres. Comprendra une ligne si toutes les lignes pour un fil donné ont HitCount null

SELECT Thread, Function, HitCount 
FROM (SELECT Thread, Function, HitCount, 
     ROW_NUMBER() over (PARTITION BY Thread ORDER BY HitCount DESC) as R 
    FROM Samples 
    WHERE FunctionId NOT IN 
     (SELECT CalleeId FROM Callers)) t 
WHERE R = 1 
ORDER BY ThreadId, HitCount DESC 

Alternative 4 & 5 - Utilise des constructions plus anciennes, si les fonctions fenêtrées ne sont pas disponibles, et dit ce que l'on entend un peu plus propre que l'utilisation joint. Benchmark si Spead est une priorité. Les deux retournent toutes les lignes qui participent à une égalité. Alternative 4 sera HitCount est nul lorsque les valeurs non nulles ne sont pas disponibles pour HitCount. L'option 5 ne retournera pas de lignes avec HitCount est nulle.

SELECT * 
FROM Samples s1 
WHERE FunctionId NOT IN 
    (SELECT CalleeId FROM Callers) 
AND NOT EXISTS 
    (SELECT * 
    FROM Samples s2 
    WHERE s1.FunctionId = s2.FunctionId 
    AND s1.HitCount < s2.HitCount) 
ORDER BY ThreadId, HitCount DESC 

SELECT * 
FROM Samples s1 
WHERE FunctionId NOT IN 
    (SELECT CalleeId FROM Callers) 
AND HitCount = 
    (SELECT MAX(HitCount) 
    FROM Samples s2 
    WHERE s1.FunctionId = s2.FunctionId) 
ORDER BY ThreadId, HitCount DESC 
2

Voilà comment je le ferais:

SELECT s1.* 
FROM Samples s1 
LEFT JOIN Samples s2 
    ON (s1.Thread = s2.Thread and s1.HitCount < s2.HitCount) 
WHERE s1.FunctionId NOT IN (SELECT CalleeId FROM Callers) 
    AND s2.Thread IS NULL 
ORDER BY s1.ThreadId, s1.HitCount DESC 

En d'autres termes, la ligne s1 pour laquelle il n'y a pas d'autre ligne s2 correspondant à la même Thread et ayant une plus grande HitCount.

+0

Il y a une subtile méchanceté ici - la sous-clause imbriquée (SELECT CalleeId FROM Callers) doit aussi être appliquée à l'autre moitié de la jointure. J'ai restructuré un peu la requête initiale: SELECT s1.* à partir d'échantillons de LEFT OUTER JOIN Appelants c1 SUR s1.ThreadId = c1.ThreadId ET s1.FunctionId = c1.CalleeId OÙ c1.ThreadId IS NULL – Promit

1

travaillera en collaboration avec SQL Server 2005+:

WITH maxHits AS(
    SELECT s.threadid, 
     MAX(s.hitcount) 'maxhits' 
    FROM SAMPLES s 
    JOIN CALLERS c ON c.threadid = s.threadid AND c.calleeid != s.functionid 
GROUP BY s.threadid 
) 
SELECT t.* 
    FROM SAMPLES t 
    JOIN CALLERS c ON c.threadid = t.threadid AND c.calleeid != t.functionid 
    JOIN maxHits mh ON mh.threadid = t.threadid AND mh.maxhits = t.hitcount 

travail sur une base de données:

SELECT t.* 
    FROM SAMPLES t 
    JOIN CALLERS c ON c.threadid = t.threadid AND c.calleeid != t.functionid 
    JOIN (SELECT s.threadid, 
       MAX(s.hitcount) 'maxhits' 
      FROM SAMPLES s 
      JOIN CALLERS c ON c.threadid = s.threadid AND c.calleeid != s.functionid 
     GROUP BY s.threadid) mh ON mh.threadid = t.threadid AND mh.maxhits = t.hitcount 
+0

si (SELECT s.ThreadAID MAX (s.HitCount) DE ÉCHANTILLONS s GROUP BY s.ThreadId) renvoie un max qui n'appartient qu'aux lignes où FunctionId est dans Callers.CallerId? Ces lignes sont finalement supprimées, et le Max (HitCount) pour ce thread à partir d'une ligne avec FuctionId pas dans Callers.CallerId est exclu des résultats. –

+0

Bon point. Facilement corrigé en ajoutant JOIN à CALLERS dans la vue CTE ou en ligne - voir mise à jour. –

+0

@rexem. J'ai remarqué un autre problème: il n'y a rien dans l'OP qui m'amène à croire que Callers a une colonne ThreadId. –

Questions connexes