Динамические имена столбцов в представлении (Postgres)
В настоящее время я программирую представление SQL, которое должно предоставить счетчик заполненного поля для определенного месяца.
Вот как я хотел бы, чтобы представление было построено:
Country | (Current Month - 12) Eg Feb 2011 | (Current Month - 11) | (Current Month - 10)
----------|----------------------------------|----------------------|---------------------
UK | 10 | 11 | 23
Число под месяцем должно быть подсчетом всех заполненных полей для конкретной страны. Поле называется eldate и является датой (приведенной в виде символа) в формате 10-12-2011. Я хочу, чтобы подсчет учитывал только те даты, которые соответствуют месяцу.
Таким образом, столбец "Текущий месяц - 12" должен включать только количество дат, которые попадают в месяц, который составляет 12 месяцев до настоящего времени. Например, текущий месяц - 12 для Великобритании должен включать количество дат, приходящихся на февраль-2011.
Я хотел бы, чтобы заголовки столбцов фактически отражали месяц, на который они смотрят, так:
Country | Feb 2011 | March 2011 | April 2011
--------|----------|------------|------------
UK | 4 | 12 | 0
Так что-то вроде:
SELECT c.country_name,
(SELECT COUNT("C1".eldate) FROM "C1" WHERE "C1".eldate LIKE %NOW()-12 Months% AS NOW() - 12 Months
(SELECT COUNT("C1".eldate) FROM "C1" WHERE "C1".eldate LIKE %NOW()-11 Months% AS NOW() - 11 Months
FROM country AS c
INNER JOIN "site" AS s using (country_id)
INNER JOIN "subject_C1" AS "C1" ON "s"."site_id" = "C1"."site_id"
Очевидно, что это не работает, но просто чтобы дать вам представление о том, к чему я стремлюсь.
Есть идеи?
Спасибо за вашу помощь, любые вопросы, пожалуйста, спросите.
2 ответа
Мое первое желание состоит в том, чтобы произвести эту таблицу:
+---------+-------+--------+
| Country | Month | Amount |
+---------+-------+--------+
| UK | Jan | 4 |
+---------+-------+--------+
| UK | Feb | 12 |
+---------+-------+--------+
и так далее. Итак, вы начали бы с (например):
SELECT
c.country,
EXTRACT(MONTH FROM s.eldate) AS month,
COUNT(*) AS amount
FROM country AS c
JOIN site AS s ON s.country_id = c.id
WHERE
s.eldate > NOW() - INTERVAL '1 year'
GROUP BY c.country, EXTRACT(MONTH FROM s.eldate);
Вы можете подключить это к одному crosstab
функции от tablefunc
Модуль для достижения цели, делая что-то вроде этого:
SELECT *
FROM crosstab('<query from above goes here>')
AS ct(country varchar, january integer, february integer, ... december integer);
Вы можете усечь даты, чтобы сделать сопоставимые:
WHERE date_trunc('month', eldate) = date_trunc('month', now()) - interval '12 months'
ОБНОВИТЬ
Этот вид замены для вашего запроса:
(SELECT COUNT("C1".eldate) FROM "C1" WHERE date_trunc('month', "C1".eldate) =
date_trunc('month', now()) - interval '12 months') AS TWELVE_MONTHS_AGO
Но это потребовало бы сканирования таблицы за каждый месяц, так что вы могли бы сделать одно сканирование с чем-то большим по следующим направлениям:
SELECT SUM( CASE WHEN date_trunc('month', "C1".eldate) = date_trunc('month', now()) - interval '12 months' THEN 1 ELSE 0 END ) AS TWELVE_MONTHS_AGO
,SUM( CASE WHEN date_trunc('month', "C1".eldate) = date_trunc('month', now()) - interval '11 months' THEN 1 ELSE 0 END ) AS ELEVEN_MONTHS_AGO
...
или сделайте соединение с таблицей месяцев, как показывают другие.
UPDATE2
В дополнение к комментарию об исправлении столбцов с января по декабрь я подумал примерно так: отфильтруйте данные за последние годы, а затем суммируйте за соответствующий месяц. Возможно, вот так:
SELECT SUM( CASE WHEN EXTRACT(MONTH FROM "C1".eldate) = 1 THEN 1 ELSE 0 END ) AS JAN
,SUM( CASE WHEN EXTRACT(MONTH FROM "C1".eldate) = 2 THEN 1 ELSE 0 END ) AS FEB
...
WHERE date_trunc('month', "C1".eldate) < date_trunc('month', now())
AND date_trunc('month', "C1".eldate) >= date_trunc('month', now()) - interval '12 months'