开发者

mysql Query: Select Lastest Where Another Row With N doesn't exist

sorry about the title, I'm not sure how to even describe this, which makes it even harder to search for a solution.

I have a table which has many answers:

CREATE TABLE `answers` (
  `a_id` int(11) NOT NULL auto_increment,
  `p_id` int(11) NOT NULL default '0',
  `q_id` int(11) NOT NULL default '0',
  `user_id` int(11) NOT NULL default '0',
  `correct` int(1) NOT NULL default '0',
  `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`a_id`)
) ;

I need to select a q_id from a specific user_id and p_id where correct = 0, but only where a more recent row from the same user_id and p_id's correct field is not 1.

I can group by id, but am unsure how to eliminate groups where the top correct != 0

Thanks in advance. I've found many helpful answers here and am looking forward to contributing where I can.

EDIT: Currently the query as stands, but takes 6 secs to execute:

From both your answers I have query that works, but takes 6 secs to execute!

SELECT a.q_id FROM answers a    
JOIN (SELECT b.q_id, MAX(b.a_id) as a_id, b.corr开发者_JS百科ect
        FROM answers b  
       WHERE b.correct = 1 
         AND b.user_id = 1 
         AND b.p_id = 22
    GROUP BY b.q_id) c ON a.q_id = c.q_id 
                      AND a.a_id > c.a_id
WHERE a.correct = 0 
  AND a.user_id = 1 
  AND a.p_id = 22  
LIMIT 1

With no JOIN they take .26 secs. and .45 secs to execute How can I make it more efficient?

Is there another way to select the most recent correct = 0 row where a prev correct = 1 row does not exist?

Thanks for all your help!


use the timestamp infomation to get the latest. You can order the records according to the time.


Since you have an auto increment field a_id, you can use it to find the latest entry. Timestamp calculations are slower than primary key sorting.

SELECT a.a_id, a.q_id, a.user_id, a.p_id, a.correct, c.correct
    FROM answers a 
    JOIN (SELECT b.p_id, b.user_id, b.correct
              FROM answers b 
              ORDER BY a_id DESC
              LIMIT 1) c
        ON (a.p_id = c.p_id
        AND a.user_id = c.user_id)
    WHERE c.correct != '1' 
    AND a.correct = '0'
    AND a.user_id = '1234'
    AND a.p_id = '5678'
    ORDER BY a.a_id DESC
    LIMIT 1;

If you don't want to limit the number of results, remove the last two lines of code.


This is the method that I almost always use in these situations. It's ANSI compliant and in MS SQL Server the performance is typically much better than using subqueries. I can't speak to performance in MySQL though:

SELECT
     A1.q_id
FROM
     Answers A1
LEFT OUTER JOIN Answers A2 ON
     A2.p_id = A1.p_id AND
     A2.user_id = A1.user_id AND
     A2.timestamp > A1.timestamp AND
     A2.correct = 1
WHERE
     A1.p_id = 22 AND
     A1.user_id = 1 AND
     A1.correct = 0
     A2.a_id IS NULL   -- This can only happen if no rows were found matching the JOIN criteria

BTW, if you want "latest" then you should be looking at the timestamp and not the a_id. Although it might almost always be the case (when inserting at least) that the numbers are sequential based on time inserted, it's usually not guaranteed. This is absolutely the case in MS SQL and I'm pretty sure that it's true in MySQL as well due to transactions and potential rollbacks affecting the IDs.


This query seems to be working best. It's my edited answer, updated with ordering the a.a_id and limiting the return to one.

  SELECT a.q_id 
      FROM user_q_answers a    
      JOIN (SELECT b.user_id,
                   b.popling_id, 
             b.q_id,
                   MAX(b.a_id) as a_id
              FROM user_q_answers b  
             WHERE b.correct = 1 
          GROUP BY b.q_id, b.user_id) c ON a.q_id = c.q_id
                                       AND a.user_id = c.user_id
                                       AND a.a_id > c.a_id
     WHERE a.correct = 0 
       AND a.user_id = 101
       AND a.popling_id = 170  
    ORDER BY a.a_id DESC
    LIMIT 1

Thanks very much to OMG Ponies and Nirmal for helping me through this. Sorry if answering my own question is bad form here, but I comprised my query based on what I learned from you both.

Thanks again!!!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜