Группировать по - выбрать по критерию, который встречается каждый месяц - PullRequest
0 голосов
/ 24 ноября 2018

Приведенный ниже запрос возвращает все USERS, которые имеют SUM(AMOUNT) > 10 в данном месяце.Он включает в себя пользователей за месяц, даже если они не соответствуют критериям в другие месяцы.

Но я бы хотел преобразовать этот запрос, чтобы он возвращал всех USERS, которые должны соответствовать критериям SUM(AMOUNT) > 10 каждый месяц (т. е. от первого месяца в таблице до последнего) по всем данным.

Другими словами, исключите пользователей, которые не встречают SUM(AMOUNT) > 10 каждый месяц.

select USERS, to_char(transaction_date, 'YYYY-MM') as month
from Table
GROUP BY USERS, month
HAVING SUM(AMOUNT) > 10;

Ответы [ 4 ]

0 голосов
/ 24 ноября 2018

Вам нужно сравнить количество месяцев> 10 с количеством месяцев между минимальной и максимальной датой:

SELECT users, Count(flag) AS months, Min(mth), Max(mth)
FROM
 (
   SELECT users, date_trunc('month',transaction_date) AS mth, 
      CASE WHEN Sum(amount) > 10 THEN 1 end AS flag
   FROM tab t
   GROUP BY users, mth
 ) AS dt
GROUP BY users  
HAVING -- adding the number of months > 10 to the min date and compare to max
   Min(mth) + (INTERVAL '1' MONTH * (Count(flag)-1)) = Max(mth)

Если пропущенные месяцы не учитываются, это будет просто count(flag) = count(*)

0 голосов
/ 24 ноября 2018

Один вариант будет использовать sign(amount-10) против sign(amount) логики как

SELECT q.users
  FROM
    (
    with tab(users, transaction_date,amount) as
    (
     select 1,date'2018-11-24',8 union all
     select 1,date'2018-11-24',18 union all    
     select 2,date'2018-10-24',13 union all
     select 3,date'2018-11-24',18 union all    
     select 3,date'2018-10-24',28 union all
     select 3,date'2018-09-24', 3 union all    
     select 4,date'2018-10-24',28
    )
    SELECT users, to_char(transaction_date, 'YYYY-MM') as month, 
           sum(sign(amount-10)) as cnt1,
           sum(sign(amount)) as cnt2
      FROM tab t
     GROUP BY users, month
    ) q
  GROUP BY q.users  
  HAVING sum(q.cnt1) = sum(q.cnt2)
  GROUP BY q.users

  users
  -----
    2
    4

Rextester Demo

0 голосов
/ 24 ноября 2018

Возможно, вы могли бы использовать коррелированный подзапрос, такой как:

select t.*
from (select distinct table.users from table) t
where not exists 
(
    select to_char(u.transaction_date, 'YYYY-MM') as month 
    from table u 
    where u.users = t.users 
    group by month
    having sum(u.amount) <= 10
)
0 голосов
/ 24 ноября 2018

Один подход использует сгенерированную календарную таблицу, представляющую все месяцы в вашем наборе данных.Мы можем присоединить эту таблицу календаря к вашему текущему запросу и затем агрегировать данные за все месяцы по пользователю:

WITH months AS (
    SELECT DISTINCT TO_CHAR(transaction_date, 'YYYY-MM') AS month
    FROM yourTable
),
cte AS (
    SELECT USERS, TO_CHAR(transaction_date, 'YYYY-MM') AS month
    FROM yourTable
    GROUP BY USERS, month
    HAVING SUM(AMOUNT) > 10
)

SELECT
    t.USERS
FROM months m
LEFT JOIN cte t
    ON m.month = t.month
GROUP BY
    t.USERS
HAVING
    COUNT(t.USERS) = (SELECT COUNT(*) FROM months);

В приведенном выше предложении HAVING утверждается, что количество месяцев, которым соответствует пользователь, на самом делеобщее количество месяцев.Это будет означать, что пользователь соответствует критериям суммы для каждого месяца.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...