SQL: выбрать максимальное значение для каждого уникального ключа? - PullRequest
1 голос
/ 08 августа 2009

Извините, я не уверен, как это сформулировать, и я действительно не очень хорошо разбираюсь в SQL. ДБ двигатель я SQL Server Compact. В настоящее время у меня есть этот запрос:

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

Что дает мне:

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

Теперь мне нужен только результат с максимальным количеством совпадений для каждого уникального значения Thread. Другими словами, этот второй ряд должен быть удален. Я не уверен, как это осуществить.

[EDIT] Если это помогает, это альтернативная форма того же запроса:

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] Я закончил вносить изменения в схему, чтобы избежать этого, поскольку предложенные запросы выглядели довольно дорогими. Спасибо за помощь.

Ответы [ 3 ]

2 голосов
/ 08 августа 2009

SQL Server Compact поддерживает оконные функции?

Альтернатива 1 - будет включать все связывающие строки. Не будет включать строку, если все строки данного потока имеют значение null для 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

Альтернатива 2 - будет включать все связывающие строки. Если для данного потока с ненулевым значением HitCount нет строки, будут возвращены все строки для этого потока:

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

Альтернатива 3 - будет недетерминистически выбирать один ряд в случае связей и отбрасывать другие. Будет включать строку, если все строки для данного потока имеют нулевое значение HitCount

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

Альтернатива 4 и 5 - использует более старые конструкции, если оконные функции недоступны, и говорит, что подразумевается немного чище, чем использование объединений. Ориентир, если спид является приоритетом. Оба возвращают все строки, которые участвуют в ничьей. В альтернативе 4 HitCount будет нулевым, если ненулевые значения недоступны для HitCount. Альтернатива 5 не будет возвращать строки с HitCount, равным нулю.

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 голосов
/ 08 августа 2009

Вот как бы я это сделал:

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

Другими словами, строка s1, для которой нет другой строки s2, совпадающей с тем же Thread и имеющей большее значение HitCount.

1 голос
/ 08 августа 2009

Будет работать с 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

Работа с любой базой данных:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...