De acordo com o MSDN , a Mediana não está disponível como uma função agregada no Transact-SQL. No entanto, gostaria de descobrir se é possível criar essa funcionalidade (usando a função Criar Agregado , função definida pelo usuário ou algum outro método).
Qual seria a melhor maneira (se possível) de fazer isso - permitir o cálculo de um valor mediano (assumindo um tipo de dados numérico) em uma consulta agregada?
sql
sql-server
aggregate-functions
median
Yaakov Ellis
fonte
fonte
Respostas:
ATUALIZAÇÃO 2019: Nos 10 anos desde que escrevi esta resposta, foram descobertas mais soluções que podem produzir melhores resultados. Além disso, as versões do SQL Server desde então (especialmente o SQL 2012) introduziram novos recursos do T-SQL que podem ser usados para calcular medianas. As versões do SQL Server também aprimoraram seu otimizador de consultas, que pode afetar o desempenho de várias soluções medianas. Net-net, minha postagem original de 2009 ainda está OK, mas pode haver soluções melhores para os aplicativos modernos do SQL Server. Dê uma olhada neste artigo de 2012, que é um ótimo recurso: https://sqlperformance.com/2012/08/t-sql-queries/median
Este artigo considerou o seguinte padrão muito, muito mais rápido que todas as outras alternativas, pelo menos no esquema simples que eles testaram. Esta solução foi 373x mais rápida (!!!) que a
PERCENTILE_CONT
solução mais lenta ( ) testada. Observe que esse truque requer duas consultas separadas, que podem não ser práticas em todos os casos. Também requer o SQL 2012 ou posterior.Obviamente, apenas porque um teste em um esquema em 2012 produziu ótimos resultados, sua milhagem pode variar, especialmente se você estiver no SQL Server 2014 ou posterior. Se o perf for importante para o cálculo da mediana, sugiro que você teste e faça o teste de várias das opções recomendadas nesse artigo para garantir que você encontrou o melhor para o seu esquema.
Eu também teria um cuidado especial ao usar a função (nova no SQL Server 2012)
PERCENTILE_CONT
recomendada em uma das outras respostas a esta pergunta, porque o artigo vinculado acima considerou essa função interna 373x mais lenta que a solução mais rápida. É possível que essa disparidade tenha melhorado nos 7 anos desde então, mas pessoalmente eu não usaria essa função em uma tabela grande até verificar seu desempenho em relação a outras soluções.O POST ORIGINAL DE 2009 ESTÁ ABAIXO:
Existem várias maneiras de fazer isso, com desempenho dramaticamente variável. Aqui está uma solução particularmente otimizada, de medianas, ROW_NUMBERs e desempenho . Essa é uma solução particularmente ideal quando se trata de E / Ss reais geradas durante a execução - ela parece mais cara que outras soluções, mas na verdade é muito mais rápida.
Essa página também contém uma discussão de outras soluções e detalhes de testes de desempenho. Observe o uso de uma coluna exclusiva como um desambiguador, caso haja várias linhas com o mesmo valor da coluna mediana.
Como em todos os cenários de desempenho do banco de dados, sempre tente testar uma solução com dados reais em hardware real - você nunca sabe quando uma alteração no otimizador do SQL Server ou uma peculiaridade em seu ambiente tornará uma solução normalmente mais rápida.
fonte
Se você estiver usando o SQL 2005 ou melhor, esse é um cálculo mediano simples e agradável para uma única coluna em uma tabela:
fonte
select gid, median(score) from T group by gid
. Você precisa de uma subconsulta correlacionada para isso?No SQL Server 2012, você deve usar PERCENTILE_CONT :
Consulte também: http://blog.sqlauthority.com/2011/11/20/sql-server-introduction-to-percentile_cont-analytic-functions-introduced-in-sql-server-2012/
fonte
DISTINCT
ouGROUPY BY SalesOrderID
? Caso contrário, você terá muitas linhas duplicadas.PERCENTILE_DISC
Minha resposta rápida original foi:
Isso lhe dará o alcance mediano e interquartil de uma só vez. Se você realmente deseja apenas uma linha com a mediana, remova o comentário da cláusula where.
Quando você coloca isso em um plano de explicação, 60% do trabalho está classificando os dados que são inevitáveis ao calcular estatísticas dependentes da posição como esta.
Alterei a resposta para seguir a excelente sugestão de Robert Ševčík-Robajz nos comentários abaixo:
Isso deve calcular os valores corretos da mediana e do percentil quando você possui um número par de itens de dados. Novamente, remova o comentário da cláusula where where se você deseja apenas a distribuição mediana e não toda a porcentagem.
fonte
Melhor ainda:
Do próprio mestre, Itzik Ben-Gan !
fonte
O MS SQL Server 2012 (e posterior) possui a função PERCENTILE_DISC que calcula um percentil específico para valores classificados. PERCENTILE_DISC (0.5) calculará a mediana - https://msdn.microsoft.com/en-us/library/hh231327.aspx
fonte
Simples, rápido, preciso
fonte
Se você deseja usar a função Criar Agregado no SQL Server, é assim que se faz. Fazer dessa maneira tem o benefício de poder escrever consultas limpas. Observe que esse processo pode ser adaptado para calcular um valor percentual com bastante facilidade.
Crie um novo projeto do Visual Studio e defina a estrutura de destino como .NET 3.5 (isso é para o SQL 2008, pode ser diferente no SQL 2012). Em seguida, crie um arquivo de classe e insira o seguinte código ou equivalente em c #:
Em seguida, compile-o e copie o arquivo DLL e PDB para sua máquina SQL Server e execute o seguinte comando no SQL Server:
Em seguida, você pode escrever uma consulta para calcular a mediana assim: SELECT dbo.Median (Field) FROM Table
fonte
Acabei de encontrar esta página enquanto procurava uma solução baseada em conjunto para mediana. Depois de analisar algumas das soluções aqui, criei o seguinte. A esperança é ajuda / funciona.
fonte
A consulta a seguir retorna a mediana de uma lista de valores em uma coluna. Ele não pode ser usado como ou em conjunto com uma função agregada, mas você ainda pode usá-lo como uma subconsulta com uma cláusula WHERE na seleção interna.
SQL Server 2005 ou superior:
fonte
Embora a solução de Justin Grant pareça sólida, descobri que, quando você tem um número de valores duplicados em uma determinada chave de partição, os números de linha dos valores duplicados ASC terminam fora de sequência, para que não se alinhem adequadamente.
Aqui está um fragmento do meu resultado:
Eu usei o código de Justin como base para esta solução. Embora não seja tão eficiente, devido ao uso de várias tabelas derivadas, ele resolve o problema de ordenação de linhas que encontrei. Quaisquer melhorias seriam bem-vindas, pois não sou tão experiente em T-SQL.
fonte
O exemplo de Justin acima é muito bom. Mas essa necessidade da chave primária deve ser declarada com muita clareza. Eu vi esse código na natureza sem a chave e os resultados são ruins.
A reclamação que recebo sobre o Percentile_Cont é que ele não fornece um valor real do conjunto de dados. Para chegar a uma "mediana" que é um valor real do conjunto de dados, use Percentile_Disc.
fonte
Em um UDF, escreva:
fonte
Constatação Mediana
Este é o método mais simples para encontrar a mediana de um atributo.
fonte
Veja outras soluções para cálculo de mediana no SQL aqui: " Maneira simples de calcular mediana com MySQL " (as soluções são na maioria independentes do fornecedor).
fonte
Para uma variável contínua / medida 'col1' de 'tabela1'
fonte
Usando o COUNT agregado, você pode primeiro contar quantas linhas existem e armazenar em uma variável chamada @cnt. Em seguida, você pode calcular parâmetros para o filtro OFFSET-FETCH para especificar, com base na ordem de quantidade, quantas linhas ignorar (valor de deslocamento) e quantas filtrar (valor de busca).
O número de linhas a serem ignoradas é (@cnt - 1) / 2. É claro que, para uma contagem ímpar, esse cálculo está correto porque você subtrai 1 pelo valor médio único antes de dividir por 2.
Isso também funciona corretamente para uma contagem par porque a divisão usada na expressão é divisão inteira; portanto, ao subtrair 1 de uma contagem par, você fica com um valor ímpar.
Ao dividir esse valor ímpar por 2, a parte da fração do resultado (0,5) é truncada. O número de linhas a serem buscadas é 2 - (@cnt% 2). A idéia é que, quando a contagem for ímpar, o resultado da operação do módulo for 1 e você precisará buscar 1 linha. Quando a contagem é uniforme, o resultado da operação do módulo é 0 e você precisa buscar 2 linhas. Subtraindo o resultado 1 ou 0 da operação do módulo de 2, você obtém o 1 ou 2 desejado, respectivamente. Por fim, para calcular a quantidade mediana, pegue uma ou duas quantidades de resultado e aplique uma média após converter o valor inteiro de entrada em um numérico da seguinte maneira:
fonte
Eu queria encontrar uma solução sozinho, mas meu cérebro tropeçou e caiu no caminho. Eu acho que funciona, mas não me peça para explicar de manhã. : P
fonte
fonte
Isso funciona com o SQL 2000:
fonte
Para iniciantes como eu, que estamos aprendendo o básico, eu pessoalmente acho esse exemplo mais fácil de seguir, pois é mais fácil entender exatamente o que está acontecendo e de onde vêm os valores medianos ...
No espanto absoluto de alguns dos códigos acima embora !!!
fonte
Esta é uma resposta tão simples quanto eu poderia sugerir. Funcionou bem com meus dados. Se você deseja excluir determinados valores, adicione uma cláusula where à seleção interna.
fonte
A seguinte solução funciona com essas premissas:
Código:
fonte
fonte
Eu tento com várias alternativas, mas como meus registros de dados têm valores repetidos, as versões ROW_NUMBER parecem não ser uma opção para mim. Então aqui a consulta que eu usei (uma versão com NTILE):
fonte
Com base na resposta de Jeff Atwood acima, aqui está o GROUP BY e uma subconsulta correlacionada para obter a mediana de cada grupo.
fonte
Freqüentemente, talvez seja necessário calcular a mediana não apenas para toda a tabela, mas para agregados com relação a algum ID. Em outras palavras, calcule a mediana para cada ID em nossa tabela, onde cada ID possui muitos registros. (baseado na solução editada por @gdoron: bom desempenho e funciona em muitos SQL)
Espero que ajude.
fonte
Para sua pergunta, Jeff Atwood já havia dado a solução simples e eficaz. Mas, se você estiver procurando alguma abordagem alternativa para calcular a mediana, o código SQL abaixo o ajudará.
Se você deseja calcular a mediana no MySQL, este link do github será útil.
fonte
Esta é a solução mais ideal para encontrar medianas que eu possa pensar. Os nomes no exemplo são baseados no exemplo de Justin. Verifique se existe um índice para a tabela Sales.SalesOrderHeader com as colunas de índice CustomerId e TotalDue nessa ordem.
ATUALIZAR
Eu estava um pouco inseguro sobre qual método tem melhor desempenho, então fiz uma comparação entre meu método Justin Grants e Jeff Atwoods executando a consulta com base nos três métodos em um lote e o custo do lote de cada consulta:
Sem índice:
E com índice
Tentei ver quão bem as consultas são dimensionadas se você tiver um índice criando mais dados a partir de 14.000 linhas por um fator de 2 a 512, o que significa, no final, cerca de 7,2 milhões de linhas. Nota: Certifiquei-me de que o campo CustomeId fosse único para cada vez que fiz uma única cópia; portanto, a proporção de linhas comparada à instância exclusiva do CustomerId era mantida constante. Enquanto fazia isso, executei execuções onde reconstruí o índice posteriormente e notei que os resultados se estabilizaram em torno de um fator de 128 com os dados que eu tinha para esses valores:
Perguntei-me como o desempenho poderia ter sido afetado pelo escalonamento do número de linhas, mas mantendo constante CustomerId exclusivo, então configurei um novo teste no qual fiz exatamente isso. Agora, em vez de estabilizar, a taxa de custo do lote continuou divergindo, também em vez de cerca de 20 linhas por CustomerId por média que eu tinha no final em torno de 10.000 linhas por esse ID exclusivo. Os números em que:
Assegurei-me de implementar cada método corretamente, comparando os resultados. Minha conclusão é que o método que usei geralmente é mais rápido, desde que o índice exista. Observe também que este método é o recomendado para este problema específico neste artigo https://www.microsoftpressstore.com/articles/article.aspx?p=2314819&seqNum=5
Uma maneira de melhorar ainda mais o desempenho das chamadas subseqüentes a essa consulta é persistir as informações de contagem em uma tabela auxiliar. Você pode até mantê-lo com um gatilho que atualiza e mantém informações sobre a contagem de linhas SalesOrderHeader dependentes do CustomerId, é claro que você também pode armazenar a mediana também.
fonte
Para conjuntos de dados em grande escala, você pode tentar este GIST:
https://gist.github.com/chrisknoll/1b38761ce8c5016ec5b2
Ele funciona agregando os valores distintos que você encontraria em seu conjunto (como idade, ano de nascimento etc.) e usa as funções da janela SQL para localizar qualquer posição de percentil que você especificar na consulta.
fonte