我使用PHP来获取搜索表单的价格和大小标准,并在下面构建MySQL查询。表中的price字段是INT,租用字段是FLOAT,size字段是VARCHAR,因为该值包含度量单位。
下面的查询使用PHP脚本运行并返回零记录。我直接在表上运行它,它返回173条记录。当我直接运行时,我将 0 的PDO占位符替换为两者的最小值, 10000000 最大价格, 1000 < / strong> size_unit0 size_unit0 尺寸,尺寸 尺寸,它返回173条记录。除了零售业务外,我可以无条件地找到它,应该有9条记录。
我对替换PHP代码中的size_unit占位符的值执行了var_dump,它们是浮点数。
该表从房地产关联中导入数据,这就是size字段为VARCHAR的原因。
我感到困惑。
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.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 CODE创建查询
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.'
';
答案 0 :(得分:1)
我很惊讶您没有看到错误消息
警告:PDOStatement :: execute():SQLSTATE [HY093]:参数号无效:绑定变量数与令牌数不匹配
PDO不会将变量绑定到: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值绑定为整数,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
您将得到不正确的结果。更好的方法是在将所有大小保存到数据库之前将其转换为一个单元,然后根据需要将用户的请求转换为相同的单元。