Como encontro o valor mediano de uma coluna no MySQL?

10

Só posso imaginar fazer isso com duas consultas ao banco de dados. O primeiro encontra o número de linhas no banco de dados e o segundo seleciona com um ORDER BYna coluna em que estou interessado e LIMIT X, 1onde X é metade do número de linhas.

Existe uma maneira simples de fazer isso com apenas uma consulta?

No momento, estou usando médias em meus cálculos, mas acho que a média seria melhor; não há limite superior para os valores e eles são limitados de baixo por 0.


EDIT: sim, eu quis dizer 'mediana', mas estava tendo algum erro cerebral e procurei por 'média'. Agora encontrei a resposta em stackoverflow

JIStone
fonte
Depois de ler metaum pouco, parece que há uma divisão quanto ao clima. Essa pergunta deve estar aqui ou no SO. Reconheço que essa pode não ser uma consulta no nível ninja , mas fiquei perplexo e não há DBA na empresa em que trabalho (6 pessoas no total).
JIStone

Respostas:

6

Há muita discussão aqui sobre o cálculo de valores medianos de uma tabela MySQL. Basta pesquisar na página por 'mediana'.

Como um aparte, parece-me negligente que não haja função interna para fazer isso. A mediana é geralmente mais descritiva da tendência central do que a média. O Access / VBA tem o mesmo buraco em sua lista de funções.

Snubian
fonte
Concordo. Quando trabalhadas em uma consulta grande, as linhas extras tornam a coisa toda mais complicada e difícil de depurar / manter.
JIStone #
2

Não vi uma solução em nenhum lugar que consiga obter a mediana em uma única consulta. Não me importo com tabelas temporárias, mas se não forem necessárias, ótimo! Aqui está o que eu vim com:

SELECT AVG(profit) median, nofitems FROM(
  SELECT x.profit, SUM(SIGN(1.0-SIGN(y.profit-x.profit))) diff, count(*) nofitems, floor(count(*)+1/2)
  FROM brand_prof x, brand_prof y
  GROUP BY x.profit
  HAVING SUM(SIGN(1.0-SIGN(y.profit-x.profit))) = floor((COUNT(*)+1)/2)
      OR SUM(SIGN(1.0-SIGN(y.profit-x.profit))) = ceiling((COUNT(*)+1)/2)
) x;

Testei isso para um conjunto uniforme e obtive a resposta certa. brand_prof é apenas duas colunas: brand_name e profit, um valor decimal. Se esses valores forem inteiros, talvez seja necessário converter "teto ((CAST COUNT (*) AS DECIMAL) ...") Mais do que eu testei. A idéia interessante de usar um produto cartesiano e relacionar a soma dos sinais foi não o meu, esqueci o autor, infelizmente.

Jeff Humphreys
fonte