Динамические имена столбцов в представлении (Postgres) - PullRequest
1 голос
/ 27 февраля 2012

В настоящее время я программирую представление 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 ]

2 голосов
/ 27 февраля 2012

Мое первое желание - создать эту таблицу:

+---------+-------+--------+
| 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);
1 голос
/ 27 февраля 2012

Вы можете усечь даты, чтобы сделать сопоставимые:

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
...

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

ОБНОВЛЕНИЕ2

В дополнение к комментарию об исправлении столбцов с января по декабрь я подумал примерно так: отфильтруйте данные за последние годы, а затем суммируйте за соответствующий месяц.Возможно так:

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'
...