MySQL: Keep the 10 most recent rows for each user












3















I have a table saving scores for a game that have 3 columns (more in practice, but it is easier for everyone this way):



userid   : the id of the user that got the score
timestamp: the time the score was gotten
score : the score itself


The goal of the query is to delete rows so we have at most 10 scores per user.We also want to keep the most recent rows. So we need to delete the older ones until we get to 10.Note that some players may have less than 10 scores.



How would I manage to do this?










share|improve this question

























  • I believe approach in answer I got in my question Query: All employee with sum of salary > 500 Can be helpful.

    – Grijesh Chauhan
    Feb 20 '14 at 11:06








  • 1





    What version of MySQL are you using?

    – Lennart
    Jun 14 '18 at 15:32
















3















I have a table saving scores for a game that have 3 columns (more in practice, but it is easier for everyone this way):



userid   : the id of the user that got the score
timestamp: the time the score was gotten
score : the score itself


The goal of the query is to delete rows so we have at most 10 scores per user.We also want to keep the most recent rows. So we need to delete the older ones until we get to 10.Note that some players may have less than 10 scores.



How would I manage to do this?










share|improve this question

























  • I believe approach in answer I got in my question Query: All employee with sum of salary > 500 Can be helpful.

    – Grijesh Chauhan
    Feb 20 '14 at 11:06








  • 1





    What version of MySQL are you using?

    – Lennart
    Jun 14 '18 at 15:32














3












3








3








I have a table saving scores for a game that have 3 columns (more in practice, but it is easier for everyone this way):



userid   : the id of the user that got the score
timestamp: the time the score was gotten
score : the score itself


The goal of the query is to delete rows so we have at most 10 scores per user.We also want to keep the most recent rows. So we need to delete the older ones until we get to 10.Note that some players may have less than 10 scores.



How would I manage to do this?










share|improve this question
















I have a table saving scores for a game that have 3 columns (more in practice, but it is easier for everyone this way):



userid   : the id of the user that got the score
timestamp: the time the score was gotten
score : the score itself


The goal of the query is to delete rows so we have at most 10 scores per user.We also want to keep the most recent rows. So we need to delete the older ones until we get to 10.Note that some players may have less than 10 scores.



How would I manage to do this?







mysql delete






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Feb 20 '14 at 5:33









Abdul Manaf

6,211105375




6,211105375










asked Feb 20 '14 at 5:16









Maxime MichelMaxime Michel

1612




1612













  • I believe approach in answer I got in my question Query: All employee with sum of salary > 500 Can be helpful.

    – Grijesh Chauhan
    Feb 20 '14 at 11:06








  • 1





    What version of MySQL are you using?

    – Lennart
    Jun 14 '18 at 15:32



















  • I believe approach in answer I got in my question Query: All employee with sum of salary > 500 Can be helpful.

    – Grijesh Chauhan
    Feb 20 '14 at 11:06








  • 1





    What version of MySQL are you using?

    – Lennart
    Jun 14 '18 at 15:32

















I believe approach in answer I got in my question Query: All employee with sum of salary > 500 Can be helpful.

– Grijesh Chauhan
Feb 20 '14 at 11:06







I believe approach in answer I got in my question Query: All employee with sum of salary > 500 Can be helpful.

– Grijesh Chauhan
Feb 20 '14 at 11:06






1




1





What version of MySQL are you using?

– Lennart
Jun 14 '18 at 15:32





What version of MySQL are you using?

– Lennart
Jun 14 '18 at 15:32










6 Answers
6






active

oldest

votes


















1














You can try below procedure first test it on local before going to production.



This consider that user has unique timestamp I have taken that as scored_at



Table Structure



show create table user_scoreG
*************************** 1. row ***************************
Table: user_score
Create Table: CREATE TABLE `user_score` (
`userid` int(11) DEFAULT NULL,
`score` int(11) DEFAULT NULL,
`scored_at` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)


Procedure



DROP PROCEDURE IF EXISTS DeleteRecords;

DELIMITER $$

CREATE PROCEDURE `DeleteRecords`()
BEGIN

DECLARE nomore_userid BOOLEAN DEFAULT FALSE;
DECLARE user_id INT;

DECLARE cursor_delete_users CURSOR FOR
SELECT userid FROM user_score GROUP BY userid HAVING COUNT(userid) > 10;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET nomore_userid = TRUE;
OPEN cursor_delete_users;

REPEAT

FETCH cursor_delete_users INTO user_id;

IF NOT nomore_userid THEN
SELECT COUNT(*) INTO @varCount FROM user_score WHERE userid = user_id;

SET @limit = @varCount - 10;

SET @varSQL = CONCAT('DROP TABLE IF EXISTS tmp_user;');
PREPARE statement FROM @varSQL;
EXECUTE statement;
DEALLOCATE PREPARE statement;

SET @varSQL = CONCAT('CREATE TABLE tmp_user SELECT * FROM user_score WHERE userid =',user_id ,' ORDER BY scored_at DESC
LIMIT 10', ',',@limit,';');

PREPARE statement FROM @varSQL;
EXECUTE statement;
DEALLOCATE PREPARE statement;

DELETE a.* FROM user_score a JOIN tmp_user b ON a.userid = b.userid and a.scored_at = b.scored_at;
END IF;

UNTIL nomore_userid
END REPEAT;


END$$

DELIMITER ;





share|improve this answer

































    1














    I found figured out an answer that works pretty well, though if you have a lot of users it may take some time to execute. I have yet to do any time testing with it. It also assumes you have an id field that uniquely identifies each score.



    The way it works is in the inner query it finds up to the 10 most recent scores. Then deletes everything not returned by the inner query.



    DELETE FROM score
    WHERE id NOT IN (
    SELECT id
    FROM (
    SELECT *
    FROM score s1
    WHERE (
    SELECT COUNT(*)
    FROM score s2
    WHERE s1.userid = s2.userid
    AND s1.timestamp <= s2.timestamp
    ) <= 10 --Keep this many records
    ) foo
    );





    share|improve this answer


























    • I don't think that the query fits the question.

      – ypercubeᵀᴹ
      Oct 12 '14 at 1:25











    • You are right. I edited it to be correct. That's what I get for blindly replacing names. My solution needs a unique id column.

      – Lukiahas
      Oct 15 '14 at 19:12



















    0














    Rank the rows by timestamp, and delete any whose rank is greater than 10.






    share|improve this answer































      0














      It's difficult to do it in one sentence because MySQL doesn't allows the LIMIT statement in subqueries, that's why we need a temp folder.



      We need a temp table to get the oldest timestamp we will maintain



      CREATE TABLE i_am_a_temp_folder (
      `userid` INT(10) UNSIGNED NOT NULL,
      `timestamp` DATETIME NOT NULL
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8;


      Getting the oldest timestamp (number 10) of the users which have 10 or more scores



      INSERT INTO i_am_a_temp_folder (userid, `timestamp`)
      select c1.userid, c1.`timestamp`
      from score_table c1
      join score_table c2
      on c1.userid= c2.useridand c1.`timestamp` <= c2.`timestamp`
      group by c1.userid, c1.`timestamp`
      having count(*) = 10;


      Only on the users with more than 10 scores we will delete the older scores



      DELETE c.* FROM score_table c
      INNER JOIN i_am_a_temp_folder t
      ON c.userid= t.userid
      AND c.`timestamp` < t.`timestamp`


      Deleting the temp table



      drop table i_am_a_temp_folder;





      share|improve this answer































        0














        Table structure, example:



        row_id  int(11) Auto Increment   
        userid int(11)
        score int(11)
        updated_at timestamp [CURRENT_TIMESTAMP]


        First: Insert a new record



        INSERT INTO `user_score` (`userid`, `score`)
        VALUES ('50', '80');


        Second: Delete all rows start from position 10th, sorted by updated_at descending



        DELETE FROM user_score 
        WHERE row_id < ( SELECT row_id FROM
        (SELECT * FROM user_score
        ORDER BY updated_at DESC
        LIMIT 9,1) AS us)


        If we want too keep 10 records, the limit offset is 9





        share








        New contributor




        Jopie is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.




























          -4














          Delete from table where id not in ( select top 10 Id from table)






          share|improve this answer
























          • Only if IDs are in ascending order of age.

            – Colin 't Hart
            Feb 20 '14 at 12:11






          • 5





            This answer has several failures. It uses TOP (which is an SQL-Server thing, not MySQL). It uses TOP without ORDER BY which would result in indeterminate results. It doesn't take into account the timestamp, as specified by the OP. And lastly it would leave only 10 rows in the table while the OP wants to leave 10 rows per user.

            – ypercubeᵀᴹ
            Feb 20 '14 at 12:16











          Your Answer








          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "182"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f59238%2fmysql-keep-the-10-most-recent-rows-for-each-user%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          6 Answers
          6






          active

          oldest

          votes








          6 Answers
          6






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          You can try below procedure first test it on local before going to production.



          This consider that user has unique timestamp I have taken that as scored_at



          Table Structure



          show create table user_scoreG
          *************************** 1. row ***************************
          Table: user_score
          Create Table: CREATE TABLE `user_score` (
          `userid` int(11) DEFAULT NULL,
          `score` int(11) DEFAULT NULL,
          `scored_at` datetime DEFAULT NULL
          ) ENGINE=InnoDB DEFAULT CHARSET=utf8
          1 row in set (0.00 sec)


          Procedure



          DROP PROCEDURE IF EXISTS DeleteRecords;

          DELIMITER $$

          CREATE PROCEDURE `DeleteRecords`()
          BEGIN

          DECLARE nomore_userid BOOLEAN DEFAULT FALSE;
          DECLARE user_id INT;

          DECLARE cursor_delete_users CURSOR FOR
          SELECT userid FROM user_score GROUP BY userid HAVING COUNT(userid) > 10;

          DECLARE CONTINUE HANDLER FOR NOT FOUND SET nomore_userid = TRUE;
          OPEN cursor_delete_users;

          REPEAT

          FETCH cursor_delete_users INTO user_id;

          IF NOT nomore_userid THEN
          SELECT COUNT(*) INTO @varCount FROM user_score WHERE userid = user_id;

          SET @limit = @varCount - 10;

          SET @varSQL = CONCAT('DROP TABLE IF EXISTS tmp_user;');
          PREPARE statement FROM @varSQL;
          EXECUTE statement;
          DEALLOCATE PREPARE statement;

          SET @varSQL = CONCAT('CREATE TABLE tmp_user SELECT * FROM user_score WHERE userid =',user_id ,' ORDER BY scored_at DESC
          LIMIT 10', ',',@limit,';');

          PREPARE statement FROM @varSQL;
          EXECUTE statement;
          DEALLOCATE PREPARE statement;

          DELETE a.* FROM user_score a JOIN tmp_user b ON a.userid = b.userid and a.scored_at = b.scored_at;
          END IF;

          UNTIL nomore_userid
          END REPEAT;


          END$$

          DELIMITER ;





          share|improve this answer






























            1














            You can try below procedure first test it on local before going to production.



            This consider that user has unique timestamp I have taken that as scored_at



            Table Structure



            show create table user_scoreG
            *************************** 1. row ***************************
            Table: user_score
            Create Table: CREATE TABLE `user_score` (
            `userid` int(11) DEFAULT NULL,
            `score` int(11) DEFAULT NULL,
            `scored_at` datetime DEFAULT NULL
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8
            1 row in set (0.00 sec)


            Procedure



            DROP PROCEDURE IF EXISTS DeleteRecords;

            DELIMITER $$

            CREATE PROCEDURE `DeleteRecords`()
            BEGIN

            DECLARE nomore_userid BOOLEAN DEFAULT FALSE;
            DECLARE user_id INT;

            DECLARE cursor_delete_users CURSOR FOR
            SELECT userid FROM user_score GROUP BY userid HAVING COUNT(userid) > 10;

            DECLARE CONTINUE HANDLER FOR NOT FOUND SET nomore_userid = TRUE;
            OPEN cursor_delete_users;

            REPEAT

            FETCH cursor_delete_users INTO user_id;

            IF NOT nomore_userid THEN
            SELECT COUNT(*) INTO @varCount FROM user_score WHERE userid = user_id;

            SET @limit = @varCount - 10;

            SET @varSQL = CONCAT('DROP TABLE IF EXISTS tmp_user;');
            PREPARE statement FROM @varSQL;
            EXECUTE statement;
            DEALLOCATE PREPARE statement;

            SET @varSQL = CONCAT('CREATE TABLE tmp_user SELECT * FROM user_score WHERE userid =',user_id ,' ORDER BY scored_at DESC
            LIMIT 10', ',',@limit,';');

            PREPARE statement FROM @varSQL;
            EXECUTE statement;
            DEALLOCATE PREPARE statement;

            DELETE a.* FROM user_score a JOIN tmp_user b ON a.userid = b.userid and a.scored_at = b.scored_at;
            END IF;

            UNTIL nomore_userid
            END REPEAT;


            END$$

            DELIMITER ;





            share|improve this answer




























              1












              1








              1







              You can try below procedure first test it on local before going to production.



              This consider that user has unique timestamp I have taken that as scored_at



              Table Structure



              show create table user_scoreG
              *************************** 1. row ***************************
              Table: user_score
              Create Table: CREATE TABLE `user_score` (
              `userid` int(11) DEFAULT NULL,
              `score` int(11) DEFAULT NULL,
              `scored_at` datetime DEFAULT NULL
              ) ENGINE=InnoDB DEFAULT CHARSET=utf8
              1 row in set (0.00 sec)


              Procedure



              DROP PROCEDURE IF EXISTS DeleteRecords;

              DELIMITER $$

              CREATE PROCEDURE `DeleteRecords`()
              BEGIN

              DECLARE nomore_userid BOOLEAN DEFAULT FALSE;
              DECLARE user_id INT;

              DECLARE cursor_delete_users CURSOR FOR
              SELECT userid FROM user_score GROUP BY userid HAVING COUNT(userid) > 10;

              DECLARE CONTINUE HANDLER FOR NOT FOUND SET nomore_userid = TRUE;
              OPEN cursor_delete_users;

              REPEAT

              FETCH cursor_delete_users INTO user_id;

              IF NOT nomore_userid THEN
              SELECT COUNT(*) INTO @varCount FROM user_score WHERE userid = user_id;

              SET @limit = @varCount - 10;

              SET @varSQL = CONCAT('DROP TABLE IF EXISTS tmp_user;');
              PREPARE statement FROM @varSQL;
              EXECUTE statement;
              DEALLOCATE PREPARE statement;

              SET @varSQL = CONCAT('CREATE TABLE tmp_user SELECT * FROM user_score WHERE userid =',user_id ,' ORDER BY scored_at DESC
              LIMIT 10', ',',@limit,';');

              PREPARE statement FROM @varSQL;
              EXECUTE statement;
              DEALLOCATE PREPARE statement;

              DELETE a.* FROM user_score a JOIN tmp_user b ON a.userid = b.userid and a.scored_at = b.scored_at;
              END IF;

              UNTIL nomore_userid
              END REPEAT;


              END$$

              DELIMITER ;





              share|improve this answer















              You can try below procedure first test it on local before going to production.



              This consider that user has unique timestamp I have taken that as scored_at



              Table Structure



              show create table user_scoreG
              *************************** 1. row ***************************
              Table: user_score
              Create Table: CREATE TABLE `user_score` (
              `userid` int(11) DEFAULT NULL,
              `score` int(11) DEFAULT NULL,
              `scored_at` datetime DEFAULT NULL
              ) ENGINE=InnoDB DEFAULT CHARSET=utf8
              1 row in set (0.00 sec)


              Procedure



              DROP PROCEDURE IF EXISTS DeleteRecords;

              DELIMITER $$

              CREATE PROCEDURE `DeleteRecords`()
              BEGIN

              DECLARE nomore_userid BOOLEAN DEFAULT FALSE;
              DECLARE user_id INT;

              DECLARE cursor_delete_users CURSOR FOR
              SELECT userid FROM user_score GROUP BY userid HAVING COUNT(userid) > 10;

              DECLARE CONTINUE HANDLER FOR NOT FOUND SET nomore_userid = TRUE;
              OPEN cursor_delete_users;

              REPEAT

              FETCH cursor_delete_users INTO user_id;

              IF NOT nomore_userid THEN
              SELECT COUNT(*) INTO @varCount FROM user_score WHERE userid = user_id;

              SET @limit = @varCount - 10;

              SET @varSQL = CONCAT('DROP TABLE IF EXISTS tmp_user;');
              PREPARE statement FROM @varSQL;
              EXECUTE statement;
              DEALLOCATE PREPARE statement;

              SET @varSQL = CONCAT('CREATE TABLE tmp_user SELECT * FROM user_score WHERE userid =',user_id ,' ORDER BY scored_at DESC
              LIMIT 10', ',',@limit,';');

              PREPARE statement FROM @varSQL;
              EXECUTE statement;
              DEALLOCATE PREPARE statement;

              DELETE a.* FROM user_score a JOIN tmp_user b ON a.userid = b.userid and a.scored_at = b.scored_at;
              END IF;

              UNTIL nomore_userid
              END REPEAT;


              END$$

              DELIMITER ;






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Feb 20 '14 at 6:46

























              answered Feb 20 '14 at 6:37









              Abdul ManafAbdul Manaf

              6,211105375




              6,211105375

























                  1














                  I found figured out an answer that works pretty well, though if you have a lot of users it may take some time to execute. I have yet to do any time testing with it. It also assumes you have an id field that uniquely identifies each score.



                  The way it works is in the inner query it finds up to the 10 most recent scores. Then deletes everything not returned by the inner query.



                  DELETE FROM score
                  WHERE id NOT IN (
                  SELECT id
                  FROM (
                  SELECT *
                  FROM score s1
                  WHERE (
                  SELECT COUNT(*)
                  FROM score s2
                  WHERE s1.userid = s2.userid
                  AND s1.timestamp <= s2.timestamp
                  ) <= 10 --Keep this many records
                  ) foo
                  );





                  share|improve this answer


























                  • I don't think that the query fits the question.

                    – ypercubeᵀᴹ
                    Oct 12 '14 at 1:25











                  • You are right. I edited it to be correct. That's what I get for blindly replacing names. My solution needs a unique id column.

                    – Lukiahas
                    Oct 15 '14 at 19:12
















                  1














                  I found figured out an answer that works pretty well, though if you have a lot of users it may take some time to execute. I have yet to do any time testing with it. It also assumes you have an id field that uniquely identifies each score.



                  The way it works is in the inner query it finds up to the 10 most recent scores. Then deletes everything not returned by the inner query.



                  DELETE FROM score
                  WHERE id NOT IN (
                  SELECT id
                  FROM (
                  SELECT *
                  FROM score s1
                  WHERE (
                  SELECT COUNT(*)
                  FROM score s2
                  WHERE s1.userid = s2.userid
                  AND s1.timestamp <= s2.timestamp
                  ) <= 10 --Keep this many records
                  ) foo
                  );





                  share|improve this answer


























                  • I don't think that the query fits the question.

                    – ypercubeᵀᴹ
                    Oct 12 '14 at 1:25











                  • You are right. I edited it to be correct. That's what I get for blindly replacing names. My solution needs a unique id column.

                    – Lukiahas
                    Oct 15 '14 at 19:12














                  1












                  1








                  1







                  I found figured out an answer that works pretty well, though if you have a lot of users it may take some time to execute. I have yet to do any time testing with it. It also assumes you have an id field that uniquely identifies each score.



                  The way it works is in the inner query it finds up to the 10 most recent scores. Then deletes everything not returned by the inner query.



                  DELETE FROM score
                  WHERE id NOT IN (
                  SELECT id
                  FROM (
                  SELECT *
                  FROM score s1
                  WHERE (
                  SELECT COUNT(*)
                  FROM score s2
                  WHERE s1.userid = s2.userid
                  AND s1.timestamp <= s2.timestamp
                  ) <= 10 --Keep this many records
                  ) foo
                  );





                  share|improve this answer















                  I found figured out an answer that works pretty well, though if you have a lot of users it may take some time to execute. I have yet to do any time testing with it. It also assumes you have an id field that uniquely identifies each score.



                  The way it works is in the inner query it finds up to the 10 most recent scores. Then deletes everything not returned by the inner query.



                  DELETE FROM score
                  WHERE id NOT IN (
                  SELECT id
                  FROM (
                  SELECT *
                  FROM score s1
                  WHERE (
                  SELECT COUNT(*)
                  FROM score s2
                  WHERE s1.userid = s2.userid
                  AND s1.timestamp <= s2.timestamp
                  ) <= 10 --Keep this many records
                  ) foo
                  );






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Oct 15 '14 at 19:11

























                  answered Oct 11 '14 at 21:49









                  LukiahasLukiahas

                  113




                  113













                  • I don't think that the query fits the question.

                    – ypercubeᵀᴹ
                    Oct 12 '14 at 1:25











                  • You are right. I edited it to be correct. That's what I get for blindly replacing names. My solution needs a unique id column.

                    – Lukiahas
                    Oct 15 '14 at 19:12



















                  • I don't think that the query fits the question.

                    – ypercubeᵀᴹ
                    Oct 12 '14 at 1:25











                  • You are right. I edited it to be correct. That's what I get for blindly replacing names. My solution needs a unique id column.

                    – Lukiahas
                    Oct 15 '14 at 19:12

















                  I don't think that the query fits the question.

                  – ypercubeᵀᴹ
                  Oct 12 '14 at 1:25





                  I don't think that the query fits the question.

                  – ypercubeᵀᴹ
                  Oct 12 '14 at 1:25













                  You are right. I edited it to be correct. That's what I get for blindly replacing names. My solution needs a unique id column.

                  – Lukiahas
                  Oct 15 '14 at 19:12





                  You are right. I edited it to be correct. That's what I get for blindly replacing names. My solution needs a unique id column.

                  – Lukiahas
                  Oct 15 '14 at 19:12











                  0














                  Rank the rows by timestamp, and delete any whose rank is greater than 10.






                  share|improve this answer




























                    0














                    Rank the rows by timestamp, and delete any whose rank is greater than 10.






                    share|improve this answer


























                      0












                      0








                      0







                      Rank the rows by timestamp, and delete any whose rank is greater than 10.






                      share|improve this answer













                      Rank the rows by timestamp, and delete any whose rank is greater than 10.







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Feb 20 '14 at 6:13









                      James K. LowdenJames K. Lowden

                      61234




                      61234























                          0














                          It's difficult to do it in one sentence because MySQL doesn't allows the LIMIT statement in subqueries, that's why we need a temp folder.



                          We need a temp table to get the oldest timestamp we will maintain



                          CREATE TABLE i_am_a_temp_folder (
                          `userid` INT(10) UNSIGNED NOT NULL,
                          `timestamp` DATETIME NOT NULL
                          ) ENGINE=InnoDB DEFAULT CHARSET=utf8;


                          Getting the oldest timestamp (number 10) of the users which have 10 or more scores



                          INSERT INTO i_am_a_temp_folder (userid, `timestamp`)
                          select c1.userid, c1.`timestamp`
                          from score_table c1
                          join score_table c2
                          on c1.userid= c2.useridand c1.`timestamp` <= c2.`timestamp`
                          group by c1.userid, c1.`timestamp`
                          having count(*) = 10;


                          Only on the users with more than 10 scores we will delete the older scores



                          DELETE c.* FROM score_table c
                          INNER JOIN i_am_a_temp_folder t
                          ON c.userid= t.userid
                          AND c.`timestamp` < t.`timestamp`


                          Deleting the temp table



                          drop table i_am_a_temp_folder;





                          share|improve this answer




























                            0














                            It's difficult to do it in one sentence because MySQL doesn't allows the LIMIT statement in subqueries, that's why we need a temp folder.



                            We need a temp table to get the oldest timestamp we will maintain



                            CREATE TABLE i_am_a_temp_folder (
                            `userid` INT(10) UNSIGNED NOT NULL,
                            `timestamp` DATETIME NOT NULL
                            ) ENGINE=InnoDB DEFAULT CHARSET=utf8;


                            Getting the oldest timestamp (number 10) of the users which have 10 or more scores



                            INSERT INTO i_am_a_temp_folder (userid, `timestamp`)
                            select c1.userid, c1.`timestamp`
                            from score_table c1
                            join score_table c2
                            on c1.userid= c2.useridand c1.`timestamp` <= c2.`timestamp`
                            group by c1.userid, c1.`timestamp`
                            having count(*) = 10;


                            Only on the users with more than 10 scores we will delete the older scores



                            DELETE c.* FROM score_table c
                            INNER JOIN i_am_a_temp_folder t
                            ON c.userid= t.userid
                            AND c.`timestamp` < t.`timestamp`


                            Deleting the temp table



                            drop table i_am_a_temp_folder;





                            share|improve this answer


























                              0












                              0








                              0







                              It's difficult to do it in one sentence because MySQL doesn't allows the LIMIT statement in subqueries, that's why we need a temp folder.



                              We need a temp table to get the oldest timestamp we will maintain



                              CREATE TABLE i_am_a_temp_folder (
                              `userid` INT(10) UNSIGNED NOT NULL,
                              `timestamp` DATETIME NOT NULL
                              ) ENGINE=InnoDB DEFAULT CHARSET=utf8;


                              Getting the oldest timestamp (number 10) of the users which have 10 or more scores



                              INSERT INTO i_am_a_temp_folder (userid, `timestamp`)
                              select c1.userid, c1.`timestamp`
                              from score_table c1
                              join score_table c2
                              on c1.userid= c2.useridand c1.`timestamp` <= c2.`timestamp`
                              group by c1.userid, c1.`timestamp`
                              having count(*) = 10;


                              Only on the users with more than 10 scores we will delete the older scores



                              DELETE c.* FROM score_table c
                              INNER JOIN i_am_a_temp_folder t
                              ON c.userid= t.userid
                              AND c.`timestamp` < t.`timestamp`


                              Deleting the temp table



                              drop table i_am_a_temp_folder;





                              share|improve this answer













                              It's difficult to do it in one sentence because MySQL doesn't allows the LIMIT statement in subqueries, that's why we need a temp folder.



                              We need a temp table to get the oldest timestamp we will maintain



                              CREATE TABLE i_am_a_temp_folder (
                              `userid` INT(10) UNSIGNED NOT NULL,
                              `timestamp` DATETIME NOT NULL
                              ) ENGINE=InnoDB DEFAULT CHARSET=utf8;


                              Getting the oldest timestamp (number 10) of the users which have 10 or more scores



                              INSERT INTO i_am_a_temp_folder (userid, `timestamp`)
                              select c1.userid, c1.`timestamp`
                              from score_table c1
                              join score_table c2
                              on c1.userid= c2.useridand c1.`timestamp` <= c2.`timestamp`
                              group by c1.userid, c1.`timestamp`
                              having count(*) = 10;


                              Only on the users with more than 10 scores we will delete the older scores



                              DELETE c.* FROM score_table c
                              INNER JOIN i_am_a_temp_folder t
                              ON c.userid= t.userid
                              AND c.`timestamp` < t.`timestamp`


                              Deleting the temp table



                              drop table i_am_a_temp_folder;






                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Jun 14 '18 at 14:21









                              NetViciousNetVicious

                              1012




                              1012























                                  0














                                  Table structure, example:



                                  row_id  int(11) Auto Increment   
                                  userid int(11)
                                  score int(11)
                                  updated_at timestamp [CURRENT_TIMESTAMP]


                                  First: Insert a new record



                                  INSERT INTO `user_score` (`userid`, `score`)
                                  VALUES ('50', '80');


                                  Second: Delete all rows start from position 10th, sorted by updated_at descending



                                  DELETE FROM user_score 
                                  WHERE row_id < ( SELECT row_id FROM
                                  (SELECT * FROM user_score
                                  ORDER BY updated_at DESC
                                  LIMIT 9,1) AS us)


                                  If we want too keep 10 records, the limit offset is 9





                                  share








                                  New contributor




                                  Jopie is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                  Check out our Code of Conduct.

























                                    0














                                    Table structure, example:



                                    row_id  int(11) Auto Increment   
                                    userid int(11)
                                    score int(11)
                                    updated_at timestamp [CURRENT_TIMESTAMP]


                                    First: Insert a new record



                                    INSERT INTO `user_score` (`userid`, `score`)
                                    VALUES ('50', '80');


                                    Second: Delete all rows start from position 10th, sorted by updated_at descending



                                    DELETE FROM user_score 
                                    WHERE row_id < ( SELECT row_id FROM
                                    (SELECT * FROM user_score
                                    ORDER BY updated_at DESC
                                    LIMIT 9,1) AS us)


                                    If we want too keep 10 records, the limit offset is 9





                                    share








                                    New contributor




                                    Jopie is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                    Check out our Code of Conduct.























                                      0












                                      0








                                      0







                                      Table structure, example:



                                      row_id  int(11) Auto Increment   
                                      userid int(11)
                                      score int(11)
                                      updated_at timestamp [CURRENT_TIMESTAMP]


                                      First: Insert a new record



                                      INSERT INTO `user_score` (`userid`, `score`)
                                      VALUES ('50', '80');


                                      Second: Delete all rows start from position 10th, sorted by updated_at descending



                                      DELETE FROM user_score 
                                      WHERE row_id < ( SELECT row_id FROM
                                      (SELECT * FROM user_score
                                      ORDER BY updated_at DESC
                                      LIMIT 9,1) AS us)


                                      If we want too keep 10 records, the limit offset is 9





                                      share








                                      New contributor




                                      Jopie is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.










                                      Table structure, example:



                                      row_id  int(11) Auto Increment   
                                      userid int(11)
                                      score int(11)
                                      updated_at timestamp [CURRENT_TIMESTAMP]


                                      First: Insert a new record



                                      INSERT INTO `user_score` (`userid`, `score`)
                                      VALUES ('50', '80');


                                      Second: Delete all rows start from position 10th, sorted by updated_at descending



                                      DELETE FROM user_score 
                                      WHERE row_id < ( SELECT row_id FROM
                                      (SELECT * FROM user_score
                                      ORDER BY updated_at DESC
                                      LIMIT 9,1) AS us)


                                      If we want too keep 10 records, the limit offset is 9






                                      share








                                      New contributor




                                      Jopie is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.








                                      share


                                      share






                                      New contributor




                                      Jopie is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.









                                      answered 5 mins ago









                                      JopieJopie

                                      11




                                      11




                                      New contributor




                                      Jopie is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.





                                      New contributor





                                      Jopie is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.






                                      Jopie is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.























                                          -4














                                          Delete from table where id not in ( select top 10 Id from table)






                                          share|improve this answer
























                                          • Only if IDs are in ascending order of age.

                                            – Colin 't Hart
                                            Feb 20 '14 at 12:11






                                          • 5





                                            This answer has several failures. It uses TOP (which is an SQL-Server thing, not MySQL). It uses TOP without ORDER BY which would result in indeterminate results. It doesn't take into account the timestamp, as specified by the OP. And lastly it would leave only 10 rows in the table while the OP wants to leave 10 rows per user.

                                            – ypercubeᵀᴹ
                                            Feb 20 '14 at 12:16
















                                          -4














                                          Delete from table where id not in ( select top 10 Id from table)






                                          share|improve this answer
























                                          • Only if IDs are in ascending order of age.

                                            – Colin 't Hart
                                            Feb 20 '14 at 12:11






                                          • 5





                                            This answer has several failures. It uses TOP (which is an SQL-Server thing, not MySQL). It uses TOP without ORDER BY which would result in indeterminate results. It doesn't take into account the timestamp, as specified by the OP. And lastly it would leave only 10 rows in the table while the OP wants to leave 10 rows per user.

                                            – ypercubeᵀᴹ
                                            Feb 20 '14 at 12:16














                                          -4












                                          -4








                                          -4







                                          Delete from table where id not in ( select top 10 Id from table)






                                          share|improve this answer













                                          Delete from table where id not in ( select top 10 Id from table)







                                          share|improve this answer












                                          share|improve this answer



                                          share|improve this answer










                                          answered Feb 20 '14 at 10:36









                                          user34559user34559

                                          1




                                          1













                                          • Only if IDs are in ascending order of age.

                                            – Colin 't Hart
                                            Feb 20 '14 at 12:11






                                          • 5





                                            This answer has several failures. It uses TOP (which is an SQL-Server thing, not MySQL). It uses TOP without ORDER BY which would result in indeterminate results. It doesn't take into account the timestamp, as specified by the OP. And lastly it would leave only 10 rows in the table while the OP wants to leave 10 rows per user.

                                            – ypercubeᵀᴹ
                                            Feb 20 '14 at 12:16



















                                          • Only if IDs are in ascending order of age.

                                            – Colin 't Hart
                                            Feb 20 '14 at 12:11






                                          • 5





                                            This answer has several failures. It uses TOP (which is an SQL-Server thing, not MySQL). It uses TOP without ORDER BY which would result in indeterminate results. It doesn't take into account the timestamp, as specified by the OP. And lastly it would leave only 10 rows in the table while the OP wants to leave 10 rows per user.

                                            – ypercubeᵀᴹ
                                            Feb 20 '14 at 12:16

















                                          Only if IDs are in ascending order of age.

                                          – Colin 't Hart
                                          Feb 20 '14 at 12:11





                                          Only if IDs are in ascending order of age.

                                          – Colin 't Hart
                                          Feb 20 '14 at 12:11




                                          5




                                          5





                                          This answer has several failures. It uses TOP (which is an SQL-Server thing, not MySQL). It uses TOP without ORDER BY which would result in indeterminate results. It doesn't take into account the timestamp, as specified by the OP. And lastly it would leave only 10 rows in the table while the OP wants to leave 10 rows per user.

                                          – ypercubeᵀᴹ
                                          Feb 20 '14 at 12:16





                                          This answer has several failures. It uses TOP (which is an SQL-Server thing, not MySQL). It uses TOP without ORDER BY which would result in indeterminate results. It doesn't take into account the timestamp, as specified by the OP. And lastly it would leave only 10 rows in the table while the OP wants to leave 10 rows per user.

                                          – ypercubeᵀᴹ
                                          Feb 20 '14 at 12:16


















                                          draft saved

                                          draft discarded




















































                                          Thanks for contributing an answer to Database Administrators Stack Exchange!


                                          • Please be sure to answer the question. Provide details and share your research!

                                          But avoid



                                          • Asking for help, clarification, or responding to other answers.

                                          • Making statements based on opinion; back them up with references or personal experience.


                                          To learn more, see our tips on writing great answers.




                                          draft saved


                                          draft discarded














                                          StackExchange.ready(
                                          function () {
                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f59238%2fmysql-keep-the-10-most-recent-rows-for-each-user%23new-answer', 'question_page');
                                          }
                                          );

                                          Post as a guest















                                          Required, but never shown





















































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown

































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown







                                          Popular posts from this blog

                                          SQL Server 17 - Attemping to backup to remote NAS but Access is denied

                                          Always On Availability groups resolving state after failover - Remote harden of transaction...

                                          Restoring from pg_dump with foreign key constraints