Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Calcular medianas para várias colunas na mesma tabela em uma chamada de consulta


Esse tipo de coisa é uma grande dor de cabeça no MySQL. Você pode ser sábio em usar o Oracle Express Edition gratuito ou o postgreSQL se for fazer uma grande quantidade desse trabalho de classificação estatística. Todos eles têm MEDIAN(value) funções agregadas que são internas ou disponíveis como extensões. Aqui está um pequeno sqlfiddle demonstrando isso. http://sqlfiddle.com/#!4/53de8/6/0

Mas você não perguntou sobre isso.

No MySQL, seu problema básico é o escopo de variáveis ​​como @rownum. Você também tem um problema de pivô:ou seja, você precisa transformar as linhas de sua consulta em colunas.

Vamos resolver o problema do pivô primeiro. O que você vai fazer é criar uma união de várias consultas grandes e gordas. Por exemplo:
SELECT 'median_wages' AS tag, wages AS value
  FROM (big fat query making median wages) A
 UNION
SELECT 'median_volunteer_hours' AS tag, hours AS value
  FROM (big fat query making median volunteer hours) B
 UNION
SELECT 'median_solvent_days' AS tag, days AS value
  FROM (big fat query making median solvency days) C

Então, aqui estão seus resultados em uma tabela de pares de tag/valor. Você pode dinamizar essa tabela assim, para obter uma linha com um valor em cada coluna.
SELECT SUM( CASE tag WHEN 'median_wages' THEN value ELSE 0 END 
          ) AS median_wages, 
SELECT SUM( CASE tag WHEN 'median_volunteer_hours' THEN value ELSE 0 END
          ) AS median_volunteer_hours, 
SELECT SUM( CASE tag WHEN 'median_solvent_days' THEN value ELSE 0 END 
          ) AS median_solvent_days
FROM (
    /* the above gigantic UNION query */
 ) Q

É assim que você move as linhas (da consulta UNION neste caso) para as colunas. Segue um tutorial sobre o tema. http://www.artfulsoftware.com/infotree/qrytip.php?id =523

Agora precisamos lidar com as subconsultas de computação mediana. O código em sua pergunta parece muito bom. Eu não tenho seus dados, então é difícil para mim avaliá-los.

Mas você precisa evitar reutilizar a variável @rownum. Chame de @rownum1 em uma de suas consultas, @rownum2 na próxima e assim por diante. Aqui está um violino sql dinky fazendo apenas um desses. http://sqlfiddle.com/#!2/2f770/1/0

Agora vamos construir um pouco, fazendo duas medianas diferentes. Aqui está o violino http://sqlfiddle.com/#!2/2f770/2/ 0 e aqui está a consulta UNION. Aviso a segunda metade da consulta união usa @rownum2 em vez de @rownum .

Finalmente, aqui está a consulta completa com o pivoting. http://sqlfiddle.com/#!2/2f770/13/0
 SELECT SUM( CASE tag WHEN 'Boston' THEN value ELSE 0 END ) AS Boston,
           SUM( CASE tag WHEN 'Bronx' THEN value ELSE 0 END ) AS Bronx   
   FROM (
 SELECT 'Boston' AS tag, pop AS VALUE
  FROM (
        SELECT @rownum := @rownum +1 AS  `row_number` , pop
          FROM pops, 
        (SELECT @rownum :=0)r
          WHERE pop >0 AND city = 'Boston'
          ORDER BY pop
        ) AS ordered_rows, 
        ( 
         SELECT COUNT( * ) AS total_rows
           FROM pops
          WHERE pop >0 AND city = 'Boston'
        ) AS rowcount
  WHERE ordered_rows.row_number = FLOOR( total_rows /2 ) +1
  UNION ALL
 SELECT 'Bronx' AS tag, pop AS VALUE
  FROM (
        SELECT @rownum2 := @rownum2 +1 AS  `row_number` , pop
          FROM pops, 
        (SELECT @rownum2 :=0)r
          WHERE pop >0 AND city = 'Bronx'
          ORDER BY pop
        ) AS ordered_rows, 
        ( 
         SELECT COUNT( * ) AS total_rows
           FROM pops
          WHERE pop >0 AND city = 'Bronx'
        ) AS rowcount
  WHERE ordered_rows.row_number = FLOOR( total_rows /2 ) +1
) D

Isso é apenas duas medianas. Você precisa de cinco. Eu acho que é fácil argumentar que essa computação mediana é absurdamente difícil de fazer no MySQL em uma única consulta.