web-gelistirme-sc.com

PHP MySQL Aynı tablodaki bir satırı kopyalayın ... Birincil ve Benzersiz anahtarla

Masamın iki anahtarı var, biri otomatik artan bir kimlik numarası (PRIMARY), diğeri ise öğenin adı (UNIQUE).

Bu aynı tablo içerisinde bir satırı çoğaltmak mümkün müdür? Denedim:

INSERT INTO items
SELECT * FROM items WHERE id = '9198'

Bu hata verir Duplicate entry '9198' for key 'PRIMARY'

Ben de denedim:

INSERT INTO items
SELECT * FROM items WHERE id = '9198'
ON DUPLICATE KEY UPDATE id=id+1

Hangi hata verir Column 'id' in field list is ambiguous 

Öğe adı (UNIQUE) alanı geçerli olduğu sürece, bu alanın da benzersiz olması gerektiğinden, öğe adına (Copy) eklemenin bir yolu var mı?

17
Norse

Kimlik sütunu hariç tüm sütunları açıkça seçin:

INSERT INTO items
(col1, col2, ..., coln)
SELECT col1, col2, ..., coln
FROM items
WHERE id = '9198'

Bir sonraki sorunuz muhtemelen olacaktır:

Açıkça tüm sütunları listelemeden bunu yapmanın bir yolu var mı?

Cevap: Hayır, sanmıyorum.

38
Mark Byers

Eğer really , Mark'ın cevabındaki gibi tüm tablo sütunlarını listelemek istemiyorsanız, şunu deneyebilirsiniz:

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;

Güzel değil, hızlı değil. Ama işe yarıyor.

22
Phius

Bakım gerektirmeyen mükemmel bir çözüm sunan hobailey'e teşekkür ederiz.

İşte kullandığım, MySQLi için güncellenen kod:

// 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
3
Mark

Alternatif olarak, tüm sütunları açıkça yazmak istemiyorsanız (ve tablo oluşturmayı/bırakmayı başlatmak istemiyorsanız), tablonun sütunlarını alıp otomatik olarak sorguyu oluşturabilirsiniz:

//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

Bunun MySQL'in kullanım dışı kodunu kullandığını ve MySQLi olması gerektiğini unutmayın. Ayrıca geliştirilebileceğinden eminim, ama kullanıyorum bu ve çok iyi çalışıyor.

3
hobailey

Soru başlığı, bunu PHP'den yapmak istediğinizi belirtir.

Aynı sorunla karşılaştım ve tablo yapınızı değiştirirseniz (sütun ekle/kaldır) tüm sütun adlarını yazmak yorucu ve zordur ... ve geçici tablolar kullanan çözümleri sevmiyorum. 

Bu sorunu, PHP'den gönderilen iki sorguyla çözmeyi seçtim. - çok iyi çalışıyor ve bakım gerektirmiyor (feragatname: meekrodb kütüphanesini veritabanı erişimi için kullanıyorum) :

//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;
}

Yeniden yerleştirmeden önce iç verilerde daha fazla manipülasyon yapabilirsiniz (görmezden gelmek, değerleri düzenlemek vb. Diğer sütunları ayarlayın). 

2
Olivier

PHP'deki bir başka çözüm, aynı tablodaki bir satırı belirli bir sütun/sütunlar olmadan kopyalamak için. birincil anahtar - ve "TEMPORARY TABLE" ve "... 'DAN KOLONLARI GÖSTER" - yöntem:

$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 bir SELECT ifadesidir, bu nedenle değerler ifadesinde doğrudan değildir -> "real_escape_string" ile veya bunun gibi bir şeyle ilgili bir sorun yoktur.

2
Oliver-xx

Son zamanlarda benzer bir şey yapmak zorunda kaldım, bu yüzden örneğin herhangi bir boyuttaki tablo için çözümümü gönderdiğimi düşündüm. Sadece hemen hemen her boyuttaki tabloya ayarlanabilen bir konfigürasyon dizisi alır.

$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;
}

Bu gibi bir şey çıkacaktır:

INSERT INTO `purchase_orders` (`siteID`, `supplierID`, `status`, `notes`, `dateCreated`, `approved`)
SELECT `siteID`,'21',`status`,'copied',`dateCreated`,`approved`
FROM `purchase_orders`
WHERE `purchaseOrderID` = '4084';
1
Andy Gee

Birçok sütunu olan tablolar için Phius fikrine benzer bir (evet, yavaş) yöntem kullanıyorum.
Buraya sadece tam olması için koydum.

Diyelim ki 'tbl' tablosu, gibi tanımlanmış bir 'kimliğe' sahip

kimliği INT NULL DEĞİL AUTO_INCREMENT PRIMARY KEY

Ardından, aşağıdaki adımları izleyerek bir satırı klonlayabilir/kopyalayabilirsiniz:

  1. bir tmp tablosu oluştur

TEMPORARY TABLO OLUŞTURUN tbl_tmp LIKE tbl;

  1. Kopyalamak/kopyalamak istediğiniz bir veya daha fazla girişi ekleyin.

Tbl_tmp SELECT * 'den tbl NEREDE GELİYOR ...;

  1. aUTOINCREMENT etiketini 'id' içinden kaldır

ALTER TABLE tbl_tmp MODIFY id INT;

  1. birincil dizini bırak

ALTER TABLE tbl_tmp DROP PRIMARY KEY;

  1. benzersiz dizinlerinizi güncelleyin ve 'id' değerini 0 olarak ayarlayın (adım 6'nın çalışması için 0 gerekir)

GÜNCELLEME tbl_tmp SET unique_value = ?, id = 0;

  1. değiştirilmiş satırlarınızı 'tbl' içine kopyalayın ve 'id' otomatik olarak oluşturuldu.

Tbl SELECT içine * INSERT * FRT tbl_tmp;

  1. temizleme (veya yalnızca DB bağlantısını kapatın)

DROP TABLE tbl_tmp;

Ayrıca, bağımlı tablolardaki bazı verileri başka tablolara kopyalamanız/kopyalamanız gerekirse, her satır için yukarıdaki İşlemlerini yapın. 6. adımdan sonra, son eklenen anahtarı alabilir ve bunu aynı prosedürü kullanarak diğer tabloların içindeki bağımlı satırları klonlamak/kopyalamak için kullanabilirsiniz.

1
rockdaboot

Kimse soruyu oluşturmak için phpMyAdmin kullanarak bahsetmedi şaşırdım. Çünkü bu, tüm sütunları eklemeyi hızlandırır ve daha sonra kimliği wlf ile yukarıda belirtildiği gibi boş veya sıfır olarak ayarlayın. 

Bu, bunu yapmanın en basit yoludur. 

INSERT INTO users SELECT 0,email,user FROM users WHERE id=10
1
The Amerloc

Tablonun user(id,email,user) olduğunu ve WHERE cümlecikliğiniz olduğundan MAX(id)+1 kullanamayacağınızı söyleyin:

INSERT INTO users SELECT 0,email,user FROM users WHERE id=10

INSERT kullanırken her zaman sütun adlarını belirtmeniz gerektiğine dikkat edin.

0
wlf

Bu, herhangi bir tablonun kaydını kopyalamak için genel bir işlevdir:

/**
 * @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();
}
0
MrCatGonzo

Etkinlikler masamda bir satır kopyalamak istedim ve Mark'ın çözümünü çok faydalı buldum. Onu biraz kısalttım.

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;
}

ve kopyalama kodu:

$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).'")'; 
0
Paul Wolbers