Использование внешнего запроса приводит к подзапросу в postgresql - PullRequest
7 голосов
/ 16 ноября 2011

У меня есть две таблицы points и contacts, и я пытаюсь получить среднее значение points.score на контакт, сгруппированный ежемесячно. Обратите внимание , что точки и контакты не связаны, я просто хочу, чтобы сумма очков, созданных за месяц, делилась на количество контактов, которые существовали в этом месяце.

Итак, мне нужносумма очков, сгруппированных по месяцу созданного в месяц, и мне нужно считать количество контактов ТОЛЬКО ЗА МЕСЯЦ.Это последняя часть, которая обманывает меня.Я не уверен, как я могу использовать столбец из внешнего запроса в подзапросе.Я попробовал что-то вроде этого:

SELECT SUM(score) AS points_sum,
  EXTRACT(month FROM created_at) AS month,
  date_trunc('MONTH', created_at) + INTERVAL '1 month' AS next_month,
  (SELECT COUNT(id) FROM contacts WHERE contacts.created_at <= next_month) as contact_count
FROM points
GROUP BY month, next_month
ORDER BY month

Итак, я извлекаю фактический месяц, в который мои суммы суммируются, и в то же время получаю начало следующего месяца, чтобы я мог сказать «Получитьme число контактов, в которых они созданы, составляет

Но он жалуется, что column next_month doesn't exist Это понятно, поскольку подзапрос ничего не знает о внешнем запросе.Квалификация с points.next_month тоже не работает.

Так может ли кто-нибудь указать мне правильное направление, как этого достичь?

Таблицы:

Очки

score | created_at
10    | "2011-11-15 21:44:00.363423"
11    | "2011-10-15 21:44:00.69667" 
12    | "2011-09-15 21:44:00.773289"
13    | "2011-08-15 21:44:00.848838"
14    | "2011-07-15 21:44:00.924152"

Контакты

id | created_at
6  | "2011-07-15 21:43:17.534777"
5  | "2011-08-15 21:43:17.520828"
4  | "2011-09-15 21:43:17.506452"
3  | "2011-10-15 21:43:17.491848"
1  | "2011-11-15 21:42:54.759225"

сумма, месяц и следующий месяц (без подвыбора)

sum | month | next_month
14  | 7     | "2011-08-01 00:00:00"
13  | 8     | "2011-09-01 00:00:00"
12  | 9     | "2011-10-01 00:00:00"
11  | 10    | "2011-11-01 00:00:00"
10  | 11    | "2011-12-01 00:00:00"

1 Ответ

10 голосов
/ 16 ноября 2011

Редактировать

Теперь с текущая сумма контактов.Мой первый черновик использовал новых контактов в месяц , что явно не то, что хочет OP.

WITH c AS (
    SELECT created_at
          ,count(id) OVER (order BY created_at) AS ct
    FROM   contacts
    ), p AS (
    SELECT date_trunc('month', created_at) AS month
          ,sum(score) AS points_sum
    FROM   points
    GROUP  BY 1
    )
SELECT p.month
      ,EXTRACT(month FROM p.month) AS month_nr
      ,p.points_sum
      ,( SELECT c.ct
         FROM   c
         WHERE  c.created_at < (p.month + interval '1 month')
         ORDER  BY c.created_at DESC
         LIMIT  1) AS contacts
FROM   p
ORDER  BY 1
  • Это работает для любого числа месяцев в течениелет.
  • Предполагается, что в таблице нет ни одного месяца points.Если вы хотите, чтобы все месяцы, включая пропущенные, в points, сгенерировали список месяцев с помощью generate_series () и присоединитесь к нему.
  • Создайте промежуточную сумму в CTE с помощьюоконная функция.
  • Оба CTE не являются строго необходимыми - только для производительности и упрощения.
  • Получение контактов_счетом в подвыборке.

Ваш Исходная форма запроса может работать следующим образом:

SELECT month
      ,EXTRACT(month FROM month) AS month_nr
      ,points_sum
      ,(SELECT count(*)
        FROM   contacts c
        WHERE  c.created_at < (p.month + interval '1 month')) AS contact_count
FROM   (
    SELECT date_trunc('MONTH', created_at) AS month
          ,sum(score) AS points_sum
    FROM   points p
    GROUP  BY 1
    ) p
ORDER  BY 1

Исправление для непосредственной причины вашей ошибки - поместить агрегат в подзапрос.Вы смешивали уровни так, что это невозможно.
Я ожидаю, что мой вариант будет немного быстрее с большими столами.Не уверен насчет небольших столов.Было бы здорово, если бы вы сообщили с результатами теста.
Плюс незначительное исправление: < вместо <=.

...