web-dev-qa-db-fra.com

Problème lors de la mise à jour de trois tables liées les unes aux autres

J'essaie de mettre à jour trois tables dans ma base de données qui sont liées les unes aux autres.

Mes tables sont installées comme ceci:

des modèles

id
title
id_company

questioncat

id
title
ordering
tid (id of templates)

des questions

id
question
catid (id of questioncat)
ordering

templates contient le nom de ma liste de questions, questioncat contient toutes les catégories de ma liste et questions contient toutes les questions appartenant à une catégorie.

Insérer ces données fonctionne bien, je le fais comme ceci:

D'abord, mon script PHP obtient un tableau qui ressemble par exemple à ceci:

Array
(
    [0] => Array
        (
            [name] => lijsttitle
            [value] => Lijst nieuw
        )

    [1] => Array
        (
            [name] => category[]
            [value] => cat1
        )

    [2] => Array
        (
            [name] => sortorder
            [value] => 1
        )

    [3] => Array
        (
            [name] => question[]
            [value] => q1
        )

    [4] => Array
        (
            [name] => category[]
            [value] => cat2
        )

    [5] => Array
        (
            [name] => sortorder
            [value] => 2
        )

    [6] => Array
        (
            [name] => question[]
            [value] => q1
        )

)

Je vérifie si la liste existe déjà comme ceci:

$check = '
SELECT *
FROM templates
WHERE title = "'.$conn->real_escape_string($title["value"]).'"';
$checkcon = $conn->query($check);
$check = $checkcon->fetch_assoc();
// If there is more than 1 result, update data instead of inserting
if($checkcon->num_rows > 0){

// Else insert data as new list
}else{
    // Insert template title and companyid
    $inserttemplate = '
    INSERT INTO templates (title, id_company) VALUES ("'.$conn->real_escape_string($title["value"]).'","'.$conn->real_escape_string($companyid).'")';
    $inserttemplatecon = $conn->query($inserttemplate);
    $lastinserted = $conn->inserted_id();

    $currCat = '';
    $sortorder = '';

    foreach($arr as $a) {
      $val = $a['value'];
      // handle category
      if($a['name'] == 'category[]') {
        // save cat name
        $currCat = $val;
        // init questions array
        $store[$currCat] = [];
      }else if($a['name'] == 'sortorder') {
            $sortorder = $val;
        $store[$currCat]['sortorder'] = $val;
      }else {
        // add question to question array
        $store[$currCat]['question'][] = $val;
      }
    }

    array_shift($store);
    // $key is de waarde van de categorie, $lijst is een array met alles onder de categorie
    foreach($store as $keycat => $lijst){
        $sortorder = $lijst['sortorder'];

        $insertcats = '
        INSERT INTO questioncat (title, tid, ordering) VALUES ("'.$conn->real_escape_string($keycat).'", "'.$conn->real_escape_string($lastinserted).'", "'.$conn->real_escape_string($sortorder).'")';
        $insertcatscon = $conn->query($insertcats);
        $lastinserted1 = $conn->inserted_id();

        $questionarr = $lijst['question'];

            foreach($questionarr as $q){
                $insertquestions = '
                INSERT INTO questions (question, catid) VALUES ("'.$conn->real_escape_string($q).'", "'.$conn->real_escape_string($lastinserted1).'")';
                $insertquestionscon = $conn->query($insertquestions);
            }
    }

    echo 'Uw lijst is toegevoegd';
}

S'il y a 0 résultat, la liste n'existe pas et est ajoutée à ma base de données, ce qui fonctionne bien. S'il y a plus d'un résultat, cela signifie que la liste existe déjà et doit être mise à jour.

C'est là que je commence à avoir des problèmes.

Puis-je mettre à jour les trois tables en une requête? 

J'ai d'abord essayé de mettre à jour uniquement les noms de catégorie avec le code suivant dans mon instruction if (celle où je vérifie si une liste de modèles existe déjà):

foreach($arr as $a) {
    $val = $a['value'];
    // handle category
    if($a['name'] == 'category[]') {
        // save cat name
        $currCat = $val;
        // init questions array
        $store[$currCat] = [];
    }else if($a['name'] == 'sortorder') {
        $sortorder = $val;
        $store[$currCat]['sortorder'] = $val;
    }else {
        // add question to question array
        $store[$currCat]['question'][] = $val;
    }

    $updatetemplate = '
    UPDATE questioncat c
    INNER JOIN templates t
    ON c.tid = t.id
    SET t.title = "'.$conn->real_escape_string($title["value"]).'",
    c.title = "'.$conn->real_escape_string($currCat).'",
    c.ordering = "'.$conn->real_escape_string($sortorder).'"
    WHERE t.title = "'.$conn->real_escape_string($getcats['title']).'"
    AND c.id = "'.$conn->real_escape_string($getcats["id"]).'"';
    $updatetemplatecon = $conn->query($updatetemplate);
    echo 'Uw lijst is gewijzigd.';
}

Mais tous les titres de catégories sont les mêmes et l'ordre est identique.

Est-il possible de mettre à jour les trois tables en une requête? Il y a essentiellement trois niveaux, Modèle - Catégories sous le modèle - Questions sous une catégorie. Est-ce possible et si oui, comment?

5
twan

Vous voudrez peut-être commencer à chercher des procédures PL/SQL, elles peuvent vous faire économiser beaucoup de code et de sécurité.

BRIEFING:

Lorsqu'un événement se produit dans la 1ère table, il peut exécuter plusieurs événements sur la base de données. L’événement peut être (ON DELETE, ON UPDATE ou ON INSERT) avec les conditions AFTER et BEFORE.

Déclencheurs PL/SQL: Source

DÉFINITION

Les déclencheurs sont des programmes stockés, qui sont automatiquement exécutés ou déclenchés lorsque certains événements se produisent. 

Quant à la syntaxe, elle varie un peu en fonction du SGBD que vous utilisez ... J'espère que mon explication est bonne.

4
lagripe

Pour mettre à jour trois tables en même temps, vous devez le faire en une seule transaction de base de données.

Si vous avez des déclencheurs (ON UPDATE/DELETE/INSERT) sur les tables qui doivent être exécutées, certains moteurs de base de données, comme PostgreSQL, permettent de reporter le moment d'exécution des déclencheurs . Si le déclencheur est différé, il sera exécuté immédiatement après la validation de la transaction. Grâce à elle, vous pourrez même mettre à jour tous les types de clé (primaire, étrangère, unique, complexe, etc.).

0
Marek Malbrandt

Essayer de mettre à jour avec une seule requête ne simplifie pas le processus. Ce serait une requête de mise à jour très complexe. Et toujours vous avez besoin d’un moyen d’identifier d’une manière ou d’une autre les lignes "enfants" (catégorie, question) pour chaque "parent" (modèles, catégorie).

Solution avec plusieurs requêtes de mise à jour/insertion:

Chaque table a un identifiant unique dans votre exemple. Vous pouvez utiliser cet identifiant pour mettre à jour des lignes spécifiques. Dans votre tableau php (POST/GET?), Vous avez un nom et une valeur pour chaque élément, mais aucun identifiant. Ajoutez simplement "id" en plus. 

Si id est vide => INSERER une nouvelle ligne (Cet élément ne provient pas de la base de données)

si id est défini => UPDATE la ligne avec un identifiant spécifique (Cet élément existe déjà et peut avoir été modifié)

Array
(
    [0] => Array
        (
            [id] => 1
            [name] => lijsttitle
            [value] => Lijst nieuw
        )

    [1] => Array
        (
            [id] => 17
            [name] => category[]
            [value] => cat1
        )

    [2] => Array
        (
            [name] => sortorder
            [value] => 1
        )

    [3] => Array
        (
            [id] => 35
            [name] => question[]
            [value] => q1
        )

    [4] => Array
        (
            [id] => 
            [name] => category[]
            [value] => cat2
        )

    [5] => Array
        (
            [name] => sortorder
            [value] => 2
        )

    [6] => Array
        (
            [id] => 
            [name] => question[]
            [value] => q1
        )

)
0
Steffen Mächtel