我正在使用 PHP 获取搜索表单的价格和大小标准,并构建下面的 MySQL 查询。表中的价格字段是 INT,租赁字段是 FLOAT,大小字段是 VARCHAR,因为该值包含计量单位。
下面的查询使用 PHP 脚本运行并返回零条记录。我直接在表上运行它,它返回 173 条记录。当我直接运行它时,我将 PDO 占位符替换为 0 表示两者的最小值,10000000 表示最高价格,1000 表示最大尺寸,ft 表示size_unit0,sqft 表示size_unit1,它返回 173 条记录。据我查到,除了零售业务外,没有任何条件,应该有9条记录。
我对替换 PHP 代码中 size_unit 占位符的值进行了 var_dump,它们是 float 。
该表从房地产协会导入数据,这就是大小字段为 VARCHAR 的原因。
我很困惑。
查询
SELECT lt.Price, lt.Lease, lt.LeasePerUnit,
IF (lt.Price >= :minimum_price AND
lt.Price <= :maximum_price,
REPLACE(
FORMAT(lt.Price, 2), ".00", ""),
CONCAT(REPLACE(FORMAT(lt.Lease, 2), ".00", ""), "/", lt.LeasePerUnit)
) AS DisplayPrice,
IF (lt.Price >= :minimum_price AND
lt.Price <= :maximum_price,
REPLACE(lt.Price, ".00", ""), REPLACE(lt.Lease, ".00", "")
) AS DisplayPriceSort,
lt.ListingId AS MlsNumber, lt.PropertyId, lt.PropertyType,
lt.StreetAddress AS Address, lt.City, lt.PublicRemarks,
lt.ListAgent1Id, lt.ListAgent2Id
FROM listings AS lt
WHERE 1 = 1 AND lt.PropertyType = "Retail"
AND (
(lt.Price >= :minimum_price AND lt.Price <= :maximum_price) OR
(lt.Lease >= :minimum_price AND lt.Lease <= :maximum_price)
)
AND (
(
REPLACE(lt.SizeFrontage, ' :size_unit0', '') >= :minimum_size
AND REPLACE(lt.SizeFrontage, ' :size_unit0', '') <= :maximum_size
) OR
(
REPLACE(lt.SizeInterior, ' :size_unit0', '') >= :minimum_size
AND REPLACE(lt.SizeInterior, ' :size_unit0', '') <= :maximum_size
) OR
(
REPLACE(lt.SizeTotal, ' :size_unit0', '') >= :minimum_size
AND REPLACE(lt.SizeTotal, ' :size_unit0', '') <= :maximum_size
) OR
(
REPLACE(lt.SizeFrontage, ' :size_unit1', '') >= :minimum_size
AND REPLACE(lt.SizeFrontage, ' :size_unit1', '') <= :maximum_size
) OR
(
REPLACE(lt.SizeInterior, ' :size_unit1', '') >= :minimum_size
AND REPLACE(lt.SizeInterior, ' :size_unit1', '') <= :maximum_size
) OR
(
REPLACE(lt.SizeTotal, ' :size_unit1', '') >= :minimum_size
AND REPLACE(lt.SizeTotal, ' :size_unit1', '') <= :maximum_size
)
)
ORDER BY DisplayPriceSort * 1 DESC
适用的 PHP 代码创建查询
if (isset($minimum_price) && isset($maximum_price) && !isset($featured_mls_number) && !isset($mls_number))
{
if ($transaction_type != '')
{
if ($transaction_type == 'for_lease')
{
$where .= ' AND (lt.Lease >= :minimum_price AND lt.Lease <= :maximum_price)';
}
elseif ($transaction_type == 'for_sale')
{
$where .= ' AND (lt.Price >= :minimum_price AND lt.Price <= :maximum_price)';
}
}
elseif (($transaction_type != '' && $transaction_type == 'for_sale_or_rent') || $transaction_type == '')
{
$where .= ' AND ((lt.Price >= :minimum_price AND lt.Price <= :maximum_price) OR (lt.Lease >= :minimum_price AND lt.Lease <= :maximum_price))';
}
$execute_array[':minimum_price'] = $minimum_price;
$execute_array[':maximum_price'] = $maximum_price;
}
else
{
$execute_array[':minimum_price'] = 0;
$execute_array[':maximum_price'] = 100000000;
}
if (isset($minimum_size) && isset($maximum_size) && !isset($featured_mls_number) && !isset($mls_number))
{
#SizeFrontage, SizeInterior, SizeTotal
foreach ($size_units_array as $su_key => $su_value)
{
$size_unit_lower = strtolower($su_key);
if ($size_unit_lower == $size_unit)
{
$where .= " AND (";
for ($i = 0; $i < count($su_value); $i++)
{
$where .=
"
(REPLACE(lt.SizeFrontage, CONCAT(' ', :size_unit".$i."), '') >= :minimum_size
AND REPLACE(lt.SizeFrontage, CONCAT(' ', :size_unit".$i."), '') <= :maximum_size)
OR (REPLACE(lt.SizeInterior, CONCAT(' ', :size_unit".$i."), '') >= :minimum_size
AND REPLACE(lt.SizeInterior, CONCAT(' ', :size_unit".$i."), '') <= :maximum_size)
OR (REPLACE(lt.SizeTotal, CONCAT(' ', :size_unit".$i."), '') >= :minimum_size
AND REPLACE(lt.SizeTotal, CONCAT(' ', :size_unit".$i."), '') <= :maximum_size)
";
$execute_array[':size_unit'.$i] = $su_value[$i];
if ($i != count($su_value) - 1) $where .= " OR ";
}
$where .= ")";
}
$execute_array[':minimum_size'] = $minimum_size;
$execute_array[':maximum_size'] = $maximum_size;
}
}
$query =
'
SELECT lt.Price, lt.Lease, lt.LeasePerUnit,
IF (lt.Price >= :minimum_price AND lt.Price <= :maximum_price,
REPLACE(FORMAT(lt.Price, 2), ".00", ""), CONCAT(REPLACE(FORMAT(lt.Lease, 2),
".00", ""), "/", lt.LeasePerUnit)) AS DisplayPrice,
IF (lt.Price >= :minimum_price AND lt.Price <= :maximum_price,
REPLACE(lt.Price, ".00", ""), REPLACE(lt.Lease, ".00", "")) AS DisplayPriceSort,
lt.ListingId AS MlsNumber, lt.PropertyId, lt.PropertyType,
lt.StreetAddress AS Address, lt.City, lt.BedroomsTotal, lt.BathroomTotal,
lt.PublicRemarks, lt.ListAgent1Id, lt.ListAgent2Id,
ListAgent1OfficeName, ListAgent2OfficeName
FROM listings AS lt
WHERE '.$where.'
ORDER BY '.$sort_by.'
';
最佳答案
我很惊讶您没有看到错误消息
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
PDO 不会将变量绑定(bind)到 :size_unitN
参数,因为它们位于 SQL 查询中的单引号内。这意味着它们被视为文字字符串“:size_unitN”。
相反,您应该将参数移到带引号的字符串之外,并使用 CONCAT
在它们前面添加空格,例如
REPLACE(lt.SizeFrontage, ' :size_unit0', '') >= :minimum_size
应替换为:
REPLACE(lt.SizeFrontage, CONCAT(' ', :size_unit0), '') >= :minimum_size
如果尺寸数据始终采用整数后跟空格后跟字母单位的格式,则可能根本不需要使用 REPLACE
函数。如果你明确地将minimum_size和maximum_size值绑定(bind)为整数,MySQL也会将列转换为整数来进行比较。例如
$q = $pdo->prepare(
"SELECT * FROM listings WHERE SizeFrontage > :min AND SizeFrontage < :max");
$q->bindValue(":min", 10, PDO::PARAM_INT);
$q->bindValue(":max", 35, PDO::PARAM_INT);
您应该考虑改进数据模型。目前您的查询效率将非常低。如果您将大小作为整数存储在数据库中,则搜索速度会更快,特别是因为您可以对字段建立索引。如果您有大量记录,这可能是一个特别值得关注的问题。
如果记录使用不同的单位存储在数据库中(例如,有些以平方米为单位,有些以平方英尺为单位),您在任何时候都只能使用REPLACE
搜索其中的一些记录> 语法,并且使用 PDO::PARAM_INT
会得到不正确的结果。更好的方法是在将所有尺寸保存到数据库之前将它们转换为一个单位,然后根据需要将用户的请求转换为相同的单位。
关于php - 替换并强制转换以进行比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36071845/