MySQL 在执行以下操作时总是抛出错误:
INSERT INTO `newtable`
(`a`, `b`, `c`, `d`)
SELECT
`a`, `b`, `c` , `d` FROM `oldtable`
当“newtable”中不存在字段 a 和 c 时。当然,我理解这是一个合法的错误。我想知道的是,有什么方法可以构建类似案例声明的东西来处理这个问题。该查询是基于动态表动态构建的,因此我无法预先知道存在哪些字段。
你有什么精明的想法?
请注意,newtable 是如上所述动态定义的:
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);
}