sql >> Base de Datos >  >> RDS >> Mysql

Calcule las medianas para varias columnas en la misma tabla en una llamada de consulta

Este tipo de cosas es un gran dolor en el cuello en MySQL. Puede que sea prudente utilizar Oracle Express Edition o postgreSQL gratis si va a hacer mucho de este trabajo de clasificación estadística. Todos tienen MEDIAN(value) funciones agregadas que están integradas o disponibles como extensiones. Aquí hay un pequeño sqlfiddle que demuestra eso. http://sqlfiddle.com/#!4/53de8/6/0

Pero no preguntaste sobre eso.

En MySQL, su problema básico es el alcance de variables como @rownum. También tiene un problema de rotación:es decir, debe convertir las filas de su consulta en columnas.

Abordemos primero el problema del pivote. Lo que vas a hacer es crear una unión de varias consultas grandes y gordas. Por ejemplo:

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

Así que aquí están sus resultados en una tabla de pares de etiquetas/valores. Puede girar esa tabla así para obtener una fila con un valor en cada columna.

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

Así es como pivota las filas (desde la consulta UNION en este caso) a las columnas. Aquí hay un tutorial sobre el tema. http://www.artfulsoftware.com/infotree/qrytip.php?id =523

Ahora tenemos que abordar las subconsultas de cálculo de la mediana. El código en tu pregunta se ve bastante bien. No tengo sus datos, por lo que me resulta difícil evaluarlos.

Pero debe evitar reutilizar la variable @rownum. Llámelo @rownum1 en una de sus consultas, @rownum2 en la siguiente, y así sucesivamente. Aquí hay un pequeño violín sql haciendo solo uno de estos. http://sqlfiddle.com/#!2/2f770/1/0

Ahora construyamos un poco, haciendo dos medianas diferentes. Aquí está el violín http://sqlfiddle.com/#!2/2f770/2/ 0 y aquí está la consulta UNION. Aviso la segunda mitad de la consulta de unión usa @rownum2 en lugar de @rownum .

Finalmente, aquí está la consulta completa con el pivote. 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

Esto es sólo dos medianas. Necesitas cinco. Creo que es fácil argumentar que este cálculo medio es absurdamente difícil de hacer en MySQL en una sola consulta.