MySQLi多表查询

时间:2019-01-02 17:31:32

标签: php join mysqli

努力弄清楚要使用哪些功能来获取我需要的功能-以升序列出所有公司及其所有用户。

到目前为止,我已经创建了两个表:“ companies”和“ users”,并使用外键将它们连接起来,如下所示:

我尝试执行JOIN查询以使用在一定程度上都有效的两个表,尽管我不知道如何纠正它。以下是我一直造成的原因: enter image description here

如您所见,“ Contoso”公司被列出两次,因为它在users表中有2个与之关联的用户。我正在执行的代码是:

$joinquery = "SELECT companies.id, companies.name, users.fname, users.lname FROM users RIGHT JOIN companies ON users.cid = companies.id ORDER BY name ASC";
       $joinresult = $mysqli->query($joinquery);

       if($joinresult->num_rows > 0) {
           while($row = $joinresult->fetch_assoc()){
               $company = $row['name'];
               $fname = $row['fname'];
               $lname = $row['lname'];
               $name = $fname . " " . $lname;
               echo "<div class='customer'>";
               echo "<div class='name'>";
               echo $company;
               echo "</div>";
               echo "<div class='contacts'>";
               echo $name;
               echo "</div>";
               echo "</div>";
           }
       } else {
           echo "No results";
       }

div仅使其成为一个块元素并更改颜色。

如何让所有用户都在其相关公司内,而不是每个公司和用户都排成一行?我已经尝试过嵌套,但是离最终目标还很远,下面是代码:

// Nested Query Test
$nestquery1 = "SELECT companies.name, users.fname, users.lname FROM companies INNER JOIN users ON companies.id = users.cid ORDER BY companies.name ASC";
$nestresult1 = $mysqli->query($nestquery1);

$nestquery2 = "SELECT companies.id, users.fname, users.lname FROM users INNER JOIN companies ON users.cid = companies.id ORDER BY fname ASC";
$nestresult2 = $mysqli->query($nestquery2);

if($nestresult1->num_rows > 0) {
    while($row = $nestresult1->fetch_assoc()){
        $company = $row['name'];
        echo "<div class='customer'>";
        echo "<div class='name'>";
        echo $company;
        echo "</div>";
        if($nestresult2->num_rows > 0) {
            while($row = $nestresult2->fetch_assoc()){
                $fname = $row['fname'];
                $lname = $row['lname'];
                $name = $fname . " " . $lname;
                echo "<div class='contacts'>";
                echo "<li>";
                echo $name;
                echo "</li>";
                echo "</div>";
            }
        }
        echo "</div>";
    }
} else {
    echo "No results";
}

非常感谢您的帮助!

3 个答案:

答案 0 :(得分:2)

由于要按公司名称进行订购,因此您应该能够检查公司名称何时更改,以便知道何时创建新容器。

$currentCompany = "";

while($row = $joinresult->fetch_assoc()){
    $company = $row['name'];
    $fname = $row['fname'];
    $lname = $row['lname'];
    $name = $fname . " " . $lname;

    if($currentCompany != $company) {
        if($currentCompany != "")
            echo "</div>";

        $currentCompany = $company;

        echo "<div class='customer'>";
        echo "<div class='name'>";
        echo $company;
        echo "</div>";
    }

    echo "<div class='contacts'>";
    echo $name;
    echo "</div>";
}

答案 1 :(得分:1)

您有两个选择,(A)使用联接或(B)尝试使用两个查询。联接将要求您跟踪公司的更改,但是不会查询这两个查询。两种选择都有优点和缺点:

  • A)这样的联接速度很快,但是您将返回每条记录的公司详细信息,从而在与数据库的通信中产生额外的流量负载。如果数据库服务器位于单独的服务器上,或者您要处理的是巨大的数据集,那么这可能是一个问题。请记住,即使多余的数据看起来很小,也可以将其乘以预期的网站并发访问者数量,这可能会使数据库链接饱和。

    @ abney317提供的示例是准确的,但是与其比较公司名称,不如比较cid,因为它不仅性能更高,而且更可靠。

  • B)这是我会选择的方法,虽然实现起来会涉及更多点,并且需要两个查询而不是一个查询,但它是将来可扩展性和可维护性更高的选项。还将使您的代码更易于遵循和调试。

    示例:

    // Nested Query Test
    $rsCompanies = $mysqli->query("SELECT cid, name FROM companies ORDER BY name");
    while($company = $rsCompanies->fetch_assoc())
    {
      echo "<div class='customer'>";
      echo "<div class='name'>" . htmlspecialchars($company['name']) . "</div>";
      echo "<div class='contacts'>";
      echo "<ul>";
      $rsUsers = $mysqli->query("SELECT fname, lname FROM users WHERE cid = " . $company['id']);
      while($user = $rsUsers->fetch_assoc())
      {
        $name = htmlspecialchars($user['fname'] . " " . $user['lname']);
        echo "<li>$name</li>";
      }
      echo "</ul>";
      echo "</div>";
      echo "</div>";
    }
    

更多注意事项:

  • 从不包含任何HTML的数据库输出文本时,始终使用htmlspecialchars,否则将使您容易受到XSS攻击媒介的攻击。<​​/ p>

  • 我没有SQL转义公司ID,因为根据您的数据库架构,它是整数,并且由于最终用户未提供它,因此可以安全地直接使用它,从而避免了任何额外的处理开销。 p>

答案 2 :(得分:-1)

如果只需要显示几个字段,则尝试在一个查询中获取数据: sql fiddle

SELECT c.name company_name,
group_concat(u.name) employees_name
FROM companies c JOIN users u on c.id = u.cid
group by c.name;