替换和演员比较

时间:2016-03-17 21:17:22

标签: php mysql pdo

我使用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.'
';

1 个答案:

答案 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您将得到不正确的结果。更好的方法是在将所有大小保存到数据库之前将其转换为一个单元,然后根据需要将用户的请求转换为相同的单元。