Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Berechnen Sie Mediane für mehrere Spalten in derselben Tabelle in einem Abfrageaufruf

So etwas ist in MySQL ein großes Ärgernis. Es ist ratsam, die kostenlose Oracle Express Edition oder postgreSQL zu verwenden, wenn Sie eine Menge dieser statistischen Ranking-Arbeit durchführen möchten. Sie alle haben MEDIAN(value) Aggregatfunktionen, die entweder integriert oder als Erweiterungen verfügbar sind. Hier ist ein kleines Sqlfiddle, das das demonstriert. http://sqlfiddle.com/#!4/53de8/6/0

Aber danach hast du nicht gefragt.

In MySQL ist Ihr grundlegendes Problem der Gültigkeitsbereich von Variablen wie @rownum. Sie haben auch ein Pivot-Problem:Das heißt, Sie müssen Zeilen Ihrer Abfrage in Spalten umwandeln.

Lassen Sie uns zuerst das Pivot-Problem angehen. Was Sie tun werden, ist eine Vereinigung mehrerer großer, fetter Abfragen zu erstellen. Zum Beispiel:

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

Hier sind also Ihre Ergebnisse in einer Tabelle mit Tag/Wert-Paaren. Sie können diese Tabelle so drehen, um eine Zeile mit einem Wert in jeder Spalte zu erhalten.

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

Auf diese Weise schwenken Sie Zeilen (in diesem Fall aus der UNION-Abfrage) in Spalten. Hier ist ein Tutorial zum Thema. http://www.artfulsoftware.com/infotree/qrytip.php?id =523

Jetzt müssen wir uns mit den Unterabfragen zur Berechnung des Medians befassen. Der Code in Ihrer Frage sieht ziemlich gut aus. Ich habe Ihre Daten nicht, daher kann ich sie nur schwer auswerten.

Sie müssen jedoch vermeiden, die @rownum-Variable wiederzuverwenden. Nennen Sie es @rownum1 in einer Ihrer Abfragen, @rownum2 in der nächsten und so weiter. Hier ist eine kleine SQL-Geige, die nur eines davon macht. http://sqlfiddle.com/#!2/2f770/1/0

Jetzt bauen wir es ein wenig auf und machen zwei verschiedene Mediane. Hier ist die Geige http://sqlfiddle.com/#!2/2f770/2/ 0 und hier ist die UNION-Abfrage. Hinweis die zweite Hälfte der Union-Abfrage verwendet @rownum2 statt @rownum .

Schließlich ist hier die vollständige Abfrage mit der Pivotisierung. 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

Das sind nur zwei Mediane. Du brauchst fünf. Ich denke, es ist einfach zu argumentieren, dass diese Medianberechnung in MySQL in einer einzigen Abfrage absurd schwierig ist.