SQL: эффективный способ выполнять расчеты с данными в длинном формате - PullRequest
0 голосов
/ 05 июня 2018

У меня есть таблица мужских и женских подсчетов по элементам, например:

enter image description here

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

ITEM  PROP_MALE
A     0.3
B     0.5

В R я бы dcast пол в широкоформатном формате, а затем разделить количество мужчин на общее количество, как только M / F находятся в той же строке.Но в SQL я пытаюсь найти эффективное решение (если оно помогает, я использую Oracle SQL).

Ответы [ 4 ]

0 голосов
/ 05 июня 2018

Я бы сделал это просто используя sum() и деление:

select item,
       sum(case when gender = 'M' then n else 0 end) / sum(n) as male_ratio
from t
group by item;
0 голосов
/ 05 июня 2018

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

SQL Fiddle

Настройка схемы Oracle 11g R2 :

CREATE TABLE table_name ( item , gender, n ) AS
SELECT 'A', 'M',  30 FROM DUAL UNION ALL
SELECT 'A', 'F',  70 FROM DUAL UNION ALL
SELECT 'B', 'M', 100 FROM DUAL UNION ALL
SELECT 'B', 'F', 100 FROM DUAL;

Запрос 1 :

SELECT Item,
       n / total AS prop_male
FROM   (
  SELECT t.*,
         SUM( n ) OVER ( PARTITION BY Item ) AS total
  FROM   table_name t
)
WHERE  gender = 'M'

Результаты :

| ITEM | PROP_MALE |
|------|-----------|
|    A |       0.3 |
|    B |       0.5 |

Вы можете даже выполнитьрасчет непосредственно по таблице с неучтенными значениями:

Настройка схемы Oracle 11g R2 :

CREATE TABLE table_name_pre_count ( item , gender ) AS
SELECT 'A', 'M' FROM DUAL CONNECT BY LEVEL <=  30 UNION ALL
SELECT 'A', 'F' FROM DUAL CONNECT BY LEVEL <=  70 UNION ALL
SELECT 'B', 'M' FROM DUAL CONNECT BY LEVEL <= 100 UNION ALL
SELECT 'B', 'F' FROM DUAL CONNECT BY LEVEL <= 100;

Запрос 2 :

SELECT Item,
       prop_male
FROM   (
  SELECT item,
         gender,
         COUNT(*) / SUM( COUNT(*) ) OVER ( PARTITION BY Item )
           AS prop_male
  FROM   table_name_pre_count
  GROUP BY Item, Gender
)
WHERE  gender = 'M'

Результаты :

| ITEM | PROP_MALE |
|------|-----------|
|    A |       0.3 |
|    B |       0.5 |
0 голосов
/ 05 июня 2018
create table gender
(
  item varchar(10),
  gender varchar(10),
  val decimal(3,1)
  );
 insert into gender values ('A','M',30) ;
 insert into gender values ('A','F',70) ;
 with cte as
(
  select item,val,gender,
  sum(val) over(order by val) as calc
  from gender
  ),
cte1 as 
  (
  select item,
  case when gender='M' then val/calc end as prop_male
  from cte)
  select * from cte1
  where PROP_MALE is not null
0 голосов
/ 05 июня 2018

Вы можете использовать RATIO_TO_REPORT:

SELECT ITEM, PROP_MALE
FROM  (SELECT ITEM, gender,
       RATIO_TO_REPORT(N) OVER (PARTITION BY Item) AS PROP_MALE
      FROM tab) sub
WHERE sub.gender = 'M';

DBFiddle Demo

...