DB2 SQL - медиана с GROUP BY - PullRequest
       25

DB2 SQL - медиана с GROUP BY

0 голосов
/ 08 августа 2009

Прежде всего, я работаю на DB2 для i5 / OS V5R4. У меня есть ROW_NUMBER (), RANK () и общие табличные выражения. У меня нет TOP_ PERCENT или LIMIT OFFSET.

Фактический набор данных, с которым я работаю, трудно объяснить, поэтому давайте просто скажем, что у меня есть таблица истории погоды, столбцы которой (city, temperature, timestamp). Я хочу сравнить медианы со средними значениями для каждой группы (city).

Это был самый чистый способ получения медианы для всей таблицы. Я адаптировал его из IBM Redbook здесь :

WITH base_t AS
( SELECT temp, row_number() over (order by temperature) AS rownum FROM t ),
count_t AS
( SELECT COUNT(temperature) + 1 AS base_count FROM base_t ),
median_t AS
( SELECT temperature FROM base_t, count_t
  WHERE rownum in (FLOOR(base_count/2e0), CEILING(base_count/2e0)) )
SELECT DECIMAL(AVG(temperature),10,2) AS median FROM median_t

Это хорошо работает для возврата одного ряда, но похоже, что оно распадается на части для группировки. Концептуально это то, что я хочу:

<code>
SELECT city, AVG(temperature), MEDIAN(temperature) FROM ...
</code>
city           | mean_temp       | median_temp       
===================================================
'Minneapolis'  | 60              | 64
'Milwaukee'    | 65              | 66
'Muskegon'     | 70              | 61

Может быть ответ, который заставляет меня выглядеть глупо, но у меня психическое расстройство, и сейчас я не над этим работаю # 1. Кажется, это возможно, но я не могу использовать что-то очень сложное, поскольку это большая таблица, и я хочу иметь возможность настраивать агрегируемые столбцы.

1 Ответ

1 голос
/ 08 августа 2009

В SQL Server агрегированные функции, такие как count (*), можно разделить и рассчитать без группировки по. Я быстро просмотрел справочное руководство, на которое ссылаются, и похоже, что DB2 обладает той же функцией. Но если нет, то это не сработает:

create table TemperatureHistory 
    (City varchar(20)
    , Temperature decimal(5, 2)
    , DateTaken datetime)

insert into TemperatureHistory values ('Minneapolis', 61, '20090101')
insert into TemperatureHistory values ('Minneapolis', 59, '20090102')

insert into TemperatureHistory values ('Milwaukee', 65, '20090101')
insert into TemperatureHistory values ('Milwaukee', 65, '20090102')
insert into TemperatureHistory values ('Milwaukee', 100, '20090103')

insert into TemperatureHistory values ('Muskegon', 80, '20090101')
insert into TemperatureHistory values ('Muskegon', 70, '20090102')
insert into TemperatureHistory values ('Muskegon', 70, '20090103')
insert into TemperatureHistory values ('Muskegon', 20, '20090104')

; with base_t as
    (select city
        , Temperature
        , row_number() over (partition by city order by temperature) as RowNum
        , (count(*) over (partition by city)) + 1 as CountPlusOne 
    from TemperatureHistory)
select City
    , avg(Temperature) as MeanTemp
    , avg(case 
        when RowNum in (FLOOR(CountPlusOne/2.0), CEILING(CountPlusOne/2.0)) 
            then Temperature
            else null end) as MedianTemp
from base_t 
group by City
...