【问题标题】:Should I be using multiple SQL queries or multiple loops in my client code?我应该在客户端代码中使用多个 SQL 查询还是多个循环?
【发布时间】:2012-10-18 20:00:01
【问题描述】:

我正在构建一个小型内部电话号码分机列表。

在数据库中我有两个表,一个people 表和一个numbers 表。关系分别为one-to-many

我想在单个 HTML 表格中显示结果,每行一个人,但如果他们有多个数字,它会在单个列中显示这些结果,并在个人行上显示行跨度以进行补偿。

现在,要从数据库中获取要使用的结果,我可以这样做:

(pseudocode)

SELECT id, name
FROM people

foreach result as row {
  SELECT number
  FROM numbers
  WHERE numbers.person_id = row['id']
}

这意味着我正在执行一个查询来获取所有用户,但是如果我有 100 个用户,我将执行 100 个额外的查询来获取每个用户的数字。

相反,我可以这样做:

(pseudocode)

SELECT number, person_id
FROM numbers

SELECT id, name
FROM people

foreach people as person {
  echo name
  foreach numbers as number {
    if (number.id = person.id) {
      echo number
    }
  }
}

所以,基本上它在做完全相同的事情,只是我做了两个查询以将所有结果放入数组中,然后循环遍历数组以格式化我的表。

我应该使用哪种方法或有更好的方法来做到这一点?

【问题讨论】:

    标签: php mysql sql loops


    【解决方案1】:

    常见的方法是做一个常规的 JOIN:

    SELECT id, name, number
    FROM people, numbers
    WHERE people.id = numbers.person_id;
    

    您可以添加一个ORDER BY 来按顺序获取数字,或者您可以创建一个对结果集进行一次遍历的数组,然后循环遍历该数组。

    您还可以考虑使用GROUP_CONCAT 来连接同一个人的所有数字:

    SELECT id, name, GROUP_CONCAT(number SEPARATOR ', ')
    FROM people, numbers
    WHERE people.id = numbers.person_id
    GROUP BY people.id;
    

    既然您甚至会问这个问题:我不能强调您应该选择一本关于数据库设计的介绍性书籍。它帮助我了解了关系数据库背后的理论。

    【讨论】:

    • 我相信您的查询是提问者在他的嵌套循环示例中已经在做的事情,但是,您的 GROUP_CONCAT 想法是一个很棒的想法,我可能会最终使用它。
    • morrty 在第二个示例中仍然使用两个查询。不太好重新实现加入 imo。
    • @EmilVikström 是的,对不起。没有看到顶部的两个查询,我认为他正在加入!这加强了我对你的回答的投票哈哈。
    • 啊,实际上,我不认为这会起作用,除非可以修改查询。因为我试图保持 OP 简单,所以我没有提到 numbers 表有另一列 type (移动、工作、扩展等)。可以修改当前查询以允许这样做吗?
    • @EmilVikström SELECT locations.name AS location, contacts.name, contacts.title, GROUP_CONCAT(CONCAT(' {', types.name, '} ', numbers.number) SEPARATOR ' | ') AS numbers FROM contacts INNER JOIN numbers ON contacts.id = numbers.contacts_id INNER JOIN locations ON contacts.locations_id = locations.id INNER JOIN TYPES ON numbers.types_id = types.id GROUP BY contacts.id - 这似乎有效。
    【解决方案2】:

    可能只想执行一个查询。类似的东西

    select people.id, people.name, group_concat(numbers.number)
    from people 
    inner join numbers on numbers.id = people.id
    group by people.id, people.name
    order by people.name
    

    然后你可以用简单的 php 代码循环遍历结果集。

    【讨论】:

    • 我认为这可能有效,但是,它将所有数字放入一个用逗号分隔的字段中。除了逗号,还有其他分隔符吗?
    • 是的。 GROUP_CONCAT syntax。您甚至可以使用 HTML 标记作为分隔符:group_concat(numbers.number separator '<br/>').
    【解决方案3】:

    视情况而定,您可能需要花时间才能找到答案。如果您的数据库与 Web 服务器位于不同的计算机上,则执行多个查询会导致很多网络转弯,因此这通常需要更长的时间。但是,如果您的数据库服务器与您的 Web 服务器在同一台计算机上,这可能不是问题。

    还要考虑在数组中查找数字所需的时间。作为一个数组,您正在执行线性顺序 O(N) 搜索。如果你可以把它放在一个散列中,查找会快很多,两个查询的方法可能会更快,但如果你花很多时间在你的数组中查找答案,则不会。

    使用连接将其放入一个查询中可能是最快的,因为数字将与人员相关联,具体取决于您将数据存储到其中以在 foreach 循环中访问的容器结构。

    【讨论】:

      【解决方案4】:

      使用存储过程或函数来检索数据,不要在程序中写sql

      【讨论】:

        【解决方案5】:

        你不应该这样做。您可以对表进行 一个 查询(连接):

        select name, number
        from people p, numbers n
        where p.id = n.person_id
        order by name, number;
        

        然后只是一个循环:

        $link = mysqli_connect(...);
        $query = 'select name, number from people p, numbers n where p.id = n.person_id order by name, number';
        
        if ($result = mysqli_query($link, $query)) {
            $person = '';
            while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
                if ($row['name'] !== $person) {
                    $person = $row['name'];
                    echo $person;
                }
        
                echo $row['number'];
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-08-18
          • 2013-07-31
          • 2010-09-20
          • 1970-01-01
          • 2018-07-16
          • 2012-04-19
          • 2016-10-16
          • 2022-11-25
          相关资源
          最近更新 更多