Mysql
 sql >> Database >  >> RDS >> Mysql

Calcola le mediane per più colonne nella stessa tabella in una chiamata di query

Questo genere di cose è un grande dolore al collo in MySQL. Potrebbe essere saggio utilizzare Oracle Express Edition o postgreSQL gratuiti se hai intenzione di fare un sacco di questo lavoro di classificazione statistica. Hanno tutti MEDIAN(value) funzioni aggregate che sono integrate o disponibili come estensioni. Ecco un piccolo sqlfiddle che lo dimostra. http://sqlfiddle.com/#!4/53de8/6/0

Ma non me l'hai chiesto.

In MySQL, il tuo problema di base è l'ambito di variabili come @rownum. Hai anche un problema di rotazione:devi trasformare le righe della tua query in colonne.

Affrontiamo prima il problema del pivot. Quello che farai è creare un'unione di diverse query big fat. Ad esempio:

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

Quindi ecco i tuoi risultati in una tabella di coppie tag / valore. Puoi ruotare la tabella in questo modo, per ottenere una riga con un valore in ogni colonna.

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

È così che si spostano le righe (dalla query UNION in questo caso) alle colonne. Ecco un tutorial sull'argomento. http://www.artfulsoftware.com/infotree/qrytip.php?id =523

Ora dobbiamo affrontare le sottoquery di calcolo della mediana. Il codice nella tua domanda sembra abbastanza buono. Non ho i tuoi dati, quindi è difficile per me valutarli.

Ma devi evitare di riutilizzare la variabile @rownum. Chiamalo @rownum1 in una delle tue query, @rownum2 in quella successiva e così via. Ecco un piccolo violino sql che fa solo uno di questi. http://sqlfiddle.com/#!2/2f770/1/0

Ora costruiamolo un po', facendo due mediane diverse. Ecco il violino http://sqlfiddle.com/#!2/2f770/2/ 0 ed ecco la query UNION. Avviso la seconda metà della query di unione utilizza @rownum2 invece di @rownum .

Infine, ecco la query completa con il pivot. 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

Queste sono solo due mediane. Ne servono cinque. Penso che sia facile sostenere che questo calcolo mediano sia assurdamente difficile da eseguire in MySQL in una singola query.