简体   繁体   中英

SQL merging rows with least amount of queries

My database system is pretty easy. I have a table with the users, and a table with 'guesses'. My site has logos, and a user can guess the name of each logo. There is a unique relation between the logo_id and the user_id . Here's the guesses table-structure:

|| id | user_id | logo_id | guess | guess_count | guessed | level | time ||

Now, when a user visits the page and isn't logged in, a user is made with the session_id and all the guesses and stuff are stored in the same structure. So the only difference is in the user -table.

Now I want the user to be able to login and keep whatever he/she just did. Of course, if the logged in account already has the logo as guessed, this shouldn't be altered. But when the logged in account has a logo as not-guessed, the guess_count of the session user should be added to the logged in user guess_count . Also the guessed should be updated. It should only do this if the time of the edit was more recent, but I think it's safe to assume that the session-guesses are more recent.

Now how I would do this, is loop through all the logos from the logged in id first where guessed = 0 , then for each result do a query again to add the guess_count and store the guessed , then remove all the ones found from the session-id, then loop through all the old ones with the session-id and change the user_id to the one of the logged-in-user. Now, this is a ton of queries, so there must be a more efficiënt way.

Any thoughts? Sorry for the wall of text & bad explanation, databases are not my best thing.

Sorry havn't used mySQL in donkey's years, but here's an example of the stored procedure in SQL Server: Hopefully someone can help with the MySQL syntax, or you can infer it from the SQL below

CREATE PROC MergeGuesses
 @UserSessionId INT,
 @UserId INT
AS

 --where the userId has already a guess for the logo update it
 UPDATE gusr
 SET gusr.guess_count = gusr.guess_count + gses.guess_count,
     gusr.guessed = gses.guessed
 FROM Guesses gusr
 JOIN Guesses gses ON gusr.logo_id = gses.logo_id
                   AND gusr.time > gses.time  -- more recent
 WHERE gusr.user_id = @UserId
 AND gses.user_id = @UserSessionId
 AND gses.guessed = 0 --not yet guessed

 --where there is no guess for the user yet - just update the userId
 UPDATE gses
 SET gses.user_id = @UserId
 FROM Guesses gses
 LEFT JOIN Guesses gusr ON gusr.logo_id = gses.logo_id
                        AND gusr.user_id = @UserId
 WHERE gses.user_id = @UserSessionId
 AND gusr.user_id = NULL -- there is no guess for the userId

 --finally delete any rows for the sessionId that are left
 DELETE FROM Guesses 
 WHERE user_id = @UserSessionId

Since I have no idea how to start stored procedures, I've just written it out in a few queries, but it's okay I guess.

$STH = $DBH->prepare("SELECT logo_id, guess_count, guessed, guess FROM guess WHERE user_id=:id GROUP BY logo_id");
$STH->bindParam(":id",$loginuser['id']);
$STH->execute();
while($row = $STH->fetch()){
    if($row['guessed'] == 0){
        $STH2 = $DBH->prepare("SELECT guess, guess_count, guessed FROM guess WHERE logo_id=:logo_id AND user_id=:id");
        $STH2->bindParam(":logo_id",$row['logo_id'],PDO::PARAM_STR,20);
        $STH2->bindParam(':id',$_SESSION['login'],PDO::PARAM_INT);
        $STH2->execute();
        $row2 = $STH2->fetch(PDO::FETCH_ASSOC);
        if($row2){
            $STH3 = $DBH->prepare("UPDATE guess SET guess_count=guess_count+:guess_count, guessed=:guessed, guess=:guess WHERE logo_id=:logo_id AND user_id=:id");
            $data = array('guess_count'=>$row2['guess_count'],'guessed'=>$row2['guessed'],'guess'=>$row2['guess'],'logo_id'=>$row['logo_id'],'id'=>$loginuser['id']);
            $STH3->execute($data);

            $STH3 = $DBH->prepare("DELETE FROM guess WHERE logo_id=:logo_id AND user_id=:id");
            $STH3->bindParam(":logo_id",$row['logo_id']);
            $STH3->bindParam(':id',$_SESSION['login']);
            $STH3->execute();
        }
    }else{
        $STH2 = $DBH->prepare("DELETE FROM guess WHERE logo_id=:logo_id AND user_id=:id");
        $STH2->bindParam(":logo_id",$row['logo_id']);
        $STH2->bindParam(':id',$_SESSION['login']);
        $STH2->execute();
    }
}
$STH = $DBH->prepare("UPDATE guess SET user_id=:login WHERE user_id=:session"); // update all entries that are new from session
$STH->bindParam(':login',$loginuser['id']);
$STH->bindParam(':session',$_SESSION['login']);
$STH->execute();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM