在这里,我已经编辑了原始问题。 我已经在下一封邮件中回答了。
我正在尝试通过参数化的php PDO查询从MySQL获取结果,但是事情表现得很糟糕。我不知道这是一个错误,还是我做错了什么或看不到明显的东西。
让我们假设数据库中有这两个表
CREATE TABLE `users` (
`user_id` int(11) NOT NULL PRIMARY KEY
)
CREATE TABLE `users_contacts` (
`contact_id` int(11) NOT NULL PRIMARY KEY ,
`user_id` int(11) DEFAULT NULL,
`type` varchar(45) DEFAULT NULL,
`value` varchar(255) DEFAULT NULL
)
用最少的数据填充它们:
INSERT INTO `users` (`user_id`) VALUES (125);
INSERT INTO `users_contacts` (`contact_id`, `user_id`, `type`, `value`)
VALUES(11432, 125, 'email', 'losleyTyped@offten.stinks'),
(11433, 125, 'phone', '1234567'),
(564, 125, 'unit', '910');
然后尝试像这样获取数据
$db_name = "";
$db_user = "";
$db_pass = "";
$db_pdo = new pdo("mysql:host=localhost;dbname=$db_name","$db_user","$db_pass");
$user = 125;
$user_unit_btm = 900;
$user_unit_top = $user_unit_btm + 100;
$upload_user = $db_pdo -> prepare("SELECT K.value AS unit
FROM users AS O,
users_contacts AS K
WHERE O.user_id = :user_id AND
K.user_id = O.user_id AND
K.type = 'unit' AND
K.value >= :unit_btm AND
K.value < :unit_top
");
$upload_user -> execute( [":user_id" => $user,
":unit_btm" => $user_unit_btm,
":unit_top" => $user_unit_top
]
);
$upload_user = $upload_user -> fetch(PDO::FETCH_ASSOC);
var_dump($upload_user);
var_dump将返回false,但没有错误(错误为0000)
我减少了这个问题,发现只有一个参数“:organization”是有问题的,并且会导致bizare行为。
但是如果您替换“ K.value <:unit_top“
带有变量$ user_unit_top
“ K.value <$ user_unit_top”
然后,查询返回结果!
如果我用文字1000替换“ K.value <:unit_top”,也是一样,
“ K.value <100”
然后查询返回结果!
为什么会这样?
答案 0 :(得分:0)
这是一个答案,如果有人发现他自己也有类似问题
为什么会这样?
我认为这是因为Php或MySQL身份类型识别/广播
看看表var FAQfor3Months = new Dictionary<string, int>();
var FAQfor4to12Months = new Dictionary<string, int>();
var FAQfor12plusMonths = new Dictionary<string, int>();
foreach (Activity call in CallsForProperty) {
if ( /*call is in 3 months*/ ) {
//do some unrelated stuff
FAQfor3Months.TryGetValue(call.callQuestion, out int count);
FAQfor3Months[call.callQuestion] = count+1;
}
}
var top3ThreeMonthFaqs = FAQfor3Months.OrderByDescending(kvp => kvp.Value).Take(3).Select(kvp => kvp.Key).ToList();
,名为“值”的列的类型为VARCHAR(因为该表类似于EAV数据模型)
在此行的问题中准备好的查询中
users_contacts
PHP / MySQL假设参数:unit_top与K.value列(VARCHAR)具有相同的数据类型,因此它像字符串???一样对它们进行比较-排序,字符串“ 910”后面是“ 1000”。 br /> 如果将变量“:unit_top”替换为变量$ user_unit_top
K.value < :unit_top
或文字
K.value < $user_unit_top
然后Php在进行数值比较,“ 1000”比“ 910”大
*如果将名为“值”的表K.value < 1000
列从VARCHAR更改为INT,则
users_contacts
比较将是数字
我认为这是非常不一致的行为,因为如果您进行以下操作
K.value < :unit_top
PHP将执行自动类型转换,然后进行数字比较,...
我错了吗?
答案 1 :(得分:0)
如我对您的答案的评论中所述。
关于PDOStatement::execute
的PHP文档。
一个值数组,其中元素的数量与正在执行的SQL语句中绑定的参数一样多。所有值都被视为
PDO::PARAM_STR
。
来源:https://www.php.net/manual/en/pdostatement.execute.php
如果没有更多结果或失败,则PDOStatement::fetch()
返回false
。
此函数成功返回的值取决于访存类型。在所有情况下,
FALSE
将在失败时返回。
$pdo = new \PDO('sqlite::memory:', null, null, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
$pdo->query('CREATE TABLE foo(id INTEGER)');
$stmt = $pdo->prepare('SELECT * FROM foo');
$stmt->execute();
var_dump($stmt->fetch());
//bool(false)
如果您需要为发送给MySQL的参数明确定义数据类型(PDO::PARAM_STR
除外),则可以使用PDOStatement::bindParam
或PDOStatement::bindValue
示例:
$upload_user = $db_pdo->prepare('SELECT
K.value AS unit
FROM users AS O,
users_contacts AS K
WHERE O.user_id = :user_id
AND K.user_id = O.user_id
AND K.type = \'unit\'
AND K.value >= :unit_btm
AND K.value < :unit_top');
$upload_user->bindValue(':user_id', $user, PDO::PARAM_INT);
$upload_user->bindValue(':unit_btm', $user_unit_btm, PDO::PARAM_INT);
$upload_user->bindValue(':unit_top', $user_unit_top, PDO::PARAM_INT);
$upload_user->execute();
另一种选择是强制对查询中的参数进行数据类型转换。
$upload_user = $db_pdo->prepare('SELECT
K.value AS unit
FROM users AS O,
users_contacts AS K
WHERE O.user_id = :user_id
AND K.user_id = O.user_id
AND K.type = \'unit\'
AND K.value >= (:unit_btm - 0)
AND K.value < (:unit_top - 0)'); //CAST(:unit_top AS SIGNED)
$upload_user->execute([
':user_id' => $user,
':unit_btm' => $user_unit_btm,
':unit_top' => $user_unit_top
]);
另一个导致您遇到问题的因素是,MySQL将自动转换为列的数据类型以进行比较。其他RDMBS(例如PostgreSQL和SQLite3)不执行相同的转换。
当运算符与不同类型的操作数一起使用时,请键入 进行转换以使操作数兼容。一些转换 隐式发生。例如,MySQL自动将字符串转换为 编号,反之亦然。
来源:https://dev.mysql.com/doc/refman/5.7/en/type-conversion.html
由于您的初始列数据类型为VARCHAR
,因此测试得出了以下结果。
DB Fiddle
初始查询为PDOStatement::execute([1000])
。
SELECT IF('910' > '1000', 'fail', 'pass') AS if_str_to_str;
| if_str_to_str |
| ------------- |
| fail |
手动为查询提供整数
SELECT IF('910' > 1000, 'fail', 'pass') AS if_str_to_int;
| if_str_to_int |
| ------------- |
| pass |
更改数据库列数据类型并使用PDOStatement::execute([1000])
SELECT IF(910 > '1000', 'fail', 'pass') AS if_int_to_str;
| if_int_to_str |
| ------------- |
| pass |
使用PDOStatement::bindValue(':param', '1000', PDO::PARAM_INT)
或('1000' - 0)
SELECT IF('910' > CAST('1000' AS SIGNED), 'fail', 'pass') AS if_str_to_typecast_int;
| if_str_to_typecast_int |
| ---------------------- |
| pass |