Select only last value using group by at mysql

后端 未结 6 691
有刺的猬
有刺的猬 2020-12-11 15:16

I have one table with data about attendance into some events. I have in the table the data of the attendance everytime the user sends new attendance, the information is like

相关标签:
6条回答
  • 2020-12-11 15:29
    SELECT id_branch_channel, id_member, attendance, timestamp, id_member 
    FROM (select * from view_event_attendance order by timestamp desc) as whatever
    WHERE id_event = 782 
    GROUP BY id_event,id_member;
    

    EDIT: This may yield better performance:

    SELECT *
    FROM (SELECT id_branch_channel, id_member, attendance, timestamp, id_member 
          FROM view_event_attendance 
          WHERE id_event = 782 
          ORDER BY timestamp desc
         ) as whatever
    GROUP BY id_event,id_member;
    

    As long as the result-set can fit into the Innodb_buffer_pool, you will not see a significant performance drop.

    0 讨论(0)
  • 2020-12-11 15:30

    Here is one option (untested):

    SELECT v.id_branch_channel, v.id_member, v.attendance, v.timestamp, v.id_member 
    FROM view_event_attendance v
        JOIN (
            SELECT id_event, id_member, MAX(attendance) maxattendance
            FROM view_event_attendance 
            GROUP BY id_event, id_member ) m ON 
                v.id_event = m.id_event AND
                v.id_member = m.id_member AND
                v.attendance = m.maxattendance
    WHERE v.id_event = 782 
    GROUP BY v.id_member;
    

    The concept is to get the MAX() of timestamp and use that field to JOIN on your view. You might not need all the fields -- really depends on your table structure. But this should get you going in the correct direction.

    0 讨论(0)
  • 2020-12-11 15:32

    I see answers with JOINS and Subquerys, but I believe a simple HAVING clause should do the trick:

    SELECT 
      id_branch_channel,
      id_member, 
      attendance, 
      timestamp,
      id_member
    FROM view_event_attendance
    WHERE id_event = 782 
    GROUP BY id_event, id_member
    HAVING MAX(timestamp) OR timestamp IS NULL;
    

    EDIT: Added a check for IS NULL if you also want to include those rows.

    EDIT 2: Is it even needed to group by id_event when you're already filtering it to 1 event?

    EDIT 3: Don't know why the downvote, this sql fiddle shows it works.

    EDIT 4: I have to apologise, @ysth is correct, the SQL Fiddle does not work correctly. I deserved the -1, but when you down vote at least explain why so I can learn something myself as well.

    The following works, but unfortunately it has a subquery again and won't perform much better than the other solutions posted here.

    SELECT 
      id_branch_channel,
      id_member, 
      attendance, 
      timestamp,
      id_member
    FROM view_event_attendance AS t1
    WHERE id_event = 782
    AND timestamp = (SELECT MAX(timestamp)
                     FROM view_event_attendance AS t2 
                     WHERE t1.id_member = t2.id_member 
                       AND t1.id_event = t2.id_event 
                     GROUP BY id_event, id_member)
    OR timestamp IS NULL
    GROUP BY id_event, id_member;
    
    0 讨论(0)
  • 2020-12-11 15:34
    SUBSTRING_INDEX(SUBSTRING_INDEX(group_concat(%requiredfield%), ',', count(*)),',',-1)
    

    This will get the last value of the 'required field' from any group_concat, if unsorted it will be the last value in the table by default.

    Could use group_concat_ws to account for possible null fields.

    0 讨论(0)
  • 2020-12-11 15:38

    Use a simple group by id_member, but select:

    substring(max(concat(from_unixtime(timestamp),attendance)) from 20) as attendance
    

    This attaches attendance to the timestamp for each row in a group, in order to be able to select the desired timestamp/attendance with max() and then extract just the attendance.

    What concat() returns is 19 characters of formatted timestamp (YYYY-mm-dd HH:MM:SS) with the attendance appended starting at character 20; the substring(... from 20) gets just the attendance from the (stringwise) maximum one for the group. You can remove the group by and just

    select concat(from_unixtime(timestamp),attendance), timestamp, attendance
    

    to get a better idea of how it uses max to get the right attendance.

    0 讨论(0)
  • 2020-12-11 15:39

    One way to do this is to use a window function and a subquery, if you add an entry to your select list as row_number() over (partition by id_member order by timestamp desc) this will resolve to a number ordering the rows by timestamp (with 1 being the oldest) grouped in each id_member group (run it if this doesn't make sense, it will be clear). You can then select from this as a subquery where the extra column = 1 which will only select the rows with the highest timestamp within each group.

    0 讨论(0)
提交回复
热议问题