我怎样才能“选择”?有未知的列?

发布于 2024-10-04 05:40:58 字数 5274 浏览 4 评论 0原文

MySQL 在执行以下操作时总是会抛出错误:

INSERT INTO `newtable` 
(`a`, `b`, `c`, `d`) 
SELECT 
`a`, `b`, `c` , `d` FROM `oldtable`

当“newtable”中不存在字段 a 和 c 时。当然,我知道这是一个合法的错误。我想知道的是,有什么方法可以构建类似 case 语句的东西来处理这个问题。该查询是基于动态表动态构建的,因此我无法预先知道存在哪些字段。

你有什么精明的想法?

请注意,新表是动态定义的,如上所述:

public function updateTableSchema($table, $fields)
{
    // Drop the temporary table if exists
    $sql = "
        DROP TABLE IF EXISTS `temp_{$table}`
    ";
    if (!$this->db()->query($sql)) return FALSE;

    // Make a backup of the original table and select the old values into it
    $sql = "
        CREATE TABLE `temp_{$table}`
        SELECT * FROM `$table`
    ";
    if (!$this->db()->query($sql)) return FALSE;

    // Drop the old table
    if (!$this->db()->query("DROP TABLE `$table`")) return FALSE;

    // Recreate the table with the new fields
    $sql = "
        CREATE TABLE IF NOT EXISTS `$table`
        (\n";

        $sql .= "`id` int(11) NOT NULL AUTO_INCREMENT,\n";
        foreach ($fields as $field)
        {
            $sql .= html_entity_decode("`$field` varchar(255) NOT NULL,\n");
        }
        $sql .= "PRIMARY KEY (`id`)\n";

     $sql .= "
        ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1
    ";
    if (!$this->db()->query($sql)) return FALSE;

    CREATE TABLE new_tbl SELECT * FROM orig_tbl;

    // Insert the temporary records into the new table
    $sql = "INSERT INTO `$table` (";
    foreach ($fields as $field)
    {
        $sql .= html_entity_decode("`$field`, ");
    }
    $sql = rtrim($sql, ', ') . ') SELECT ';
    foreach ($fields as $field)
    {
        $sql .= html_entity_decode("`$field`, ");
    }
    $sql = rtrim($sql, ', ') . " FROM `temp_{$table}`"; 
    print $sql;
    if (!$this->db()->query($sql)) return FALSE;

    // Drop the temporary table
    $sql = "DROP TABLE `temp_{$table}`";
    return $this->db()->query($sql);
}

这里的原始表是根据给定表单上存在的表单字段进行更新的,可以随时添加、删除或重命名。新表也需要符合这些变化。

更新: 工作解决方案如下:

public function updateTableSchema($table, $fields)
{
    // Drop the temporary table if exists
    $sql = "
        DROP TABLE IF EXISTS `temp_{$table}`
    ";
    if (!$this->db()->query($sql)) return FALSE;

    // Make a backup of the original table and select the old values into it
    $sql = "
        CREATE TABLE `temp_{$table}`
        SELECT * FROM `$table`
    ";
    if (!$this->db()->query($sql)) return FALSE;

    // Drop the old table
    if (!$this->db()->query("DROP TABLE `$table`")) return FALSE;

    // Recreate the table with the new fields
    $sql = "
        CREATE TABLE IF NOT EXISTS `$table`
        (\n";

        $sql .= "`id` int(11) NOT NULL AUTO_INCREMENT,\n";
        foreach ($fields as $field)
        {
            $sql .= html_entity_decode("`$field` varchar(255) NOT NULL,\n");
        }
        $sql .= "PRIMARY KEY (`id`)\n";

     $sql .= "
        ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1
    ";
    if (!$this->db()->query($sql)) return FALSE;

    // Insert the temporary records into the new table
    $sql = "INSERT INTO `$table` (";
    foreach ($fields as $field)
    {
        $sql .= html_entity_decode("`$field`, ");
    }
    $sql = rtrim($sql, ', ') . ') SELECT ';
    foreach ($fields as $field)
    {
        $sql .= html_entity_decode("`$field`, ");
    }
    $sql = rtrim($sql, ', ') . " FROM `temp_{$table}`";

    try
    {
        $this->db()->query($sql);
    }
    catch (error $e)
    {
        if (preg_match('/Unknown column/', $e->getMessage()))
        {
            $new_field = utility::getStringBetween($e->getMessage(), "'", "'");
            if (!$new_field) return FALSE;

            $this->db()->query("TRUNCATE TABLE `$table`");
            $key = array_search($new_field, $fields);
            $key--;

            // Check if adding after
            if ($key > 0)
            {
                $sql = "
                    ALTER TABLE `temp_{$table}`
                    ADD `$new_field` VARCHAR( 255 ) NOT NULL AFTER `{$fields[$key]}` 
                ";
                if (!$this->db()->query($sql)) return FALSE;
            }
            // Check if adding before
            else
            {
                $sql = "
                    ALTER TABLE `temp_{$table}`
                    ADD `$new_field` VARCHAR( 255 ) NOT NULL FIRST
                ";
                if (!$this->db()->query($sql)) return FALSE;
            }

            // Insert the temporary records into the new table
            $sql = "INSERT INTO `$table` (";
            foreach ($fields as $field)
            {
                $sql .= html_entity_decode("`$field`, ");
            }
            $sql = rtrim($sql, ', ') . ') SELECT ';
            foreach ($fields as $field)
            {
                $sql .= html_entity_decode("`$field`, ");
            }
            $sql = rtrim($sql, ', ') . " FROM `temp_{$table}`";
            if (!$this->db()->query($sql)) return FALSE;
        }
    }

    // Drop the temporary table
    $sql = "DROP TABLE `temp_{$table}`";
    return $this->db()->query($sql);
}

MySQL always throws an error when doing something like:

INSERT INTO `newtable` 
(`a`, `b`, `c`, `d`) 
SELECT 
`a`, `b`, `c` , `d` FROM `oldtable`

when field a and c does not exist in 'newtable'. Of course, I understand this is a legitimate error. What I want to know is, is there any way to build something like a case statement for handling this. The query is dynamically built based on a dynamic table, so there is no way for me to know up front what fields exist.

What are your savvy ideas?

Note that the newtable is defined dynamically as mentioned above:

public function updateTableSchema($table, $fields)
{
    // Drop the temporary table if exists
    $sql = "
        DROP TABLE IF EXISTS `temp_{$table}`
    ";
    if (!$this->db()->query($sql)) return FALSE;

    // Make a backup of the original table and select the old values into it
    $sql = "
        CREATE TABLE `temp_{$table}`
        SELECT * FROM `$table`
    ";
    if (!$this->db()->query($sql)) return FALSE;

    // Drop the old table
    if (!$this->db()->query("DROP TABLE `$table`")) return FALSE;

    // Recreate the table with the new fields
    $sql = "
        CREATE TABLE IF NOT EXISTS `$table`
        (\n";

        $sql .= "`id` int(11) NOT NULL AUTO_INCREMENT,\n";
        foreach ($fields as $field)
        {
            $sql .= html_entity_decode("`$field` varchar(255) NOT NULL,\n");
        }
        $sql .= "PRIMARY KEY (`id`)\n";

     $sql .= "
        ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1
    ";
    if (!$this->db()->query($sql)) return FALSE;

    CREATE TABLE new_tbl SELECT * FROM orig_tbl;

    // Insert the temporary records into the new table
    $sql = "INSERT INTO `$table` (";
    foreach ($fields as $field)
    {
        $sql .= html_entity_decode("`$field`, ");
    }
    $sql = rtrim($sql, ', ') . ') SELECT ';
    foreach ($fields as $field)
    {
        $sql .= html_entity_decode("`$field`, ");
    }
    $sql = rtrim($sql, ', ') . " FROM `temp_{$table}`"; 
    print $sql;
    if (!$this->db()->query($sql)) return FALSE;

    // Drop the temporary table
    $sql = "DROP TABLE `temp_{$table}`";
    return $this->db()->query($sql);
}

The original table here is updated based on the form fields which exist on a given form that may be added to, deleted from or renamed at any time. The new table needs to also be in accordance with these changes.

UPDATE:
Working solution follows:

public function updateTableSchema($table, $fields)
{
    // Drop the temporary table if exists
    $sql = "
        DROP TABLE IF EXISTS `temp_{$table}`
    ";
    if (!$this->db()->query($sql)) return FALSE;

    // Make a backup of the original table and select the old values into it
    $sql = "
        CREATE TABLE `temp_{$table}`
        SELECT * FROM `$table`
    ";
    if (!$this->db()->query($sql)) return FALSE;

    // Drop the old table
    if (!$this->db()->query("DROP TABLE `$table`")) return FALSE;

    // Recreate the table with the new fields
    $sql = "
        CREATE TABLE IF NOT EXISTS `$table`
        (\n";

        $sql .= "`id` int(11) NOT NULL AUTO_INCREMENT,\n";
        foreach ($fields as $field)
        {
            $sql .= html_entity_decode("`$field` varchar(255) NOT NULL,\n");
        }
        $sql .= "PRIMARY KEY (`id`)\n";

     $sql .= "
        ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1
    ";
    if (!$this->db()->query($sql)) return FALSE;

    // Insert the temporary records into the new table
    $sql = "INSERT INTO `$table` (";
    foreach ($fields as $field)
    {
        $sql .= html_entity_decode("`$field`, ");
    }
    $sql = rtrim($sql, ', ') . ') SELECT ';
    foreach ($fields as $field)
    {
        $sql .= html_entity_decode("`$field`, ");
    }
    $sql = rtrim($sql, ', ') . " FROM `temp_{$table}`";

    try
    {
        $this->db()->query($sql);
    }
    catch (error $e)
    {
        if (preg_match('/Unknown column/', $e->getMessage()))
        {
            $new_field = utility::getStringBetween($e->getMessage(), "'", "'");
            if (!$new_field) return FALSE;

            $this->db()->query("TRUNCATE TABLE `$table`");
            $key = array_search($new_field, $fields);
            $key--;

            // Check if adding after
            if ($key > 0)
            {
                $sql = "
                    ALTER TABLE `temp_{$table}`
                    ADD `$new_field` VARCHAR( 255 ) NOT NULL AFTER `{$fields[$key]}` 
                ";
                if (!$this->db()->query($sql)) return FALSE;
            }
            // Check if adding before
            else
            {
                $sql = "
                    ALTER TABLE `temp_{$table}`
                    ADD `$new_field` VARCHAR( 255 ) NOT NULL FIRST
                ";
                if (!$this->db()->query($sql)) return FALSE;
            }

            // Insert the temporary records into the new table
            $sql = "INSERT INTO `$table` (";
            foreach ($fields as $field)
            {
                $sql .= html_entity_decode("`$field`, ");
            }
            $sql = rtrim($sql, ', ') . ') SELECT ';
            foreach ($fields as $field)
            {
                $sql .= html_entity_decode("`$field`, ");
            }
            $sql = rtrim($sql, ', ') . " FROM `temp_{$table}`";
            if (!$this->db()->query($sql)) return FALSE;
        }
    }

    // Drop the temporary table
    $sql = "DROP TABLE `temp_{$table}`";
    return $this->db()->query($sql);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

平生欢 2024-10-11 05:40:58

使用Create Table...Select这里有一些参考

http: //dev.mysql.com/doc/refman/5.0/en/create-table-select.html

http://dev.mysql.com/doc/refman/5.0/en/create-table.html

CREATE TABLE new_tbl SELECT * FROM orig_tbl;

Use Create Table...Select here is some reference

http://dev.mysql.com/doc/refman/5.0/en/create-table-select.html

http://dev.mysql.com/doc/refman/5.0/en/create-table.html

CREATE TABLE new_tbl SELECT * FROM orig_tbl;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文