Ma table a deux clés, l’une est un identifiant auto-incrémenté (PRIMARY), l’autre est le nom de l’article (UNIQUE).
Est-il possible de dupliquer une ligne dans cette même table? J'ai essayé:
INSERT INTO items
SELECT * FROM items WHERE id = '9198'
Cela donne l'erreur Duplicate entry '9198' for key 'PRIMARY'
J'ai aussi essayé:
INSERT INTO items
SELECT * FROM items WHERE id = '9198'
ON DUPLICATE KEY UPDATE id=id+1
Ce qui donne l'erreur Column 'id' in field list is ambiguous
Et en ce qui concerne le champ nom d’élément (UNIQUE), existe-t-il un moyen d’ajouter (Copy)
au nom de l’élément, puisque ce champ doit également être unique?
Sélectionnez toutes les colonnes explicitement, à l'exception de la colonne id:
INSERT INTO items
(col1, col2, ..., coln)
SELECT col1, col2, ..., coln
FROM items
WHERE id = '9198'
Votre prochaine question sera probablement:
Y a-t-il un moyen de faire cela sans lister explicitement toutes les colonnes?
Réponse: non, je ne pense pas.
Si vous vraiment ne voulez pas lister toutes les colonnes du tableau comme dans la réponse de Mark, essayez ceci:
CREATE TEMPORARY TABLE temp_tbl SELECT * FROM items WHERE id = '9198';
UPDATE temp_tbl SET id = id + 1;
INSERT INTO items SELECT * FROM temp_tbl;
DROP TABLE temp_tbl;
Pas beau, pas rapide. Mais ça marche.
Merci à Hobailey pour sa solution sans entretien.
Voici le code que j'ai finalement utilisé, qui est mis à jour pour MySQLi:
// Get the columns
$cols = array();
$result = $mysqli->query("SHOW COLUMNS FROM [TABLE]"); // Change table name
while ($r = $result->fetch_array(MYSQLI_ASSOC)) {
if (!in_array($r["Field"], array("COLA", "COL4", "COL8"))) { // Edit array with any column names you want to exclude
$cols[] = $r["Field"];
}
}
// Build and do the insert
$result = $mysqli->query("SELECT * FROM [TABLE] WHERE [SELECTION CRITERIA];"); // Change table name and add selection criteria
while ($r = $result->fetch_array(MYSQLI_ASSOC)) {
$insertSQL = "INSERT INTO [TABLE] (" . implode(", ",$cols) . ") VALUES ("; // Change table name
$count = count($cols);
foreach($cols as $counter=>$col) {
// This is where you can add any code to change the value of existing columns
$insertSQL .= "'" . $mysqli->real_escape_string($r[$col]) . "'";
if ($counter < ($count - 1)) {
$insertSQL .= ", ";
}
} // END foreach
$insertSQL .= ");";
$mysqli->query($insertSQL);
if ($mysqli->affected_rows < 1) {
// Add code if the insert fails
} else {
// Add code if the insert is successful
}
} // END while
Si vous ne voulez pas écrire explicitement toutes les colonnes (et ne voulez pas commencer à créer/supprimer des tables), vous pouvez simplement obtenir les colonnes de la table et construire la requête automatiquement:
//get the columns
$cols=array();
$result = mysql_query("SHOW COLUMNS FROM [table]");
while ($r=mysql_fetch_assoc($result)) {
if (!in_array($r["Field"],array("[unique key]"))) {//add other columns here to want to exclude from the insert
$cols[]= $r["Field"];
} //if
}//while
//build and do the insert
$result = mysql_query("SELECT * FROM [table] WHERE [queries against want to duplicate]");
while($r=mysql_fetch_array($result)) {
$insertSQL = "INSERT INTO [table] (".implode(", ",$cols).") VALUES (";
$count=count($cols);
foreach($cols as $counter=>$col) {
$insertSQL .= "'".$r[$col]."'";
if ($counter<$count-1) {$insertSQL .= ", ";}//dont want a , on the last one
}//foreach
$insertSQL .= ")";
mysql_query($insertSQL);//execute the query
}//while
Notez que cela utilise le code déprécié de MySQL et que cela devrait être MySQLi. Je suis sûr que cela pourrait également être amélioré, mais c'est ce que j'utilise et cela fonctionne très bien.
Le titre de la question indique que vous souhaitez le faire à partir de PHP.
J'ai rencontré le même problème et écrire tous les noms de colonnes est fastidieux et difficile à maintenir si vous modifiez la structure de votre table (ajout/suppression de colonnes) ... et je n'aime pas les solutions qui utilisent des tables temporaires.
J'ai choisi de résoudre ce problème avec deux requêtes envoyées par PHP - fonctionne très bien et ne nécessite aucune maintenance (avertissement: j'utilise la bibliothèque meekrodb pour accéder à une base de données) :
//get the data as an associative array
$row = DB::queryFirstRow("SELECT * FROM your_table WHERE id=%i",$id);
if ($row){
unset($row["id"]); //unset the primary key
DB::insert("your_table",$row);
return DB::insertId();
} else {
return false;
}
Vous pouvez même effectuer davantage de manipulations sur les données internes (désélectionner d'autres colonnes à ignorer, modifier des valeurs, etc.) avant de les réinsérer.
Une autre solution dansPHPpour copier une ligne de la même table sans colonne spécifique/p. Ex. clé primaire - et sans les méthodes "TABLE TEMPORAIRE" et "AFFICHER LES COLONNES DE ...":
$stmt = $db->prepare("select * from table where id = :id;");
$stmt->bindValue(':id', $_GET['id'], PDO::PARAM_INT);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
unset($row['id']); //remove primary key
$columns = array_keys($row);
$query = "insert into table (`".implode('`, `', $columns)."`) select `".implode('`, `', $columns)."` from data_ticket_serie where id = ".$_GET['id'].";";
// echo $query;
$stmt = $db->prepare($query);
$stmt->execute();
L'INSERT est une instruction SELECT, les valeurs ne sont donc pas directes dans l'instruction -> aucun problème avec "real_escape_string" ou quelque chose comme ça.
Pour les tables à plusieurs colonnes, j'utilise une méthode (oui lente) similaire à celle de Phius idea .
Je le mets ici juste pour être complet.
Supposons que la table 'tbl' a un 'id' défini comme
id INT NON NULL AUTO_INCREMENT PRIMARY KEY
Ensuite, vous pouvez cloner/copier une ligne en procédant comme suit:
CREATE TEMPORARY TABLE tbl_tmp LIKE tbl;
INSERT INTO tbl_tmp SELECT * FROM tbl WHERE ...;
ALTER TABLE tbl_tmp MODIFY id INT;
ALTER TABLE tbl_tmp DROP PRIMARY KEY;
UPDATE tbl_tmp SET valeur_unique = ?, id = 0;
INSERT INTO tbl SELECT * FROM tbl_tmp;
DROP TABLE tbl_tmp;
Si vous avez également besoin de cloner/copier des données dépendantes dans d'autres tables, procédez comme suit Pour chaque ligne. Après l'étape 6, vous pouvez obtenir la dernière clé insérée et l'utiliser pour Cloner/copier les lignes dépendantes dans d'autres tables en suivant la même procédure.
Je suis surpris que quiconque n'ait pas mentionné l'utilisation de phpMyAdmin pour créer la requête. Parce que cela rendrait rapide l'ajout de toutes les colonnes et ensuite vous définissez l'identifiant sur null ou o comme mentionné ci-dessus par wlf
C'est de loin le moyen le plus simple de le faire
INSERT INTO users SELECT 0,email,user FROM users WHERE id=10
Supposons que la table est user(id,email,user)
et que vous avez une clause WHERE
, vous ne pouvez pas utiliser MAX(id)+1
:
INSERT INTO users SELECT 0,email,user FROM users WHERE id=10
Notez cependant que vous devez toujours spécifier les noms de colonne lorsque vous utilisez INSERT.
Ceci est une fonction générale pour copier un enregistrement de n'importe quelle table:
/**
* @param string $table Name of table
* @param array $primaryKey Which record should be copied? array('nameOfColumnWithUniqueId' => "value")
* @param array $excludeFields Which columns should not be copied (e.q. Unique Cols)
* @param string $database Name of database
* @return int ID of new inserted record
*/
function copyMysqlRow($table, $primaryKey, $excludeFields = array(), $database = "usr_web3_2")
{
$field = key($primaryKey);
$value = current($primaryKey);
$sql = "
SELECT
*
FROM
$database.$table
WHERE
$field = '$value'
";
$result = mysql_query($sql);
$row = mysql_fetch_assoc($result);
$cols = array();
$values = array();
foreach ($row AS $col=>$value) {
if (!in_array($col, $excludeFields)) {
$cols[] = "`" . $col . "`";
$values[] = $value === null ? 'null' : "'" . $value . "'";
}
}
$sql = sprintf(" INSERT INTO $database.$table (%s) VALUES (%s) ", implode($cols, ','), implode($values, ','));
mysql_query($sql);
return mysql_insert_id();
}
Je voulais copier une ligne dans ma table d'événements et j'ai trouvé la solution de Mark très utile. Je l'ai fait un peu plus court.
public static function getColumnsOfTable($table, $arr_exclude_cols=array()) {
global $obj_db;
$cols = array();
$result = $obj_db->query("SHOW COLUMNS FROM `".$table."`");
while ($r = $result->fetch_array(MYSQLI_ASSOC)) {
if (!in_array($r["Field"], $arr_exclude_cols)) {
$cols[] = $r["Field"];
}
}
return $cols;
}
et le code pour copier:
$cols = Utils::getColumnsOfTable('events', array('event_id'));
$result1 = $obj_db->query('SELECT * FROM `events` WHERE `event_id` = '.$event_id);
$arr_event = mysqli_fetch_array($result1, MYSQLI_NUM);
unset($arr_event[0]);
$insertSQL = 'INSERT INTO `events` (`' . implode('`, `',$cols) . '`) VALUES ("'. implode('","', $arr_event).'")';