#sql #postgresql #group-by #percentage
#sql #postgresql #группировать по #процент
Вопрос:
Я хотел бы создать новый столбец, который содержит значения 50%, 60% и т.д. На основе значений из других столбцов, присутствующих в таблице. Из приведенного ниже вывода я хотел бы иметь столбец «Желаемые результаты» на основе значений из столбца «cnt». В настоящее время мои входные данные выглядят так, как показано ниже
Я мог получить только cnt записей из приведенного ниже запроса. Однако я не могу сгенерировать процент. Можете ли вы, пожалуйста, помочь мне?
with test as
(
select subject_id,hadm_id,case
when valuenum between 80 and 110 then 1
else 0
end as "within_range"
from labevents where itemid in ('50809','50931','51529') and
hadm_id is not null
) select subject_id,hadm_id,within_range,count(*) as cnt
from test group by subject_id,hadm_id,within_range
Я бы хотел, чтобы результат был таким, как показано ниже
Комментарии:
1. какова логика, стоящая за этими процентами
2. Если вы посмотрите на данные выше, для subject_id = 3, имеет две строки, а общее cnt равно 22, поэтому 14/22 равно 64, а 8/22 равно 36. Аналогично для остальных. Для объектов, где есть только одна запись, тогда это 100 пк
Ответ №1:
Используйте функцию окна:http://www.postgresqltutorial.com/postgresql-window-function /
with cte as
(
select subject_id,
hadm_id,
case
when valuenum between 80 and 110 then 1
else 0
end as "within_range"
from labevents
where itemid in ('50809', '50931', '51529')
and hadm_id is not null
),
subq as (
select subject_id,
hadm_id,
within_range,
count(*) as cnt
from cte
group by subject_id, hadm_id, within_range
)
select subq.*, (cnt / sum(cnt) OVER (PARTITION BY subject_id, hadm_id)) * 100 "Desired Results"
from subq;
Комментарии:
1. Для вашей логики вы должны настроить «РАЗДЕЛЕНИЕ ПО» столбцам
Ответ №2:
Вы можете использовать функцию окна с group by
. Кроме того, CTE на самом деле не нужен, особенно потому, что Postgres позволяет использовать псевдонимы столбцов для group by
:
select subject_id, hadm_id,
(case when valuenum between 80 and 110 then 1
else 0
end) as within_range,
count(*) as cnt,
count(*) * 100.0 / sum(count(*)) over () as percentage
from labevents
where itemid in ('50809', '50931', '51529') and
hadm_id is not null
group by subject_id, hadm_id, within_range
Ответ №3:
Для этой цели у вас может быть два подзапроса, один из которых сгруппирован по hadm_id, а другой — нет, и объединить их оба.
select a.* ,(a.cnt/b.cnt)*100
from(select subject_id,hadm_id,within_range,count(*) as cnt
FROM (select subject_id,hadm_id,case
when valuenum between 80 and 110 then 1
else 0
end as "within_range"
from labevents where itemid in ('50809','50931','51529') and
hadm_id is not null)
group by subject_id,hadm_id,within_range)a
INNER JOIN
(select subject_id,within_range,count(*) as cnt
FROM (select subject_id,hadm_id,case
when valuenum between 80 and 110 then 1
else 0
end as "within_range"
from labevents where itemid in ('50809','50931','51529') and
hadm_id is not null)
group by subject_id,within_range)b
on a.subject_id,b.subject_id and a.within_range=b.within_range