简体   繁体   中英

How to Generate Monthly Cohorts in One Report Using Postgresql?

The original table User

ID   Created_Date   SubmittedAt   ApprovedAt

The original table Campaign

User_ID   Clicked_At

Now I want to generate a report with columns like

Month  Year  #Applicants  #Submitted  #Approved

I wrote queries using postgresql:

SELECT To_char(C.clicked_at, 'MON')    AS MON, 
       Extract(year FROM C.clicked_at) AS YYYY, 
       CASE 
         WHEN created_date IS NOT NULL THEN Count(user_id) 
       END AS APPLICANTS, 
       CASE 
         WHEN submittedat IS NOT NULL THEN Count(user_id) 
       END AS SUBMITTED, 
       CASE 
         WHEN approvedat IS NOT NULL THEN Count(user_id) 
       END AS APPROVED 
FROM   campaign C, 
       users U 
WHERE  C.user_id = U.id 
GROUP  BY 1,2 

I got an error message " u.created_date must appear in the GROUP BY clause or be used in an aggregate function. However, I just want my results to be grouped by year and month .

First, use proper, explicit JOIN syntax. Second, if you want to count the number of non-null values, then you can simplify the code:

SELECT TO_CHAR(C.CLICKED_AT, 'MON') AS MON,
       EXTRACT(YEAR FROM C.CLICKED_AT) AS YYYY,
       COUNT(CREATED_DATE) AS APPLICANTS,
       COUNT(SUBMITTEDATE) AS SUBMITTED,
       COUNT(APPROVEDAT) AS APPROVED
FROM CAMPAIGN C JOIN
     USERS U
     ON C.USER_ID = U.ID
GROUP BY 1, 2;

With this simplification, you no longer have any (explicit) conditional logic at all, so the group by clause is fine.

I would suggest that you combine the month and year and sort the results:

SELECT TO_CHAR(C.CLICKED_AT, 'YYYY-MM') AS yyyymm,
       COUNT(CREATED_DATE) AS APPLICANTS,
       COUNT(SUBMITTEDATE) AS SUBMITTED,
       COUNT(APPROVEDAT) AS APPROVED
FROM CAMPAIGN C JOIN
     USERS U
     ON C.USER_ID = U.ID
GROUP BY 1
ORDER BY 1;

You need to put your CASE statements within an aggregate function:

SELECT TO_CHAR(C.CLICKED_AT,'MON') AS MON,
EXTRACT(YEAR FROM C.CLICKED_AT) AS YYYY,
COUNT(CASE WHEN CREATED_DATE IS NOT NULL THEN USER_ID END) AS APPLICANTS,
COUNT(CASE WHEN SUBMITTEDAT IS NOT NULL THEN USER_ID END) AS SUBMITTED,
COUNT(CASE WHEN APPROVEDAT IS NOT NULL THEN USER_ID END) AS APPROVED
FROM
CAMPAIGN C
JOIN USERS U ON C.USER_ID = U.ID
GROUP BY 1,2

Notes:

  • if you are using Postgres 9.4+ then you could use FILTER clause.
  • use explicit JOIN clause instead of WHERE clause for connecting tables
  • you may be better of with expanding your TO_CHAR() to accept year and month

Example:

SELECT TO_CHAR(C.CLICKED_AT,'YYYY-MM') AS date_year_month,
COUNT(CASE WHEN CREATED_DATE IS NOT NULL THEN USER_ID END) AS APPLICANTS,
COUNT(CASE WHEN SUBMITTEDAT IS NOT NULL THEN USER_ID END) AS SUBMITTED,
COUNT(CASE WHEN APPROVEDAT IS NOT NULL THEN USER_ID END) AS APPROVED
FROM
CAMPAIGN C
JOIN USERS U ON C.USER_ID = U.ID
GROUP BY 1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM