sql >> Databasteknik >  >> RDS >> Mysql

Beräkna medianer för flera kolumner i samma tabell i ett frågeanrop

Sånt här är en stor smärta i nacken i MySQL. Du kan göra klokt i att använda den kostnadsfria Oracle Express Edition eller postgreSQL om du ska göra tonnage av detta statistiska rankningsarbete. De har alla MEDIAN(value) samla funktioner som antingen är inbyggda eller tillgängliga som tillägg. Här är en liten sqlfiddle som visar det. http://sqlfiddle.com/#!4/53de8/6/0

Men du frågade inte om det.

I MySQL är ditt grundläggande problem omfattningen av variabler som @rownum. Du har också ett vridningsproblem:det vill säga du måste omvandla rader i din fråga till kolumner.

Låt oss ta itu med pivotproblemet först. Vad du ska göra är att skapa en förening av flera stora feta frågor. Till exempel:

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

Så här är dina resultat i en tabell med tagg-/värdepar. Du kan pivotera den tabellen så, för att få en rad med ett värde i varje kolumn.

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

Det är så du pivoterar upp rader (från UNION-frågan i det här fallet) till kolumner. Här är en handledning om ämnet. http://www.artfulsoftware.com/infotree/qrytip.php?id =523

Nu måste vi ta itu med medianberäkningsunderfrågorna. Koden i din fråga ser ganska bra ut. Jag har inte dina uppgifter så det är svårt för mig att utvärdera det.

Men du måste undvika att återanvända @rownum-variabeln. Kalla det @rownum1 i en av dina frågor, @rownum2 i nästa, och så vidare. Här är en dinky sql-fiol som bara gör en av dessa. http://sqlfiddle.com/#!2/2f770/1/0

Låt oss nu bygga upp det lite och göra två olika medianer. Här är fiolen http://sqlfiddle.com/#!2/2f770/2/ 0 och här är UNION-frågan. Meddelande den andra halvan av unionsfrågan använder @rownum2 istället för @rownum .

Slutligen, här är hela frågan med pivotering. 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

Detta är bara två medianer. Du behöver fem. Jag tror att det är lätt att hävda att denna medianberäkning är absurt svår att göra i MySQL i en enda fråga.



  1. Returnera alla användare, även de som inte uppfyller mina kriterier

  2. Minimal loggning med INSERT...SELECT och snabbladdningskontext

  3. villkorlig gå med i mysql

  4. Mönstermatchning:Roligare när jag var barn