我的表有两个键,一个是自动递增ID(PRIMARY),另一个是项目名称(UNIQUE)。
是否可以在同一个表中复制一行?我试过了:
INSERT INTO items
SELECT * FROM items WHERE id = '9198'
这会产生错误Duplicate entry '9198' for key 'PRIMARY'
我也尝试过:
INSERT INTO items
SELECT * FROM items WHERE id = '9198'
ON DUPLICATE KEY UPDATE id=id+1
出现错误Column 'id' in field list is ambiguous
就项目名称(UNIQUE)字段而言,有没有办法将(Copy)
附加到项目名称,因为此字段也必须是唯一的?
答案 0 :(得分:41)
显式选择所有列,但id列除外:
INSERT INTO items
(col1, col2, ..., coln)
SELECT col1, col2, ..., coln
FROM items
WHERE id = '9198'
您的下一个问题可能是:
有没有办法在不明确列出所有列的情况下执行此操作?
答案:不,我不这么认为。
答案 1 :(得分:22)
如果你真的不希望列出Mark的答案中的所有表格列,你可以试试这个:
CREATE TEMPORARY TABLE temp_tbl SELECT * FROM items WHERE id = '9198';
SELECT @maxId := MAX(id) + 1 FROM items;
UPDATE temp_tbl SET id = @maxId;
INSERT INTO items SELECT * FROM temp_tbl;
DROP TABLE temp_tbl;
不漂亮,不快。但是有效。
答案 2 :(得分:3)
或者,如果您不想显式写入所有列(并且不想开始创建/删除表),您可以只获取表的列并自动构建查询:
//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
请注意,这使用了MySQL的折旧代码,它应该是MySQLi。我确信它也可以改进,但它正是我正在使用的并且效果非常好。
答案 3 :(得分:3)
感谢hobailey提供了一个免维护的解决方案。
这是我最终使用的代码,它是针对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
答案 4 :(得分:2)
问题标题确实表明您希望从PHP执行此操作。
我遇到了同样的问题,如果更改表结构(添加/删除列),写出所有列名称都很繁琐且难以维护...而且我不喜欢使用临时表的解决方案。
我选择用PHP发送的两个查询来解决这个问题 - 效果很好,无需维护(免责声明:我使用meekrodb库进行数据库访问):
//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;
}
在重新插入之前,您甚至可以对内部数据执行更多操作(取消设置其他列以忽略,编辑值等)。
答案 5 :(得分:2)
PHP 中的另一个解决方案,用于在没有特定列/例如同一个表的情况下复制行主键 - 没有“TEMPORARY TABLE”和“SHOW COLUMNS FROM ...” - 方法:
$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();
INSERT是一个SELECT语句,因此值在语句中不是直接的 - &gt;没有问题“real_escape_string”或类似的东西。
答案 6 :(得分:1)
对于包含许多列的表,我使用类似于Phius想法的(是,慢)方法。 我把它放在这里只是为了完整。
我们假设,表'tbl'的'id'定义为
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
然后,您可以按照以下步骤克隆/复制行:
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 unique_value = ?, id = 0;
INSERT INTO tbl SELECT * FROM tbl_tmp;
DROP TABLE tbl_tmp;
如果您还需要克隆/复制其他表中的某些相关数据,请执行以上操作 对于每一行。在第6步之后,您可以获取最后插入的密钥并使用它 使用相同的过程克隆/复制其他表中的从属行。
答案 7 :(得分:1)
我很惊讶有人没有提到使用phpMyAdmin来创建查询。因为这样可以快速添加所有列,然后只需将id设置为null或o,如上所述。
这是迄今为止最简单的方法
INSERT INTO users SELECT 0,email,user FROM users WHERE id=10
答案 8 :(得分:0)
假设该表格为user(id,email,user)
,并且因为您有WHERE
条款,则无法使用MAX(id)+1
:
INSERT INTO users SELECT 0,email,user FROM users WHERE id=10
请记住,在使用INSERT时应始终指定列名。
答案 9 :(得分:0)
我想在事件表中复制一行,发现Mark的解决方案非常有用。我把它缩短了一点。
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;
}
和复制代码:
$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).'")';
答案 10 :(得分:0)
这是复制任何表记录的一般功能:
/**
* @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();
}
答案 11 :(得分:0)
最近我不得不做类似的事情,所以我想我发布任何尺寸表的解决方案,包括示例。只需一个配置数组,几乎可以将其调整为任何大小的表。
$copy_table_row = array(
'table'=>'purchase_orders', //table name
'primary'=>'purchaseOrderID', //primary key (or whatever column you're lookin up with index)
'index'=>4084, //primary key index number
'fields' => array(
'siteID', //copy colunm
['supplierID'=>21], //overwrite this column to arbirary value by wrapping it in an array
'status', //copy colunm
['notes'=>'copied'], //changes to "copied"
'dateCreated', //copy colunm
'approved', //copy colunm
),
);
echo copy_table_row($copy_table_row);
function copy_table_row($cfg){
$d=[];
foreach($cfg['fields'] as $i => $f){
if(is_array($f)){
$d['insert'][$i] = "`".current(array_keys($f))."`";
$d['select'][$i] = "'".current($f)."'";
}else{
$d['insert'][$i] = "`".$f."`";
$d['select'][$i] = "`".$f."`";
}
}
$sql = "INSERT INTO `".$cfg['table']."` (".implode(', ',$d['insert']).")
SELECT ".implode(',',$d['select'])."
FROM `".$cfg['table']."`
WHERE `".$cfg['primary']."` = '".$cfg['index']."';";
return $sql;
}
这将输出如下内容:
INSERT INTO `purchase_orders` (`siteID`, `supplierID`, `status`, `notes`, `dateCreated`, `approved`)
SELECT `siteID`,'21',`status`,'copied',`dateCreated`,`approved`
FROM `purchase_orders`
WHERE `purchaseOrderID` = '4084';