【问题标题】:Which SQL request should i use?我应该使用哪个 SQL 请求?
【发布时间】:2021-02-16 14:13:50
【问题描述】:

我有表 SkillsResult

___ Matieres ___             ___ Resultats ___
id (int auto increment)      ID (int auto_increment)
Nom (varchar)            TIME_OF_INSERTION (datetime current_timestamp)
Categorie (varchar)          ID_USER (int)
Active (boolean)             ID_MATIERE (int)
                             RESULTAT (int)

我有这段代码可以根据查询的数据创建一个表单:

$req = $bdd->query(SELECT * FROM Matieres LEFT JOIN Resultats ON Matieres.id = Resultats.ID_MATIERE WHERE Active = TRUE);

$skills = [];

while( $data = $req->fetch()) {

    array_push( $skills, [ $data['id'], $data['Nom'], $data['RESULTAT'] ] );

}

function setWidgetValue( $skill ) {
    
    if(is_null($skill[2])) {
        $value = 0;
    } else {
        $value = $skill[2];
    }

    $widget = "<div class='m-5'><p>".$skill[1]."</p><input type='range'  value='" . $value ."' class='form-control-range' min='0' step='1' max='10' id='".$skill[0]."' name='valSkill' onchange=\"MAJ_Value( ".$skill[0].", this.value, " . $_SESSION['id'] . " )\" ></div>";
    return $widget;

}


function setAllWidgetValue( $skills  ) {

    $widget = "<div id='valSkills' >\n";
    foreach( $skills as $skill )
        $widget .= setWidgetValue( $skill );
    $widget .= "</div>";
    return $widget;

}

问题是我的输入值应该是0,如果用户还没有发送它们并且如果一个用户发送它就可以正常工作。但如果另一个用户尝试访问表单,输入将具有前一个用户提交的值。

我认为问题出在 SQL 请求上,但我找不到一个完美运行的 :( 我知道我必须传递用户的id 但不知道在请求中写在哪里

【问题讨论】:

  • 您可以更改表字段名称以匹配代码中的名称吗?混合起来很混乱!
  • 我刚刚修好了! :)
  • 你在用PDO吗?
  • 恭喜您“修复它”,但现在请回答您自己的问题!告诉将来遇到此线程的每个人究竟是什么问题,并且正是你如何修复它。 (请不要更改原始帖子。)因为,在未来的某个时候,遇到类似问题的人 else 会偶然发现这个帖子......并且(s)他会感谢你。
  • @MikeRobinson 我很确定他的意思是他修复了我在第一条评论中要求他修复的字段名称;不是说他用他的代码解决了问题吗?

标签: php sql database join select


【解决方案1】:

关于 SQL 的一点点

您的Matieres 表和Resultat 表之间似乎存在one-many 关系?

当您在这种情况下使用SELECT...JOIN 语句时,您实际上返回Matieres 的次数与Resultat 中的匹配次数一样多。

例如:

  1. 假设你有技能/技能can touch toes
  2. 假设 Resultat 中有 5 记录,用于具有该技能的 users

使用您当前的查询结构,您可以执行以下操作:

__SQL:

SELECT Resultat.ID_USER, Matieres.Nom, Result.RESULTAT
FROM Matieres
    LEFT JOIN Resultat ON Matieres.id = Result.ID_SKILL


__RESULTS:

Resultat.ID_USER     Matieres.Nom        Resultat.RESULTAT
1                    can touch toes      50
2                    can touch toes      71
3                    can touch toes      23
4                    can touch toes      88
5                    can touch toes      20

要更改此行为,您需要在 ON 子句中指定其他条件:

__SQL:

SELECT Resultat.ID_USER, Matieres.Nom, Result.RESULTAT
FROM Matieres
    LEFT JOIN Resultat
        ON Matieres.id = Result.ID_SKILL
            AND Resultat.ID_USER = 1

__RESULTS:

Resultat.ID_USER     Matieres.Nom        Resultat.RESULTAT
1                    can touch toes      50

PHP while statement echoes duplicates :在此处查看答案以获取更多信息和示例

ON 不是 WHERE

附加条件必须进入ON 子句而不是WHERE 子句的原因是,您希望获得每个Active 技能/材料,无论是否有人已经获得了Resultat

如果我们将其放入 WHERE 子句中,我们会得到:

__SQL: 

SELECT Resultat.ID_USER, Matieres.Nom, Result.RESULTAT
FROM Matieres
    LEFT JOIN Resultat
        ON Matieres.id = Result.ID_SKILL
WHERE Resultat.ID_USER = 1

__RESULTS:

Resultat.ID_USER     Matieres.Nom        Resultat.RESULTAT
1                    can touch toes      50

这似乎没问题,除非您考虑到您拥有多种技能/材料并且用户没有每个技能/材料的记录...例如:

__TABLES

Matieres                         Resultat
id           Nom                 ID_USER     ID_MATIERE      RESULTAT
111          can touch toes      1           111             54
112          can handstand       1           112             60
113          can cartwheel       2           113             72

.

__SQL[1]: {For ID_USER == 1; using ON}

SELECT Resultat.ID_USER, Matieres.Nom, Result.RESULTAT
FROM Matieres
    LEFT JOIN Resultat
        ON Matieres.id = Result.ID_SKILL
            AND Resultat.ID_USER = 1

__RESULT[1]: 

Matieres                         Resultat
id           Nom                 ID_USER     ID_MATIERE      RESULTAT
111          can touch toes      1           111             54
112          can handstand       1           112             60
113          can cartwheel       NULL        NULL            NULL


__SQL[2]: {For ID_USER == 2; using ON}

SELECT Resultat.ID_USER, Matieres.Nom, Result.RESULTAT
FROM Matieres
    LEFT JOIN Resultat
        ON Matieres.id = Result.ID_SKILL
            AND Resultat.ID_USER = 2

__RESULT [2]:

Matieres                         Resultat
id           Nom                 ID_USER     ID_MATIERE      RESULTAT
111          can touch toes      NULL        NULL            NULL
112          can handstand       NULL        NULL            NULL
113          can cartwheel       2           113             72


__SQL[3]: {For ID_USER == 1; using WHERE}

SELECT Resultat.ID_USER, Matieres.Nom, Result.RESULTAT
FROM Matieres
    LEFT JOIN Resultat
        ON Matieres.id = Result.ID_SKILL
WHERE Resultat.ID_USER = 1

__RESULT[3]: 

Matieres                         Resultat
id           Nom                 ID_USER     ID_MATIERE      RESULTAT
111          can touch toes      1           111             54
112          can handstand       1           112             60


__SQL[4]: {For ID_USER == 2; using WHERE}

SELECT Resultat.ID_USER, Matieres.Nom, Result.RESULTAT
FROM Matieres
    LEFT JOIN Resultat
        ON Matieres.id = Result.ID_SKILL
WHERE Resultat.ID_USER = 2

__RESULT[4]: 

Matieres                         Resultat
id           Nom                 ID_USER     ID_MATIERE      RESULTAT
113          can cartwheel       2           113             72

你的问题

假设

  1. 您有一个user 登录到$_SESSION["id"] == Resultat.ID_USER 所在的网站
  2. 你想SELECT all Matieres.id &amp;&amp; Matieres.Nom AND Resultat.RESULTAT 已经为该Resultat.ID_USER记录的任何技能
  3. 您正在使用PDO$bdd 是您与数据库的连接

示例代码

// SQL statement using `?` as a placeholder for the users id (from $_SESSION["id"]
// Add: "AND Resultats.ID_USER = ?" to ON clause to limit joined records to currently logged in user
$sql = "    
    SELECT Matieres.id, Matieres.nom, Resultats.RESULTAT
    FROM Skills
        LEFT JOIN Resultats ON Matieres.id = Resultats.ID_MATIERE AND Resultats.ID_USER = ?
    WHERE Matieres.Active = TRUE
";

$req = $bdd->prepare($sql);         // Prepare query
$req->execute([ $_SESSION["id"] ]); // Assign value to place holder and execute query

$skills = [];
while( $data = $req->fetch() ) {
    $skills[] = [
        "id"=>$data["id"],
        "Nom"=>$data["Nom"],
        "RESULTAT"=>$data["RESULTAT"]
    ];
}

function setWidgetValue( $skill ) {

    // Set values outside of "widget" string for ease of reading
    $value    = ( is_null($skill["RESULTAT"]) ) ? 0 : $skill["RESULTAT"]; // Shorthand if statement using the ternary operator
    $nom      = $skill["Nom"];   
    $skill_id = $skill["id"];  
    $user_id  = $_SESSION["id"];

    // I've separated the code over several lines to make 
    // it easier to read you can of course change it back!
    $widget   = "
        <div class='m-5'>
            <p>{$nom}</p>
            <input
                type='range' 
                value='{$value}'
                class='form-control-range'
                min='0' step='1' max='10'
                id='{$skill_id}'
                name='valSkill'
                onchange=\"MAJ_Value( {$skill_id}, this.value, {$user_id} 
                )\" >
        </div>
    ";
    return $widget;
}

function setAllWidgetValue( $skills ) {
    $widget = "<div id='valSkills' >\n";
    foreach( $skills as $skill )
        $widget .= setWidgetValue( $skill );
    $widget .= "</div>";
    return $widget;
}

【讨论】:

  • 谢谢史蒂文!这解决了我的问题,你的解释是完整而清晰的! :)
【解决方案2】:

您必须将用户 ID 放在联接中,而不是放在 where 子句中:

SELECT * FROM Matieres 
LEFT JOIN Resultats 
  ON Matieres.id = Resultats.ID_MATIERE 
  AND Resultats.ID_USER = :ID_USER
WHERE Active = TRUE

:ID_USER 将是您的输入参数。如果您在 Resultats 中输入一个不存在的用户 ID 或一个尚不存在的 ID,您仍将获得列出的所有技能,但用户的值为 NULL。

【讨论】:

    猜你喜欢
    • 2017-06-13
    • 2018-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-28
    • 2015-12-05
    • 1970-01-01
    相关资源
    最近更新 更多