使用php和mysql从多个表复制行

时间:2011-11-30 11:00:05

标签: php mysql pdo

我正在为一个应用程序构建一个复制活动功能,我这样做的方法是使用循环来浏览所有选定的行,使用php,获取他们的ID并再次循环以插入具有相同数据但有一个更改的新行列值。这是我目前采用的完美方法:

<?php
    $id = Url::find('id');
    //Copy campaign row
    $cid = $this->Db->Query("
        INSERT INTO campaigns (`user_id`, `tid`, `featured`, `opt`, `title`, `uri`, `cpi`, `payout`, `cat`, `domain`, `created`, `disabled`, `completed`, `featured_pos`)
        SELECT `user_id`, `tid`, `featured`, `opt`, CONCAT(`title`,' - Copy'), `uri`, `cpi`, `payout`, `cat`, `domain`, `created`, `disabled`, `completed`, `featured_pos` FROM campaigns WHERE id = :id
    ",array(':id' => array(DB::INT => $id)),true);

    //Copy variants
    $vars = $this->Db->selectAll(array('cid' => $id), 'variations');
    if(!empty($vars)) {
        for($i = 0; $i < count($vars); $i++) {
            $old[] = $vars[$i]['id']; //Copy source
            $vid[] = $this->Db->Query("
                INSERT INTO variations (`ordering`, `disabled`, `cid`, `height`, `width`, `bgcolor`, `head`,`title`, `keywords`, `description`, `link`)
                SELECT `ordering`, `disabled`, :cid, `height`, `width`, `bgcolor`, `head`, `title`, `keywords`, `description`, `link` FROM variations WHERE id = :id
                ",array(
                    ':id' => array(DB::INT => $vars[$i]['id']),
                    ':cid' => array(DB::INT => $cid)
                ),true);
        }
    }
    //Copy elements
    if(isset($vid)) {
        for($i = 0; $i < count($vid); $i++) {
            $this->Db->Query("
                INSERT INTO elements (`name`, `var`, `type`, `left`, `top`, `width`, `height`, `z-index`, `html`, `css`)
                SELECT `name`, :vid, `type`, `left`, `top`, `width`, `height`, `z-index`, `html`, `css` FROM elements WHERE var = :id
                ",array(
                    ':vid' => array(DB::INT => $vid[$i]),
                    ':id' => array(DB::INT => $old[$i])
                ),true);
        }
    }
    echo "OK";
    ?>

但是我确信这不是最好的方法,因为它执行的查询太多了。我已经升级了脚本,但我无法弄清楚如何使用新变体的新ID将行复制到元素表中。 新脚本:

$id = Url::find('id');
$cid = $this->Db->Query("
    INSERT INTO campaigns (`user_id`, `featured`, `title`, `domain`, `created`, `disabled`, `featured_pos`)
    SELECT :user, `featured`, CONCAT(`title`,' - Copy'), `domain`, `created`, `disabled`, `featured_pos` FROM campaigns WHERE id = :id
",array(':id' => array(DB::INT => $id), ':user' => array(DB::INT => $this->session->user['id'])),true);

//Copy variants

$this->Db->Query("
    INSERT INTO variations (`ordering`, `disabled`, `cid`, `height`, `width`, `bgcolor`, `head`,`title`, `keywords`, `description`, `link`)
    SELECT `ordering`, `disabled`, :id, `height`, `width`, `bgcolor`, `head`, `title`, `keywords`, `description`, `link` FROM variations WHERE cid = :oid
",array(
    ':id' => array(DB::INT => $cid), //new id
    ':oid' => array(DB::INT => $id) //old id
 ),true);

 $this->Db->Query("
    INSERT INTO elements (`name`, `var`, `html`, `type`)
    SELECT e.name, v.id, e.html, e.type FROM elements AS e, variations AS v
    WHERE v.cid = :cid AND e.var = v.id
",array(
    ':cid' => array(DB::INT => $id)
 ),true);

前2个查询按预期工作,但最后一个(INSERT INTO元素)没有。这是因为它从旧的广告系列中选择了变体,并将旧的ID插入var列,而不是之前插入的新ID。显然,这是因为查询是以这种方式构建的,但是我如何从没有循环的新变体中获取ID以将它们插入到元素中。 (或者我偏执太多,我最初的做法很好吗?)

更清楚我的问题 - 如何在没有php循环的情况下这样做:

    INSERT INTO elements (`name`, `var`, `html`, `type`)
    SELECT e.name, (new v.id from the previous query and not the same one as in WHERE clause), e.html, e.type FROM elements AS e, variations AS v
    WHERE v.cid = :cid AND e.var = v.id

对不起我的语法错误(我刚上班,需要一杯咖啡)

非常感谢:)

2 个答案:

答案 0 :(得分:0)

如果这是一个你需要遵循的常规过程,那么按照我的说法定义一个函数并在函数内部使用你的逻辑会更好。由于函数是预编译的,因此执行速度很快。在前端只需调用该函数。

答案 1 :(得分:0)

我不太清楚我明白你在问什么,因为事实上,你的问题包含了太多关于原因的信息。我会尽力回答你的最后一个问题:

INSERT INTO elements (`name`, `var`, `html`, `type`)
    SELECT e.name, (new v.id from the previous query and not the same one as in WHERE clause), e.html, e.type FROM elements AS e, variations AS v
    WHERE v.cid = :cid AND e.var = v.id

再次,如果我错过了这一点,请不要苛刻:)

所以你插入一堆行,然后根据这些行的ID,你想将它们插入到不同的表中?因此,如果只有你,谁在使用系统,那么简单的方法就是获取插入行的ID,例如,如果你知道插入行的数量,只需要最后n行?或者添加另一个具有唯一ID的列,这样您就可以从中获取。然后将ID放在数组中,用冒号连接它们,最后,您的查询应如下所示:

INSERT INTO elements (`name`, `var`, `html`, `type`)
    SELECT e.name, (new v.id from the previous query and not the same one as in WHERE clause), e.html, e.type FROM elements AS e, variations AS v
    WHERE v.cid IN($c_ids) AND e.var IN($v_ids)

总结如下: -插入 - 插入c id -插入 - 插入v id -join c ids -join v ids - 使用查询

我不知道查询是如何工作的:

INSERT INTO campaigns (`user_id`, `featured`, `title`, `domain`, `created`, `disabled`, `featured_pos`)
    SELECT :user, `featured`, CONCAT(`title`,' - Copy'), `domain`, `created`, `disabled`, `featured_pos` FROM campaigns WHERE id = :id
",array(':id' => array(DB::INT => $id)

我真的希望它不会逐个插入1000行。但是如果它确实(并且我猜你对此很偏执),请在php中使用连接,这样可以减少发送到sql的文本量,尤其是调用的查询量。如果行数很高,那么花费的时间就会非常庞大​​。