日期不工作的 PDO bindParam
PDO bindParam for date not working
我是 PDO 的初学者,我正在制作一个 php 函数来 return 航班搜索结果,这是我的代码:
$db = DB::getConnection();
$stmt = $db->prepare("SELECT * FROM `flights` WHERE `date` BETWEEN :befDate AND :aftDate
AND `from` = :from
AND `to` = :to
AND `weight` >= :weight");
$stmt->bindParam(':befDate', $befDate, PDO::PARAM_STR); //$befDate = '2016-07-21';
$stmt->bindParam(':aftDate', $aftDate, PDO::PARAM_STR); //$aftDate = '2016-07-28';
$stmt->bindParam(':from', $from, PDO::PARAM_INT);
$stmt->bindParam(':to', $to, PDO::PARAM_INT);
$stmt->bindParam(':weight', $weight, PDO::PARAM_INT);
$ok = $stmt->execute();
if ($ok) {
if ($stmt->fetchColumn()>=1) {
$result = $stmt->fetchAll();
}
else{
$result = 'nope';
}
return $result;
}
else{
return false;
}
问题是,它总是 returning 0 个搜索结果。我尝试 运行 我的 SQL 通过 phpMyAdmin 中的函数手动生成,发现问题是因为 PDO 生成的 SQL 是:
"SELECT * FROM `FLIGHTS` WHERE `DATE` BETWEEN 2016-07-17 AND 2016-07-25 AND `FROM` = 1237 AND `TO` = 2380 AND `WEIGHT` >= 4"
而我得到结果的正确 SQL 应该是:
"SELECT * FROM `FLIGHTS` WHERE `DATE` BETWEEN '2016-07-17' AND '2016-07-25' AND `FROM` = 1237 AND `TO` = 2380 AND `WEIGHT` >= 4"
即,在单引号之间包含日期值。现在,如果我在 PDO 中为我的 SQL 添加引号,例如:
$stmt = $db->prepare("SELECT * FROM `flights` WHERE `date` BETWEEN ':befDate' AND ':aftDate'
AND `from` = :from
AND `to` = :to
AND `weight` >= :weight");
我收到 "Invalid parameter number: number of bound variables does not match number of tokens" 错误。
提前感谢您的帮助!
更新:
我的"flights"table结构是:
CREATE TABLE `flights` (
`fid` int(30) NOT NULL,
`user_id` int(30) NOT NULL,
`date` date NOT NULL,
`from` int(30) NOT NULL,
`to` int(30) NOT NULL,
`weight` int(30) NOT NULL,
`size` varchar(30) NOT NULL,
`details` varchar(200) NOT NULL,
`price` int(50) NOT NULL,
`airline` varchar(100) NOT NULL,
`pnr` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
我尝试从查询中删除所有引号并将其也放在一个完整的行中:
$stmt = $db->prepare("SELECT * FROM flights WHERE date BETWEEN :befDate AND :aftDate AND from = :from AND to = :to AND weight >= :weight");
但还是不行...
更新 2
为了确定 SQL 语句在将参数与 PDO 绑定后的样子(没有单引号的语句),我在函数的开头创建了一个与我的 SQL 相同的会话变量,并回显它以查看结果:
$_SESSION['err'] = "SELECT * FROM flights WHERE date BETWEEN $befDate AND $aftDate
AND from = $from
AND to = $to
AND weight >= $weight";
这是您的主要问题:
if ($stmt->fetchColumn()>=1) {
$result = $stmt->fetchAll();
}
else{
$result = 'nope';
}
调用 fetchColumn() 使结果集超过其第一行。然后,当您调用 fetchAll() 时,它只会获取 remaining 行。它不能返回并获取第一行,那已经丢失了。因此,如果您的查询结果只有一行,您将永远看不到它。
相反,我建议使用以下代码:
$result = $stmt->fetchAll();
if (empty($result)) {
$result = "nope";
}
其他提示:
切勿将参数占位符放在引号内。如果这样做,它们就不再是参数占位符,它们只是像“:befDate”这样的文字字符串。这些不是有效的日期文字。
BETWEEN :befDate AND :aftDate
等表达式中的参数不会生成 BETWEEN 2016-07-17 AND 2016-07-25
作为查询。参数永远不会成为那样的表达式,它们总是成为每个参数的标量值(例如带引号的日期文字)。
我试过你的代码。首先我启用了 MySQL 一般查询日志:
mysql> SET GLOBAL general_log = ON;
现在我可以准确地看到 MySQL 认为是 PDO 提交的查询。我 运行 PHP 脚本,并阅读我的一般查询日志(/var/lib/mysql/localhost.log 在我的虚拟机上):
160716 19:26:16 8 Connect root@localhost on test
8 Query SELECT * FROM `flights` WHERE `date` BETWEEN NULL AND NULL
AND `from` = NULL
AND `to` = NULL
AND `weight` >= NULL
8 Quit
啊,我忘记给参数绑定的变量设置值了。如果这些变量中的任何一个都没有值,这将解释为什么结果为空,因为与 NULL 的任何比较都是不正确的。所以我编辑了 PHP 以首先将示例值设置为变量。
$befDate = '2016-07-21';
$aftDate = '2016-07-28';
$from = 1;
$to = 2;
$weight = 10;
我再次运行查询,在日志中我看到以下内容:
160716 19:33:17 13 Query SELECT * FROM `flights` WHERE `date` BETWEEN '2016-07-21' AND '2016-07-28'
AND `from` = 1
AND `to` = 2
AND `weight` >= 10
这证明 PDO 确实在参数化值周围加上引号(如果它是字符串或日期)。
我是 PDO 的初学者,我正在制作一个 php 函数来 return 航班搜索结果,这是我的代码:
$db = DB::getConnection();
$stmt = $db->prepare("SELECT * FROM `flights` WHERE `date` BETWEEN :befDate AND :aftDate
AND `from` = :from
AND `to` = :to
AND `weight` >= :weight");
$stmt->bindParam(':befDate', $befDate, PDO::PARAM_STR); //$befDate = '2016-07-21';
$stmt->bindParam(':aftDate', $aftDate, PDO::PARAM_STR); //$aftDate = '2016-07-28';
$stmt->bindParam(':from', $from, PDO::PARAM_INT);
$stmt->bindParam(':to', $to, PDO::PARAM_INT);
$stmt->bindParam(':weight', $weight, PDO::PARAM_INT);
$ok = $stmt->execute();
if ($ok) {
if ($stmt->fetchColumn()>=1) {
$result = $stmt->fetchAll();
}
else{
$result = 'nope';
}
return $result;
}
else{
return false;
}
问题是,它总是 returning 0 个搜索结果。我尝试 运行 我的 SQL 通过 phpMyAdmin 中的函数手动生成,发现问题是因为 PDO 生成的 SQL 是:
"SELECT * FROM `FLIGHTS` WHERE `DATE` BETWEEN 2016-07-17 AND 2016-07-25 AND `FROM` = 1237 AND `TO` = 2380 AND `WEIGHT` >= 4"
而我得到结果的正确 SQL 应该是:
"SELECT * FROM `FLIGHTS` WHERE `DATE` BETWEEN '2016-07-17' AND '2016-07-25' AND `FROM` = 1237 AND `TO` = 2380 AND `WEIGHT` >= 4"
即,在单引号之间包含日期值。现在,如果我在 PDO 中为我的 SQL 添加引号,例如:
$stmt = $db->prepare("SELECT * FROM `flights` WHERE `date` BETWEEN ':befDate' AND ':aftDate'
AND `from` = :from
AND `to` = :to
AND `weight` >= :weight");
我收到 "Invalid parameter number: number of bound variables does not match number of tokens" 错误。 提前感谢您的帮助!
更新:
我的"flights"table结构是:
CREATE TABLE `flights` (
`fid` int(30) NOT NULL,
`user_id` int(30) NOT NULL,
`date` date NOT NULL,
`from` int(30) NOT NULL,
`to` int(30) NOT NULL,
`weight` int(30) NOT NULL,
`size` varchar(30) NOT NULL,
`details` varchar(200) NOT NULL,
`price` int(50) NOT NULL,
`airline` varchar(100) NOT NULL,
`pnr` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
我尝试从查询中删除所有引号并将其也放在一个完整的行中:
$stmt = $db->prepare("SELECT * FROM flights WHERE date BETWEEN :befDate AND :aftDate AND from = :from AND to = :to AND weight >= :weight");
但还是不行...
更新 2 为了确定 SQL 语句在将参数与 PDO 绑定后的样子(没有单引号的语句),我在函数的开头创建了一个与我的 SQL 相同的会话变量,并回显它以查看结果:
$_SESSION['err'] = "SELECT * FROM flights WHERE date BETWEEN $befDate AND $aftDate
AND from = $from
AND to = $to
AND weight >= $weight";
这是您的主要问题:
if ($stmt->fetchColumn()>=1) {
$result = $stmt->fetchAll();
}
else{
$result = 'nope';
}
调用 fetchColumn() 使结果集超过其第一行。然后,当您调用 fetchAll() 时,它只会获取 remaining 行。它不能返回并获取第一行,那已经丢失了。因此,如果您的查询结果只有一行,您将永远看不到它。
相反,我建议使用以下代码:
$result = $stmt->fetchAll();
if (empty($result)) {
$result = "nope";
}
其他提示:
切勿将参数占位符放在引号内。如果这样做,它们就不再是参数占位符,它们只是像“:befDate”这样的文字字符串。这些不是有效的日期文字。
BETWEEN :befDate AND :aftDate
等表达式中的参数不会生成 BETWEEN 2016-07-17 AND 2016-07-25
作为查询。参数永远不会成为那样的表达式,它们总是成为每个参数的标量值(例如带引号的日期文字)。
我试过你的代码。首先我启用了 MySQL 一般查询日志:
mysql> SET GLOBAL general_log = ON;
现在我可以准确地看到 MySQL 认为是 PDO 提交的查询。我 运行 PHP 脚本,并阅读我的一般查询日志(/var/lib/mysql/localhost.log 在我的虚拟机上):
160716 19:26:16 8 Connect root@localhost on test
8 Query SELECT * FROM `flights` WHERE `date` BETWEEN NULL AND NULL
AND `from` = NULL
AND `to` = NULL
AND `weight` >= NULL
8 Quit
啊,我忘记给参数绑定的变量设置值了。如果这些变量中的任何一个都没有值,这将解释为什么结果为空,因为与 NULL 的任何比较都是不正确的。所以我编辑了 PHP 以首先将示例值设置为变量。
$befDate = '2016-07-21';
$aftDate = '2016-07-28';
$from = 1;
$to = 2;
$weight = 10;
我再次运行查询,在日志中我看到以下内容:
160716 19:33:17 13 Query SELECT * FROM `flights` WHERE `date` BETWEEN '2016-07-21' AND '2016-07-28'
AND `from` = 1
AND `to` = 2
AND `weight` >= 10
这证明 PDO 确实在参数化值周围加上引号(如果它是字符串或日期)。