SQL: check insert successful (in a task to get 8 d

2019-03-04 03:17发布

Update:

I fixed the previous problems. Now the codes are up-dated. Results are unique and IDs are right. But new problem: The amount of result rows is often less than requirement (8). Because I added CREATE UNIQUE INDEX topicid on rands (topicid); to deny the repeated inserts in SQL layer; the loop - 1 regardless the insert is denied. I am now looking for a method like: IF insert successful THEN cnt-=1. Do you know any way to do this in SQL layer? Thanks.


I have a table called topictable which contains two coulmns-topicid and topic. I want to get 8 random rows from the table without repeats. I stole the code from here and modified into getting two column results. But I have two problems with it. 1. It is not distinct; 2. the id is wrong (I catch the wrong random id somehow).

DELIMITER $$
DROP PROCEDURE IF EXISTS get_rands$$
CREATE PROCEDURE get_rands(IN cnt INT)
BEGIN
  DROP TEMPORARY TABLE IF EXISTS rands;
  CREATE TEMPORARY TABLE rands ( topicid INT ,topic VARCHAR(128) );
  CREATE UNIQUE INDEX topicid on rands (topicid);
loop_me: LOOP
    IF cnt < 1 THEN
      LEAVE loop_me;
    END IF; 
    INSERT INTO rands 
       SELECT topictable.topicid,topictable.topic
         FROM topictable 
         JOIN (SELECT (RAND()*(SELECT MAX(topictable.topicid) FROM topictable)) AS id) AS choices
        WHERE topictable.topicid >= choices.id
        LIMIT 1;
    SET cnt = cnt - 1;
  END LOOP loop_me;  
END$$
DELIMITER ;

I use the following function in php to execute the script.

    function pickrandomtopics($amountoftopics,$dbh){
try {  
    $randtable="CALL get_rands($amountoftopics)";
    $dbh->exec("$randtable");
    $topictemp = $dbh->query('SELECT * FROM rands');
    $topics = $topictemp->fetchAll(PDO::FETCH_ASSOC);
}  
catch(PDOException $e) {  
    echo $e->getMessage();  
}
return $topics;}

Thanks for your helps.


Sorry, I didn't make it clear. All the topics in this table are unique in the beginning. But they might duplicate at the end, because the function picks the row randomly from time to time, sometime it just pick a same row twice. Thanks for your help.

2条回答
Ridiculous、
2楼-- · 2019-03-04 04:02

Thank @tereško. the CONTINUE HANDLER FOR SQLSTATE '23000' catches "not unique" errors and correct cnt back by +1.

DELIMITER $$
DROP PROCEDURE IF EXISTS get_rands$$
CREATE PROCEDURE get_rands(IN cnt INT)
BEGIN
  DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET cnt = cnt + 1;
  DROP TEMPORARY TABLE IF EXISTS rands;
  CREATE TEMPORARY TABLE rands ( topicid INT UNIQUE,topic VARCHAR(128) );
loop_me: LOOP
    IF cnt < 1 THEN
      LEAVE loop_me;
    END IF; 
    INSERT INTO rands 
       SELECT topictable.topicid,topictable.topic
         FROM topictable 
         JOIN (SELECT (RAND()*(SELECT MAX(topictable.topicid) FROM topictable)) AS id) AS choices
        WHERE topictable.topicid >= choices.id
        LIMIT 1;
    SET cnt = cnt - 1;
  END LOOP loop_me;  
END$$
DELIMITER ;
查看更多
爷、活的狠高调
3楼-- · 2019-03-04 04:03

To solve one of your problem I think this might help - Using SubQuery

  • first select all unique topics
  • select 8 random topics from the returned query above

.This is just a guide line and not the actual query

 select 8 random topics from
 (
  select all unique topics
 ) 
查看更多
登录 后发表回答