php - 替换并强制转换以进行比较

标签 php mysql pdo

我正在使用 PHP 获取搜索表单的价格和大小标准,并构建下面的 MySQL 查询。表中的价格字段是 INT,租赁字段是 FLOAT,大小字段是 VARCHAR,因为该值包含计量单位。

下面的查询使用 PHP 脚本运行并返回零条记录。我直接在表上运行它,它返回 173 条记录。当我直接运行它时,我将 PDO 占位符替换为 0 表示两者的最小值,10000000 表示最高价格1000 表示最大尺寸ft 表示size_unit0sqft 表示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/

相关文章:

php - 有什么软件可以做文件(PHP源码)对比

php - Azure主动拒绝MySQL连接

php - 身份不明的 PHP 和 PDO 执行时间较长

带有 REGEXP 的 PHP PDO 准备语句

mysql - 如果无需 JOIN 就可以从多个表中进行选择,为什么还要使用 JOIN?

php - 如何在 Heroku/PHP 5.6 环境中设置具有故障转移支持的 Memcached?

php - 将数据从textarea保存到数据库

php - 如何使用 php、mysql 和 jQuery 将每一行及其主键单独存储在数据库中

php - 如何选择表中多个值的最大年份?

php - SESSION 变量不会继续到下一页