Результаты группового запроса по месяцам и годам в postgresql
У меня есть следующая таблица базы данных на сервере Postgres:
id date Product Sales
1245 01/04/2013 Toys 1000
1245 01/04/2013 Toys 2000
1231 01/02/2013 Bicycle 50000
456461 01/01/2014 Bananas 4546
Я хотел бы создать запрос, который дает SUM
столбца Sales
и группирует результаты по месяцам и годам следующим образом:
Apr 2013 3000 Toys
Feb 2013 50000 Bicycle
Jan 2014 4546 Bananas
Есть ли простой способ сделать это?
Ответы
Ответ 1
select to_char(date,'Mon') as mon,
extract(year from date) as yyyy,
sum("Sales") as "Sales"
from yourtable
group by 1,2
По просьбе Раду я объясню этот запрос:
to_char(date,'Mon') as mon,
: преобразует атрибут "date" в заданный формат короткой формы месяца.
extract(year from date) as yyyy
: функция "extract" Postgresql используется для извлечения года YYYY из атрибута "date".
sum("Sales") as "Sales"
: Функция SUM() объединяет все значения "Sales" и предоставляет псевдоним с учетом регистра, при этом чувствительность к регистру поддерживается с использованием двойных кавычек.
group by 1,2
: Функция GROUP BY должна содержать все столбцы из списка SELECT, которые не являются частью агрегата (ака, все столбцы не входят в функции SUM/AVG/MIN/MAX и т.д.). Это говорит о том, что SUM() следует применять для каждой уникальной комбинации столбцов, которые в этом случае являются столбцами месяца и года. Часть "1,2" является сокращением вместо использования псевдонимов столбцов, хотя, вероятно, лучше всего использовать полные выражения "to_char (...)" и "extract (...)" для удобочитаемости.
Ответ 2
Я не могу поверить, что в принятом ответе было так много стимулов - это ужасный метод.
Здесь правильный способ сделать это, date_trunc:
SELECT date_trunc('month', txn_date) AS txn_month, sum(amount) as monthly_sum
FROM yourtable
GROUP BY txn_month
Это плохая практика, но вам может быть прощено, если вы используете
GROUP BY 1
в очень простом запросе.
Вы также можете использовать
GROUP BY date_trunc('month', txn_date)
если вы не хотите выбирать дату.
Ответ 3
to_char
фактически позволяет вам вытащить Год и месяц одним махом!
select to_char(date('2014-05-10'),'Mon-YY') as year_month; --'May-14'
select to_char(date('2014-05-10'),'YYYY-MM') as year_month; --'2014-05'
или в случае примера пользователя выше:
select to_char(date,'YY-Mon') as year_month
sum("Sales") as "Sales"
from some_table
group by 1;
Ответ 4
bma ответ велик! Я использовал его с ActiveRecords, вот он, если кому-то это нужно в Rails:
Model.find_by_sql(
"SELECT TO_CHAR(created_at, 'Mon') AS month,
EXTRACT(year from created_at) as year,
SUM(desired_value) as desired_value
FROM desired_table
GROUP BY 1,2
ORDER BY 1,2"
)
Ответ 5
Postgress имеет несколько советов для временных меток в postgress:
временная метка без часового пояса - (желательно хранить метки времени UTC) Вы находите ее в хранилище многонациональных баз данных. Клиент в этом случае позаботится о смещении часового пояса для каждой страны.
временная метка с часовым поясом. Смещение временной зоны уже включено в метку времени.
В некоторых случаях ваша база данных не использует часовой пояс, но вам по-прежнему необходимо группировать записи по локальному часовому поясу и летнему времени (например, https://www.timeanddate.com/time/zone/romania/bucharest)
Чтобы добавить часовой пояс, вы можете использовать этот пример и заменить смещение часового пояса на ваше.
"your_date_column" at time zone '+03'
Чтобы добавить смещение Летнего времени +1 к DST, вам нужно проверить, попадает ли ваша временная метка в летнее летнее время. Поскольку эти интервалы меняются с 1 или 2 днями, я буду использовать аппроксимацию, которая не влияет на записи конца месяца, поэтому в этом случае я могу игнорировать каждый год точный интервал.
Если требуется более точный запрос, вам нужно добавить условия для создания большего числа случаев. Но, грубо говоря, это будет отлично работать в расщеплении данных в месяц в отношении часового пояса и SummerTime, когда вы найдете временную метку без часовой пояс в своей базе данных:
SELECT
"id", "Product", "Sale",
date_trunc('month',
CASE WHEN
Extract(month from t."date") > 03 AND
Extract(day from t."date") > 26 AND
Extract(hour from t."date") > 3 AND
Extract(month from t."date") < 10 AND
Extract(day from t."date") < 29 AND
Extract(hour from t."date") < 4
THEN
t."date" at time zone '+03' -- Romania TimeZone offset + DST
ELSE
t."date" at time zone '+02' -- Romania TimeZone offset
END) as "date"
FROM
public."Table" AS t
WHERE 1=1
AND t."date" >= '01/07/2015 00:00:00'::TIMESTAMP WITHOUT TIME ZONE
AND t."date" < '01/07/2017 00:00:00'::TIMESTAMP WITHOUT TIME ZONE
GROUP BY date_trunc('month',
CASE WHEN
Extract(month from t."date") > 03 AND
Extract(day from t."date") > 26 AND
Extract(hour from t."date") > 3 AND
Extract(month from t."date") < 10 AND
Extract(day from t."date") < 29 AND
Extract(hour from t."date") < 4
THEN
t."date" at time zone '+03' -- Romania TimeZone offset + DST
ELSE
t."date" at time zone '+02' -- Romania TimeZone offset
END)