Get the distinct sum of a joined table column

前端 未结 4 2049
花落未央
花落未央 2020-11-27 23:14

I have a problem here, and I\'m hoping there is an easy solution. I\'ll try to make this as simple as possible:

  • A ticket belongs to an attendee
  • Exampl
相关标签:
4条回答
  • 2020-11-27 23:21

    To get the result without subquery, you have to resort to advanced window function trickery:

    SELECT sum(count(*))       OVER () AS tickets_count
         , sum(min(a.revenue)) OVER () AS atendees_revenue
    FROM   tickets   t
    JOIN   attendees a ON a.id = t.attendee_id
    GROUP  BY t.attendee_id
    LIMIT  1;
    

    sqlfiddle

    How does it work?

    The key to understanding this is the sequence of events in the query:

    aggregate functions -> window functions -> DISTINCT -> LIMIT

    More details:

    • Best way to get result count before LIMIT was applied

    Step by step:

    1. I GROUP BY t.attendee_id - which you would normally do in a subquery.

    2. Then I sum over the counts to get the total count of tickets. Not very efficient, but forced by your requirement. The aggregate function count(*) is wrapped in the window function sum( ... ) OVER () to arrive at the not-so-common expression: sum(count(*)) OVER ().

      And sum the minimum revenue per attendee to get the sum without duplicates.

      You could also use max() or avg() instead of min() to the same effect as revenue is guaranteed to be the same for every row per attendee.

      This could be simpler if DISTINCT was allowed in window functions, but PostgreSQL has not (yet) implemented this feature. Per documentation:

      Aggregate window functions, unlike normal aggregate functions, do not allow DISTINCT or ORDER BY to be used within the function argument list.

    3. Final step is to get a single row. This could be done with DISTINCT (SQL standard) since all rows are the same. LIMIT 1 will be faster, though. Or the SQL-standard form FETCH FIRST 1 ROWS ONLY.

    0 讨论(0)
  • 2020-11-27 23:26

    What about a simple division:

     Select count(tickets.*) as tickets_count
     , sum(attendees.revenue) / count(attendees.id) as atendees_revenue
     from tickets LEFT OUTER JOIN attendees ON attendees.id = 
     tickets.attendee_id;
    

    This should handle duplicates, triplicates, etcetera.

    0 讨论(0)
  • 2020-11-27 23:31

    Previous answer is nearly correct. You just need to make distinct work well in case identical revenues. You can fix this really simple if your id has numeric type:

    SELECT
      COUNT(*) AS ticketsCount,
      SUM(DISTINCT attendees.id + attendees.revenue) - SUM(DISTINCT attendees.id) AS revenueSum
    FROM
      tickets
    LEFT JOIN attendees ON
      attendees.id = tickets.attendee_id
    
    0 讨论(0)
  • 2020-11-27 23:41

    You were actually pretty close, there's many way to do this and if I understand your question correctly this should do it :

    SELECT
       COUNT(*) AS ticketsCount,
       SUM(DISTINCT attendees.revenue) AS revenueSum
    FROM
       tickets
       LEFT JOIN attendees ON
          attendees.id = tickets.attendee_id
    
    0 讨论(0)
提交回复
热议问题