JeuWeb - Crée ton jeu par navigateur
Insertion SQL sur plusieurs tables - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Insertion SQL sur plusieurs tables (/showthread.php?tid=4356)



Insertion SQL sur plusieurs tables - Ekilio - 17-09-2009

Bonjour à tous,

J'ai un léger problème dans la conception de mon appli SQL. Je vous explique le principe : j'ai trois tables.

Première table :
Code :
CREATE TABLE `cubik_pages` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) NOT NULL,
`url` varchar(255) default NULL,
PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Cette table référencie des pages.

Seconde table :
Code :
CREATE TABLE `cubik_blocs` (
`id` int(11) NOT NULL auto_increment,
`page` int(11) NOT NULL,
`bloc` varchar(30) NOT NULL,
`group` varchar(30) NOT NULL,
`x` int(11) NOT NULL,
`y` int(11) NOT NULL,
`width` int(11) NOT NULL default '10',
`height` int(11) NOT NULL default '10',
`configLevel` tinyint(1) NOT NULL,
PRIMARY KEY  (`id`),
KEY `page` (`page`),
CONSTRAINT `cubik_blocs_ibfk_1` FOREIGN KEY (`page`) REFERENCES `cubik_pages` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Cette table contient les blocs de texte présents sur la page.

Troisième table :
Code :
CREATE TABLE `cubik_configuration` (
`id` int(11) NOT NULL auto_increment,
`bloc` int(11) default NULL,
`key` varchar(30) NOT NULL,
`value` longtext NOT NULL,
PRIMARY KEY  (`id`),
UNIQUE KEY `Unique_BlocKey` (`bloc`,`key`),
KEY `bloc` (`bloc`),
CONSTRAINT `cubik_configuration_ibfk_1` FOREIGN KEY (`bloc`) REFERENCES `cubik_blocs` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Cette table contient les textes et autres infos sur les blocs de texte sus-mentionnés (notes invisibles selon les moments, etc).

Assez logiquement, il y a plusieurs blocs sur une page, et plusieurs configurations par blocs. Le problème est le suivant : j'aimerais pouvoir dupliquer des pages en copiant tout leur contenu, configurations comprises, de l'une à l'autre. Pour créer une nouvelle page, pas de problèmes, un INSERT INTO marche bien. Pour copier la liste des blocs et leurs positions, idem, INSERT INTO ... SELECT ...

Et c'est là qu'arrive le problème, parce que j'ai alors dans ma table de blocs les nouveaux blocs... Mais je ne sais pas quel est l'id de l'ancien bloc qui correspond. Du coup, je ne sais pas comment faire pour copier les valeurs de la table de configuration en leur affectant le nouvel id de bloc, vu que je n'ai pas gardé de liens entre les anciens et les nouveaux blocs... et vu que la numérotation des blocs se base sur l'auto_increment, je ne sais pas trop comment faire.

J'avais bien pensé à récupérer au moment de débuter les requêtes le numéro de l'auto-incrément sur la table des blocs et de l'augmenter du nombre de blocs voulus en espérant que ça se range dans le bon ordre et qu'il n'y ai pas deux duplications simultanées (ce qui en théorie ne devrait pas arriver, la création d'une nouvelle page est relativement rare, mais on ne sait jamais) mais ça me semble bien... hasardeux, disons.

Est-ce que vous auriez une autre idée qui serait plus pratique que celle-ci ? Hormis faire un select puis des insert/select à la pelle ?

Merci !


RE: Insertion SQL sur plusieurs tables - Ruz - 17-09-2009

3e version de cette réponse

Casse toi pas la tete.
1) tu charges tout dans une variable (ou plusieurs) (page, blocks, configuration)
2) tu sauvegardes (en récupérant l'ID de l'enregistrement inséré avec la fonction qui va bien ($ID=mysql_insert_id()Wink, en 3 étapes)

J'ai du zapper une difficulté...


RE: Insertion SQL sur plusieurs tables - Ekilio - 17-09-2009

La difficulté, c'est le poids d'une telle requête. Je peux avoir 10 ou quinze blocs par page, avec cinq ou six configurations par blocs => ça nous amène à une cinquantaine de requêtes d'insertion, sans compter les selects et autres. C'est très (trop Undecided) lourd à faire comme ça... même si on peut effectivement l'optimiser un peu, c'est très très lourd...


RE: Insertion SQL sur plusieurs tables - wild-D - 17-09-2009

je veux bien que 50 insertions ça puisse paraître un peu lourd par rapport à des requête atomique qui généralement comprenne juste une insertion, mais faut pas non plus dramatiser^^
(normalement t'auras pas des centaine de duplication de page en simultané.)

p.s.
pis sinon si tu tiens à avoir tous les blocs à la suite, tu peux faire un alter table pour fixer l'auto increment à la valeur voulue (tu te réserve l'espace pour faire tes inserts "à la mimine" , normalement si y a un insert en parallèle, il se fera avec la nouvelle valeur auto_increment)


RE: Insertion SQL sur plusieurs tables - Ekilio - 17-09-2009

Certes, ce n'est pas forcément énorme... Mais ça peut suffire à dépasser le time limit sur certains serveurs, et le code en question est une part d'un CMS donc doit être redistribuable. D'où besoin de truc léger :x


RE: Insertion SQL sur plusieurs tables - Allwise - 17-09-2009

Déjà, la table config, tu peux peut-être en faire un champ config dans la table bloc et y mettre du contenu serialisé. Ca peut marcher si tu n'as pas l'intention de faire du tri sur ces données.
Au lieu de copier pages et blocs, est-ce qu'il ne serait pas possible de faire une relation n<-->n entre tes pages et tes blocs, et ainsi de créer une table intermédiaire ? Dans ce cas il faudrait quand même copier les enregistrements de la table intermédiaire, mais ça te ferait moins de redondance d'information.

Je connais pas de requête qui puisse tout faire en même temps. Par contre avec une procédure / fonction SQL, c'est certainement faisable.


RE: Insertion SQL sur plusieurs tables - Ekilio - 17-09-2009

Nop, je ne peux pas faire un champ supplémentaire, parce que les infos dans la table configuration ne sont pas uniquement des blocs (si le numéro de bloc est null, c'est la configuration globale).

Et je ne veux pas qu'un même bloc puisse être sur plusieurs pages, pour qu'on puisse personnaliser chaque page exactement


RE: Insertion SQL sur plusieurs tables - Ter Rowan - 18-09-2009

c'est peut être très mauvais mais je me lance...

phase 1 copie de la page :
lorsque tu dupliques ta donnée maître, pourquoi ne pas rajouter un champ "id source" qui contiendra l'id de la page d'origine.

phase 2 copie des blocs :
dans le insert into ... select ... tu rajoutes la jointure sur page."id source" = bloc."id page"
et tu rajoutes un champ "id bloc source" qui contiendra l'id du bloc créé

phase 3 copie du détail :
même principe que phase 2

phase 4 "séparation"
tu updates chacune des tables qui possèdent un "id source" (page et bloc) pour permettre une prochaine copie de la page et des blocs

au global 5 requêtes (3 insert, 2 update)

la contrainte que je vois dans ce processus, c'est que tu dois interdir l'accès à ces tables le temps des traitements (pour éviter deux duplications de la même page, ce qui mettrais le binz)


voilà, c'est peut être pas très efficaces, j en sais rien, mais à première vue ça a l air de marcher


RE: Insertion SQL sur plusieurs tables - zeppelin - 22-09-2009

Je suis assez d'accord avec wild-d sur ce coup, faut pas dramatiser... Ou alors tu crée un objet qui contient toutes les infos, et avec serialize et unserialize tu fait un seul insert de ton objet au format text dans la BDD. Contraintes? Les recherches, pas terrible sur un champs dans une BDD qui contient pleins d'infos, la tu dois passer par des REGEX.

Code PHP :
<?php

class Cubik
{

private
$page;

public function
__construct()
{
$this->page = array();
}

public function
__set($key, $value)
{
$this->page[$key] = $value;
}

public function
__get($key)
{
if(
array_key_exists($key, $this->page))
{
return
$this->page[$key];
}
else
// enregistrement dans errorLog?
}

public function
load($pageID)
{
$infos = Mysql::getInstance()->get(); ... // on se choppes les infos

$this->page = unserialize($infos);
}

public function
saveAs($update = true)
{
$infos = serialize($this->page);

if(
$update === true)
{
Mysql::getInstance()->update(); // update avec $infos
}
else
{
Mysql::getInstance()->insert(); // insertion d'une nouvelle page
}
}
}

?>

Il te reste donc plus que la table pages, avec comme champs id et values.

Pour être plus concret: On migre les 2 autres tables dans des arrays (la aussi t'as autant de dimensions que tu veux, donc comme pour les BDD tu peux avoir autant de blocs par page et autant de configs par blocs que tu souhaite).

Au lieu de balancer des requêtes à tout allure on remplis notre array structuré, et uniquement tout à la fin, quand tout y est, on fait un update (ou une insertion, en passant false comme paramètre à la méthode saveAs()).


RE: Insertion SQL sur plusieurs tables - Ekilio - 23-09-2009

Houla non ^^' Ca ce ne serait pas du tout envisageable de tout migrer dans des arrays, que ce soit pour une question d'optimisation, de praticité (dans la recherche entre autres effectivement mais aussi par exemple pour la suppression d'un module), etc... Sans compter que comme je disais certaines configuration doivent pouvoir être "globales" c'est à dire qu'elles ne concernent pas un bloc en particulier (typiquement le titre ou l'adresse du site sont enregistrés ainsi)

Mais en fait j'ai résolu le problème en appliquant finalement la suggestion de faire une relation many to many en ajoutant une table de lien, du coup la duplication des pages est beaucoup plus simple.

Merci à tous pour vos conseils !