Exportation importation de bdd respectant les relations entre tables

Contenu du snippet

Avez vous jamais eu ce problème? il faut exporter des données de plusieurs tables mais tout en respectant l'id auto incrément de chaque table qui est repris dans une autre table... Evidemment il serait si simple de copier/coller les fichiers table, mais impossible si l'on souhaite ajouter des données à la suite en conservant les données déjà existantes!

voici le cas concret:
1 table mat_questionnaire (clé primaire: que_id)
==> liée à la table mat_rubrique (clé primaire: rub_id) par la jointure mat_questionnaire.que_id = mat_rubrique.que_id
==> liée à la table mat_question (clé primaire: qes_id) par la jointure mat_rubrique.rub_id = mat_question.rub_id
==> liée à la table mat_reponse (clé primaire: rep_id) par la jointure mat_question.qes_id = mat_reponse.qes_id

processus réccursif: exporter 1 ligne de mat_questionnaire; récupérer le LAST_INSERT_ID, insérer les lignes correspondantes dans mat_rubrique pour cet ID, puis les questions pour chaque ID de mat_rubrique, puis les réponses de chaque question... la définition de l'array permet de s'adapter à quasiment tout type de structure, la récursivité de la fonction fait le reste.
Comme il n'est pas forcément possible d'insérer directement dans 1 autre table (qui peut être une autre BDD...) j'ai choisis d'afficher les requetes qu'il faut ensuite copier/coller par exemple dans phpmyadmin. (on aurait pu aussi les exporter dans un ficher). Le script utilise la capacité de mySQL de déclarer des variables.

Source / Exemple :


<?php

// Information de connexion à la base de données locale
$database_local_addr = "localhost";
$database_local_name = "";
$database_local_user = "root";
$database_local_password = "";

if (!($link = @mysql_connect($database_local_addr,$database_local_user,$database_local_password)) 
	OR (!@mysql_select_db($database_local_name)))
  die("La base de données est indisponible.");

// exporter les données suivant leurs relations
$config = array('tbl' => 'mat_questionnaire', 'pk' => 'que_id', 
	'que_id' => array( 'tbl' => 'mat_rubrique', 'pk' => 'rub_id', 'fk' => 'que_id', 
		'rub_id' => array( 'tbl' => 'mat_question', 'pk' => 'qes_id', 'fk' => 'rub_id', 
			'qes_id' => array( 'tbl' => 'mat_reponse', 'pk' => 'rep_id', 'fk' => 'qes_id')
) ) );

echo '<pre>';
recurseexport( $config, 'que_id=2');
echo '</pre>';

// fonction récursive selon la définition de l'arg $array
// possibilité de filtrer sur la 1ere table définie par l'$array
function recurseexport($array, $filter='', $keyvalue= false ) {
	// récupérer le last_id si besoin
	if ($keyvalue) {
		$keyname = '@id_'.$array['tbl'];
		echo "SET $keyname := LAST_INSERT_ID();\n";
	}
	$sql = 'SELECT * FROM '.$array['tbl'];
	if ($filter) $sql.=' WHERE '.$filter;
	$result = mysql_query($sql) or die ('ERREUR '.$sql.' '.mysql_error());  
	while ($row = mysql_fetch_assoc($result)) {
		// exporter la ligne:
		if ($keyvalue)
			echo 'INSERT INTO '.$array['tbl'].' '.export ($row, $array['pk'], $array['fk'], $keyname)."\n";
		else
			echo 'INSERT INTO '.$array['tbl'].' '.export ($row, $array['pk'])."\n";
		
		// si la clé a une relation, exporter les dépendances:
		if (isset($array[$array['pk']])) {
			// 
			$tbl = $array[$array['pk']];
			$fk = $tbl['fk'];
			recurseexport( $tbl, $fk.'='.$row[$array['pk']], true);
		}
	}
}

// génere un INSERT (champs...) VALUES (valeurs...)
function export(&$row, $pkfield, $fkfield='', $fkname='') {
	$listvalues = '';
	$listfields = '';
	foreach ($row as $field => $value) {
		if ($field <> $pkfield) {
			$listfields .= ', '.$field;
			if ($field == $fkfield)
				$listvalues.=", $fkname";
			elseif (is_null($value))
				$listvalues.=', NULL';
			else
				$listvalues.=", '".mysql_escape_string($value)."'";
		}
	}
	return '('.substr($listfields, 1).') VALUES ('.substr($listvalues, 1).');';
}

Conclusion :


les champs 'pk' (clé primaire) sont supposé être en auto-incrément, leur valeur n'est donc pas exportée puisqu'elle sera récupéree dans une variable mySQL.. Les champs 'fk' sont la relation (clé étrangère) avec le champs 'pk' de la table liée. Pas testé dans le cas de relation d'1 table avec plusieurs ou bien de relations sur plusieurs champs...

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.