2012-04-19 1 views
1

У меня есть PostgreSQL таблицы userDistributions, как это:
user_id, start_date, end_date, project_id, distribution

Мне нужно написать запрос, в котором определенный диапазон дат и идентификатор пользователя, результат должен быть суммой всех распределений за каждый день для данного пользователя.
Так что выход должен быть, как это для ввода: «2-2-2012» - «2-4-2012», некоторые идентификаторов пользователя:
Date SUM(Distribution)
2-2-2012 12
2-3-2012 15
2-4-2012 34
Как найти сумму столбца между заданным диапазоном дат, где таблица имеет только дату начала и дату окончания

Пользователь имеет распределение во многих проектах, поэтому я необходимо суммировать распределения во всех проектах за каждый день и выводить эту сумму по сравнению с этим днем.

Моя проблема в том, с чем мне следует группироваться? Если бы у меня было поле в качестве даты (вместо start_date и end_date), тогда я мог бы написать что-то вроде
select date, SUM(distributions) from userDistributions group by date;
, но в этом случае я в тупике, как что делать. Спасибо за помощь.

+3

Ваша база данных нуждается в календарную таблицу. Это упрощает эти запросы. –

+2

@GordonLinoff: вам почти никогда не нужны календарные таблицы с PostgreSQL, 'generate_series' намного приятнее. –

+0

Ожидаете ли вы увидеть данные о дате без проектов? –

ответ

4

Использование generate_series произвести ваши даты, что-то вроде этого:

select dt.d::date, sum(u.distributions) 
from userdistributions u 
join generate_series('2012-02-02'::date, '2012-02-04'::date, '1 day') as dt(d) 
    on dt.d::date between u.start_date and u.end_date 
group by dt.d::date 

Ваш формат даты является неоднозначным, так что я думаю, при преобразовании его в ISO 8601.

+0

Это просто потрясающе, является ли generate_series специальным постгером или стандартом со всеми другими СУБД? –

+0

@Rohit: Я уверен, что он специфичен для PostgreSQL, но он настолько невероятно полезен, что он действительно должен быть в стандарте. –

+0

@Rohitchauhan Это нестандартная функция PostgreSQL. –

2

Это очень похоже на ответ @ Му.
Однако, чтобы покрыть дней без каких-либо матчей вы должны использовать LEFT JOIN:

SELECT d.d::date, sum(u.distributions) AS dist_sum 
FROM generate_series('2012-02-02'::date, '2012-02-04'::date, '1 day') AS d(d) 
LEFT JOIN userdistributions u ON d.d::date BETWEEN u.start_date AND u.end_date 
GROUP BY 1 
+0

Спасибо, за подсказку. –

+0

Да, это управляет ситуацией «было бы неплохо» с указанием дат без соответствующих записей пользовательских распределений. – kgrittn