我试图将数据从一个数据库复制到另一个数据库。两者都具有100%相同的结构。
当我通过PDO获取一行时,对于布尔字段,我得到整数0/1而不是本机false / true。当我尝试使用PDO将数据插入第二个数据库时导致此错误消息,这是一个问题:
column "disabled" is of type boolean but expression is of type integer
有一个简单的方法吗?我不知道的选项?因为我在这里谈论数百个不同的布尔字段。单独施放它们是不可能的。如果没有简单的方法,我将不得不阅读列类型并采取行动。但我觉得PDO为什么会这样做。
我正在使用Postgres 9.0.1和PHP 5.5.6
其他信息:
以下是一些相关的代码片段。对不起,代码太复杂了,无法显示所有内容。 适用于所有字段,但布尔:
$db = new PDO(
"pgsql:host=$host;port=$port;dbname=$name",
$user,
$pass,
array(
PDO::ATTR_PERSISTENT => $persistent,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
)
);
$sql = 'SELECT * FROM ...'
$sth = $db->query($sql);
$row = $sth->fetch(PDO::FETCH_ASSOC);
$sql = "INSERT INTO $tableName (".implode(', ',$cols).") VALUES (:".implode(', :', $cols).")";
$sthInsert = $dbInsert->prepare($sql);
foreach ($row as $k=>&$v) {
$sthInsert->bindParam($k, $v);
}
$sthInsert->execute();
答案 0 :(得分:3)
不是正确处理布尔值的列的检索,而是后续绑定值。
您可以通过简单的选择来检查:
$result = $db->query('Select true as test_truth, false as test_falsehood;');
foreach ( $x as $row ) { var_dump($row); }
/*
array(2) {
["test_truth"]=>
bool(true)
["test_falsehood"]=>
bool(false)
}
*/
问题是当在后续准备好的查询中绑定变量时,PDO会将其强制转换为字符串,因为$data_type
中PDOStatement::bindParam
的默认值为PDO::PARAM_STR
({{ 3}})。
(string)true
为'1'
,(string)false
为''
。然后将这些传递给Postgres连接,该连接无法将它们转换回布尔值,从而产生错误。
因此,解决方法不需要任何有关预期数据类型的元数据,只需要传入的值的实际类型。一种方法是:
if ( is_bool($value) ) {
$value = ( $value ? 't' : 'f' );
}
$statement->bindParam($k, $value);
这有效地使用't'
和'f'
创建了对字符串的替代广告,这些广告分别是Postgres的默认代表true
和false
。
或者,您可以根据PHP变量类型设置参数类型:
switch ( gettype($param) ) {
case 'boolean':
$param_type = PDO::PARAM_BOOL;
break;
// other cases here as necessary
// see http://php.net/gettype and http://php.net/manual/en/pdo.constants.php
default:
$param_type = PDO_PARAM_STR;
break;
}
$statement->bindParam($k, $param, $param_type);
答案 1 :(得分:2)
不回答您的问题,而是提出一种更直接的方法,并在SQL
中完成所有操作,避免insert into t (col1, col2)
select a, b
from dblink('dbname=the_other_db', 'select a, b from t') as t_other(a integer, b boolean)
过境:
PHP
http://www.postgresql.org/docs/current/static/dblink.html
如果在SQL
中进行了一些您不知道该怎么做的处理ssh jenkins@host "-Xmx6g -verbose:gc -Xloggc:/path/to/GC.lo /path/to/java -jar /path/to/slave.jar"
在另一个问题中询问它。
答案 2 :(得分:0)
好的,这似乎是最快捷的方式。它有效,但我认为这是一个错误,直到有人能解释为什么需要这样做:
$sql = "SELECT column_name, data_type FROM information_schema.columns WHERE table_name = '$tableName'";
$typeRows = DBH::fetchAll($sql);
foreach ($typeRows as &$tr) {
$columnTypes[$tr['column_name']] = $tr['data_type'];
} unset($tr);
...
switch ($columnTypes[$k]) {
case 'boolean' :
$v = $v==1;
$sthInsert->bindParam($k, $v, PDO::PARAM_BOOL);
break;
default :
$sthInsert->bindParam($k, $v);
}
答案 3 :(得分:0)
你有一个数组$cols
我不知道那是什么,但我已经提出了一个解决方案,如果你不想从另一个答案中提出的数据库中获取信息,如何定义它。此外,我还认为您需要将:
添加到bindParam
键值。
$cols = array('col1' => 's', 'col2' => 'b');
$sql = "INSERT INTO $tableName (".implode(', ',array_keys($cols)).") VALUES (:".implode(', :', array_keys($cols)).")";
$sthInsert = $dbInsert->prepare($sql);
foreach ($row as $k=>&$v) {
switch($cols[$k]){
// null
case 'n':
$sthInsert->bindParam(':' . $k, $v, PDO::PARAM_NULL);
break;
// bool
case 'b':
$sthInsert->bindParam(':' . $k, $v, PDO::PARAM_BOOL);
break;
// int
case 'i':
$sthInsert->bindParam(':' . $k, $v, PDO::PARAM_INT);
break;
// str
case 's':
$sthInsert->bindParam(':' . $k, $v, PDO::PARAM_STR);
break;
// lob
case 'l':
$sthInsert->bindParam(':' . $k, $v, PDO::PARAM_LOB);
break;
default:
$sthInsert->bindParam(':' . $k, $v);
break;
}
}