phpmysqlsqlprepare

elegant solution for multiple prepare statements


The problem I am trying to solve in a better way is to delete a folder with images that have tags. So for each image I need to delete

-the image itself

-tags of that image from three databases (img_offer, img_member, img_horses)

At the moment I get all image ids of the folder to be deleted and then iterate over these four times with the four different queries, which seems pretty inefficient.

The main problem is that as far as I know you can't have multiple prepare statements open at the same time and creating the statements new in each iteration seems also counter-intuitive.

What I think would be the best approach would be something like a multiple query prepare statement but I couldn't find anything similar so maybe someone here has an idea how to solve this in a cleaner way

My idea would be something like

$multiplePreparedStatement= "DELETE this FROM that WHERE id=?;
                             DELETE this2 FROM that2 WHERE id2=?;
                             DELETE this3 FROM that3 WHERE id3=?;";
$preparedStmt = $conn->prepare($multiplePreparedStatement);
foreach($imgArray as $imgId){
    $preparedStmt->bind_param("iii", $imgId, $imgId, $imgId);
    $preparedStmt->execute();
}
$preparedStmt->close();

But I don't think that would work as multiple SQL Queries are not supported in prepared statements or are they?

Here is my current code:

       $id=$_GET['deleteAlbum'];
       $getImages = "SELECT image_id AS id
                        FROM Images
                        WHERE folder_id = ?";
       $deleteImage="DELETE FROM Images
                        WHERE image_id=?";
       $deleteOffer = "DELETE FROM Images_Offers
                        WHERE image_id=?";
       $deleteHorse = "DELETE FROM Images_Horses
                        WHERE image_id=?";
       $deleteTeam  = "DELETE FROM Images_Team
                        WHERE image_id=?";

       //get all image ids
        $ImgStmt=$conn->prepare($getImages);
        $ImgStmt->bind_param("i", $id);
        $ImgStmt->execute();
        $ImgStmt->bind_result($id);
        $imgToDelete = array();
        while($ImgStmt->fetch()){
            array_push($imgToDelete, $id);
        }
        $ImgStmt->close();

        $stmt=$conn->prepare($deleteOffer);
        foreach ($imgToDelete as $imgId){
            $stmt->bind_param("i",$imgId);
            $stmt->execute();
        }
        $stmt->close();

        $stmt=$conn->prepare($deleteHorse);
        foreach ($imgToDelete as $imgId){
            $stmt->bind_param("i",$imgId);
            $stmt->execute();
        }
        $stmt->close();

        $stmt=$conn->prepare($deleteTeam);
        foreach ($imgToDelete as $imgId){
            $stmt->bind_param("i",$imgId);
            $stmt->execute();
        }
        $stmt->close();

        $stmt=$conn->prepare($deleteImage);
        foreach($imgToDelete as $imgId){
            unlink("../assets/img/images/img".$imgId.".jpg");
            $stmt->bind_param("i",$imgId);
            $stmt->execute();
        }
        $stmt->close();

I also had the idea of creating multiple connections but I think that might get problematic if e.g. delete an image while I still have a query iterating over images.


Solution

  • You do not have to iterate over image_id (at least not for the SQL data) at all. You can delete from the database everything associated with a particular folder_id in one go:

    DELETE Images, Images_Offers, Images_Horses, Images_Team
    FROM Images
    LEFT JOIN Images_Offers ON Images_Offers.image_id = Images.image_id
    LEFT JOIN Images_Horses ON Images_Horses.image_id = Images.image_id
    LEFT JOIN Images_Team   ON   Images_Team.image_id = Images.image_id
    WHERE folder_id = ?;
    

    Of cause, before that you should unlink the actual files.