【问题标题】:Creating a SQL query with OR statements based on whether or not checkboxes have been ticked根据是否选中复选框,使用 OR 语句创建 SQL 查询
【发布时间】:2019-06-10 19:58:45
【问题描述】:

我正在为一个学校项目构建一个搜索引擎,旨在让用户浏览一个庞大的学校数据库,我已经将它设置为在一个页面上,用户可以勾选某些复选框,并且在点击提交后,用户将返回与勾选内容相对应的学校列表。

允许用户根据多个参数在全国范围内搜索学校:

  • 学校类型(高中、初中、贸易学校、大学等...)
  • 学校状况(私立或公立)
  • 城市
  • 状态

对于我的问题,我将只关注与学校类型相关的部分,因为稍后我可以将逻辑与其他功能类似的表单元素一起应用。

对于学校类型以及许多其他表单元素,我决定使用复选框,例如,如果用户希望搜索返回初中和高中,他只需勾选两者“初中”和“高中”复选框。

因此,这意味着在我的搜索中使用OR 语句,例如,我会使用这样的 SQL 查询:

SELECT schools.schoolId, schools.schoolName, villages.villageName FROM schools, villages
WHERE schools.villageId = villages.villageId

这里是我要设置的条件,即查询只返回与中学、高中和贸易学校有关的信息:

AND (schools.schoolType = "MiddleSchool" OR schools.schoolType = "HighSchool" OR schools.schoolType = "TradeSchool")

我遇到问题的是这个语句的构造。

事实上,因为学校类型会随着数据库的发展而变化,所以我不能硬编码我的查询结构,我也不希望这样做。

我使用 PHP 根据表单结果生成查询。

为了生成所有可用学校类型的列表,我使用 DISTINCT 查询从数据库 (MySQL) 中读取了所有现有学校类型。我用它来构建所有可用学校类型的列表,我用它来生成搜索表单。

因此,我必须使用类似的方法将表单结果与数据库进行比较,这意味着,在我的结果页面上,要查看哪些复选框已被勾选,我需要查看当前可能存在哪些复选框表单已发送,所以我再次从数据库中读取所有可用类型:(一些代码被截断,这只是我使用的查询,我知道它有效,但这只是为了上下文)

try 
{
    $pdo = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
    $req_sql_type_school = "SELECT DISTINCT schoolType AS types FROM schools";
    $res_type_schools = $pdo->query($req_sql_type_school);
    $res_type_schools->setFetchMode(PDO::FETCH_ASSOC);
} catch (PDOException $e) 
{
    die("Could not connect to the database $dbname :" . $e->getMessage());
}

之后,我遍历查询结果以创建学校类型的数组:(我知道这也可以,但同样,它只是为了上下文)

$arrayTypes = array();
while ($row = $res_type_schools->fetch())
{
    $arrayTypes[]=$row['types'];
}

那么,这就是我挣扎的地方。正是在这一点上,我必须在上面提到的查询的开头创建“AND...”语句,即:

SELECT schools.schoolId, schools.schoolName, villages.villageName FROM schools, villages
WHERE schools.villageId = villages.villageId

为了查看用户是否勾选了某些内容,我遍历数组以检查相应的复选框是否被勾选。为此,这是我编写的代码。注意:basictext() 只是将字符串格式化为我用于复选框值的格式,这是只有小写字母的字符串,没有空格和重音符号):

foreach($arrayTypes as $arr)
{
    if(isSet($_GET[basictext($arr)]))
    {
        echo "[x] Type ".$arr." <br/>";
    } 
    else 
    { 
        echo "[ ] Type ".$arr." <br/>"; 
    }
}

这使我可以检查用户在搜索表单上检查了哪些类型。

但是,我不知道如何将其翻译成我想要的 AND 语句,就是这个:

AND (schools.schoolType = "MiddleSchool" OR schools.schoolType = "HighSchool" OR schools.schoolType = "TradeSchool")

我曾想过将每种类型放在括号内并用OR 分隔每种类型,并且仅在确实检查了类型时才在括号内写入。

结果如下:

AND ((schools.schoolType = 'MiddleSchool') OR () OR () OR (schools.schoolType = 'HighSchool') OR () OR () OR ())

不用说,它很丑,而且也不起作用,所以我把它装了。问题是我不知道可以有多少“检查类型”,因此构建正确的查询有点困难。

我在写这篇文章时想到的一个解决方案是将每个“有效”类型放在一个数组中,然后使用那个数组,然后我会知道它的长度。然后我将能够创建预期的 AND 语句,因为我将拥有一定数量的选中复选框,并且它还允许我完全忽略未选中的值。你觉得这样行吗?

【问题讨论】:

  • 您可能会发现使用field IN (1,2,3) 比使用field = 1 OR field = 2 OR field = 3 更容易。
  • WHERE schools.schoolType IN ("MiddleSchool", "HighSchool", "TradeSchool")

标签: php mysql sql forms


【解决方案1】:

如果您的 schools.schoolType 列是任意的 VARCHAR 数据类型,则用户提交的数据与查询中使用的数据之间需要存在某种关系,除非您预先定义了可能值的列表。

看起来你的arrayTypes 数组和$_GET 值之间存在某种关系。因此,假设查询需要HighSchool,如果用户使用您的basictext() 函数提交highschool,则可以检测到这一点。

从那里我会做这样的事情:

$selectedTypes = array();

foreach($arrayTypes as $arr)
{
    if(isSet($_GET[basictext($arr)]))
    {
        echo "[x] Type ".$arr." <br/>";
        $selectedTypes[] = $arr;
    } 
    else 
    { 
        echo "[ ] Type ".$arr." <br/>"; 
    }
}

这将使用用户提交的匹配类型填充selectedTypes 数组。

听起来您想在最终查询中添加IN 子句。

$placeholders = implode(',', array_fill(0, count($selectedTypes), '?'));

$template = "SELECT schools.schoolId, 
                    schools.schoolName, 
                    villages.villageName 
               FROM schools, 
                    villages
              WHERE schools.villageId = villages.villageId
                AND schools.schoolType IN ($placeholders)";

$stmt = $pdo->prepare($template);
$stmt->execute($selectedTypes);
$result = $stmt->fetchAll();
$stmt = null;

如果selectedTypes 包含["HighSchool", "MiddleSchool", "TradeSchool"],那么$placeholders 将包含[?, ?, ?]。这用于使用 selectedTypes 数组作为输入数据为准备好的语句查询构造 SQL 模板。

$result 应该有你想要的数据。

【讨论】:

    【解决方案2】:

    因此,如果我的理解正确,您只需要编写一些东西来连接基于位数组的 OR 语句的片段。而不是为每个条目添加一个 OR,不管它是否被选中,做类似的事情

        first = true
        string orClause = ""
        array schoolTypes
        array checkedSchoolTypes
    
        for(i = 0; i < checkedSchoolTypes.length; i++)
            if(first && checkedSchoolTypes[i])
               orClause += "schools.schoolType = " + schoolTypes[i]
               first = false
            else if(checkedSchoolTypes[i])
                 orClause += "OR schools.schoolType = " + schoolTypes[i]
    
       query = "This is your query" + orClause + "rest of your query"
    

    *请注意,这是针对学校项目而非生产环境的解决方案。如果您在生产环境中执行此操作,那么您可能希望通过参数化存储过程传递信息,并根据从表单传入的信息在 sql 中生成语句。

    而不是像您建议的那样执行 or ,您可以执行 IN 语句,因为其他人建议代码基本上是相同的,但格式不同。如果您需要任何说明,请告诉我。

    【讨论】:

      猜你喜欢
      • 2019-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多