postgresql — квартал postgres date_trunc с настраиваемым месяцем начала
Задавать вопрос
спросил
Изменено 2 года, 1 месяц назад
Просмотрено 2к раз
Я пытаюсь создать среднее квартальное количество очков игроков, однако поведение postgres 9 по умолчанию0013 date_trunc(‘четверть’, источник) заключается в том, что первый квартал начинается с ГГГГ-01-01.
Есть ли какой-либо способ или обходной путь, который я могу сделать, чтобы сказать, что первый месяц первого квартала, например, сентябрь? Итак, вместо традиционного: Q1: 1-3, Q2: 4-6, Q3: 7-9, Q4: 10-12
я хочу иметь возможность указать, какой месяц является началом Q1, поэтому, если я скажу Сентябрь это должно быть: Q1: 9-11, Q2: 12-2, Q3: 3-5, Q4: 6-8
Вот как я делаю стандартный квартальный средний балл с кварталом по умолчанию.
ВЫБЕРИТЕ идентификатор, имя, date_trunc('квартал', дата) КАК дата, AVG(ранг) AS ранг, AVG(оценка) как оценка, страна, устройство ОТ player_daily_score СГРУППИРОВАТЬ ПО id, имя, 3, страна, устройство ЗАКАЗАТЬ ПО 3 уб.;
Я открыт для всех предложений, чтобы заставить это работать.
- postgresql
- статистика
0
Если вам действительно не нужна дата начала квартала, вы можете легко сделать это с помощью выражения CASE:
ВЫБЕРИТЕ идентификатор, имя, случай при извлечении (месяц с даты) в (9,10,11), затем «Q1» при извлечении (месяц с даты) в (12,1,2), затем «Q2» при извлечении (месяц с даты) в (3,4,5), затем «Q3» при извлечении (месяц из даты) в (6,7,8), затем «Q4» конец как четверть, AVG(ранг) AS ранг, AVG(оценка) как оценка, страна, устройство ОТ player_daily_score СГРУППИРОВАТЬ ПО id, имя, 3, страна, устройство ЗАКАЗАТЬ ПО 3 уб.;
Конечно, вы можете поместить это в хранимую функцию, чтобы упростить ваши запросы.
0
На самом деле вы не используете номер квартала, только метки времени.
Итак, все, что вам нужно, это смещение , которое вы вычитаете, а затем добавляете обратно после усечения, что составляет interval '2 month'
для вашего примера:
SELECT id, date , date_trunc('квартал', дата - интервал '2 месяца') + интервал "2 месяца" AS квартал ОТ player_daily_score;
db<>скрипка здесь
Однако ваш запрос не имеет смысла. Включение столбца id
(при условии, что это PK) в GROUP BY
является шумовой операцией, так как ничего не будет агрегировано. Это могло бы иметь смысл:
SELECT date_trunc('квартал', дата - интервал '2 месяца') + интервал "2 месяца" AS квартал , страна , устройство , AVG(ранг) AS avg_rank , AVG(оценка) AS avg_score ОТ player_daily_score СГРУППИРОВАТЬ ПО 1,2,3 ЗАКАЗАТЬ ПО 1 уб;
Если id
не является ПК, дизайн вашей базы данных может выиграть от нормализации.
1
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью Google
Зарегистрироваться через Facebook
Зарегистрируйтесь, используя адрес электронной почты и пароль
Опубликовать как гость
Электронная почта
Требуется, но не отображается
Опубликовать как гость
Электронная почта
Требуется, но не отображается
Нажимая «Опубликовать свой ответ», вы соглашаетесь с нашими условиями обслуживания, политикой конфиденциальности и политикой использования файлов cookie
.![](/800/600/http/s33046.pcdn.co/wp-content/uploads/2019/08/database-properties-for-statistics.png)
Получение даты последнего изменения таблицы базы данных PostgreSQL
Записи сначала записываются в журнал записывающей головки (WAL), затем лениво в кучу (табличные файлы). Как только запись находится в WAL, Pg не спешит записывать ее в кучу, и она может даже не записываться до следующей системной контрольной точки;
Большие таблицы имеют несколько ответвлений, вам придется проверить все ответвления и выбрать самую новую отметку времени;
Простой
SELECT
может генерировать активность записи в базовую таблицу из-за установки бита подсказки;autovaccum и другое обслуживание, которое не изменяет видимые пользователю данные, по-прежнему изменяет файлы отношений;
некоторые операции, такие как
Это может быть не так, как вы ожидаете, если вы пытаетесь просмотреть его одновременно, не используя соответствующую блокировку.vaccum full
, заменят relfilenode.
Несколько вариантов
Если вам не нужна надежность, вы потенциально можете использовать информацию в pg_stat_database
и pg_stat_all_tables
. Они могут дать вам время последнего сброса статистики и статистику активности с последнего сброса статистики. Он не сообщает вам, когда была самая последняя активность, только то, что это было с момента последнего сброса статистики, и нет информации о том, что произошло до этого сброса статистики. Так что это ограничено, но это уже есть.
Один из способов сделать это надежно — использовать триггер для обновления таблицы, содержащей время последнего изменения для каждой таблицы. Имейте в виду, что это сериализует все записи в таблицу , разрушая параллелизм. Это также добавит изрядные накладные расходы на каждую транзакцию. Я не рекомендую это.
Чуть менее ужасная альтернатива — использовать ПРОСЛУШАТЬ
и УВЕДОМИТЬ
. Подключите внешний процесс демона к PostgreSQL и LISTEN
для событий. Используйте ON INSERT OR UPDATE OR DELETE
запускает отправку NOTIFY
s при изменении таблицы с oid таблицы в качестве полезной нагрузки уведомления. Они отправляются, когда транзакция фиксируется. Ваш демон может накапливать уведомления об изменениях и лениво записывать их обратно в таблицу базы данных. Если система дает сбой, вы теряете записи о самых последних изменениях, но это нормально, вы просто обрабатываете все таблицы как только что измененные, если запускаете после сбоя.
Чтобы избежать худших проблем с параллелизмом, вместо этого вы можете регистрировать временные метки изменений, используя перед вставкой, обновлением, удалением или усечением имени таблицы для каждого оператора выполняется триггер
, обобщенный для использования отношения oid в качестве параметра. Это вставит пару
(relation_oid, timestamp)
в таблицу регистрации изменений. Затем у вас есть вспомогательный процесс в отдельном соединении или периодически вызываемый вашим приложением, который объединяет эту таблицу для получения последней информации, объединяет ее в сводную таблицу самых последних изменений и усекает таблицу журнала. Единственное преимущество этого подхода по сравнению с подходом «прослушивание/уведомление» заключается в том, что он не теряет информацию при сбое, но при этом он еще менее эффективен.
Другим подходом может быть написание функции расширения C, которая использует (например) ProcessUtility_hook
, ExecutorRun_hook
и т. д. для перехвата изменений в таблице и ленивого обновления статистики. Я не смотрел, насколько это практично; взгляните на различные параметры _hook в исходниках.
Лучшим способом было бы исправить код статистики для записи этой информации и отправить исправление в PostgreSQL для включения в ядро. Не начинайте просто с написания кода; поднимите свою идею на -hackers, как только вы обдумаете ее достаточно, чтобы иметь четко определенный способ сделать это (т.е. начните с чтения кода, а не просто спрашивайте «как мне…»). Было бы неплохо добавить время последнего обновления к
pg_stat_...
, но вам нужно будет убедить сообщество, что это того стоило, или предоставить способ опционального отслеживания — и вам придется написать код, чтобы сохранить статистику и отправить патч , потому что этим будет заниматься только тот, кому нужна эта функция.
Как бы я это сделал
Если бы мне пришлось это сделать, и у меня не было времени написать патч, чтобы сделать это должным образом, я бы, вероятно, использовал описанный выше подход прослушивания/уведомления.
Обновление для PostgreSQL 9.5 метки времени фиксации
Обновление : PostgreSQL 9.5 имеет метки времени фиксации . Если вы включили их в postgresql.