2015-12-29 3 views
2

Мне нужна ваша помощь. Я хочу нормализовать числа внутри групп. Скажем, у меня есть этот набор данных:Нормализовать значения в группе с помощью SQL

A B C 
------- 
0 1 3 
1 1 0 
1 1 2 
1 1 4 
1 2 1 
1 2 1 

Я хочу, чтобы сгруппировать эти строки по А и В, а затем нормализовать значения C в пределах своей группы, т.е. суммируя все Кассиопеяне группы, а затем разделив каждую С помощью эта сумма. В приведенном выше примере я ожидал бы такой результат:

A B C 
--------- 
0 1 1   // sum of C's in group is 1, 1/1=1 
1 1 0   // sum of C's in group is 6, 0/6=0 
1 1 1/3   // ... 
1 1 2/3   // ... 
1 2 1/2   // sum of C's in group is 2, 1/2=1/2 
1 2 1/2   // ... 

Отдел по нолю может обрабатываться отдельно. Как это сделать, используя SQL (или PSQL, если это помогает)? Я могу думать о том, как это сделать в принципе, но я всегда получаю глубоко вложенные SELECT, которых я хочу избежать.

Заранее благодарен!

ответ

5

Вы можете использовать оконную функции для него:

SELECT a,b, 
    1.0 * c/CASE WHEN SUM(c) OVER(PARTITION BY a,b) = 0 THEN 1 
        ELSE SUM(c) OVER(PARTITION BY a,b) END AS c 
FROM tab 

SqlFiddleDemo

Выход:

╔════╦════╦════════════════════╗ 
║ a ║ b ║   c   ║ 
╠════╬════╬════════════════════╣ 
║ 0 ║ 1 ║ 1     ║ 
║ 1 ║ 1 ║ 0     ║ 
║ 1 ║ 1 ║ 0.3333333333333333 ║ 
║ 1 ║ 1 ║ 0.6666666666666666 ║ 
║ 1 ║ 2 ║ 0.5    ║ 
║ 1 ║ 2 ║ 0.5    ║ 
║ 2 ║ 2 ║ 0     ║   -- added for check division by 0 
╚════╩════╩════════════════════╝ 
+1

лучший ответ. –

+1

Блестящий, спасибо тонну. – random6174

1

Вы можете использовать производную таблицу для агрегирования значений, а затем join результатов обратно в исходную таблицу. Чтобы избежать деления на 0, было включено предложение where. Для этих сумм 0 вам может потребоваться специальное условие для их выбора.

select t.a, t.b, 1.0 * t.c/t1.total_c 
from tablename t 
join (select a, b, sum(c) as total_c 
     from tablename 
     group by a, b) t1 
on t.a = t1.a and t.b = t1.b 
where t1.total_c > 0 
+0

Позволяет проверить, что ... зависает :) – random6174

+1

Я немного обновил его tttal_c должен быть 't1.total_c', а Results - 0 для всех строк (int division) [demo] (http: // sqlfiddle. com/#! 15/8cd45/4/0) :) – lad2025

+0

уверенный @ lad2025..thanks для редактирования. я пропустил это –

0
with t (a,b,c) as (values 
    (0, 1, 3), 
    (1, 1, 0), 
    (1, 1, 2), 
    (1, 1, 4), 
    (1, 2, 1), 
    (1, 2, 1), 
    (2, 2, 0) 
) 
select 
    a, b, 
    c::float/coalesce(nullif(sum(c) over(partition by a, b), 0), 1) as normal 
from t 
; 
a | b |  normal  
---+---+------------------- 
0 | 1 |     1 
1 | 1 |     0 
1 | 1 | 0.333333333333333 
1 | 1 | 0.666666666666667 
1 | 2 |    0.5 
1 | 2 |    0.5 
2 | 2 |     0 
+0

Безопасное деление на 0 '(2,2,0)' ** [demo] (http://sqlfiddle.com/#!15/bdfd0/3/0) ** – lad2025

+1

@ lad2025: Выполнено. –

Смежные вопросы