我是PDO的初学者,我在做一个php函数来返回航班的搜索结果,这是我的代码:

$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;
}

问题是,它总是返回0个搜索结果。我试图在phpMyAdmin中手动运行通过函数生成的SQL,发现问题在于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");

我得到“无效参数号:绑定变量数与令牌数不匹配”错误。
谢谢你的帮助!
更新:
我的“flights”表结构是:
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
为了确定将params与PDO(不带单引号的语句)绑定后SQL语句的外观,我在函数的开头创建了一个与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()时,它只获取剩余的行。它不能回去取第一排,那是丢失的。因此,如果查询结果只有一行,就永远看不到它。
相反,我建议使用以下代码:
$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 on my virtual machine):
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确实在参数化的值(如果是字符串或日期)周围加了引号。

07-24 18:00
查看更多