How to group mysql results by foreign keys into a single array through a single query?

4

Let's say I have 2 tables, one with phone numbers, and one with sectors:

Ex :. tb_ramais: id, extension, group_id (fk).

id | ramal | grupo_id
01 | 1234  | 01
02 | 2345  | 01
03 | 3456  | 02
04 | 3457  | 02

tb_groups: id, sector, manager.

id | setor   | gestor
01 | setorA | Carlos
02 | setorB | Jose

Is there a way to get an associative array indexed by sector?

So that all the data in the tables would be available in a single array and through a single query, it being possible to iterate it as follows:

<?php
foreach ($resultado['setorA'] as $setorA) {
  // código 
}

foreach ($resultado['setorB'] as $setorB)
  // código
}

I can currently do this through two sql queries, assigning a where setor = 'setorX' clause to each of them ...

But I would like to know if there is a way to get the same result by just doing a query and returning an associative array indexed by the sector, and if that would be a good practice with a high number of data, where it is necessary to consider , if the volume of data is interesting in a single query, or if it is more interesting even, do this in 2 queries, dividing the data into 2 arrays.

Doubt is ref. the pure mysql query, so it is not necessary to talk about PDO or other classes.

    
asked by anonymous 19.05.2014 / 19:55

3 answers

5

I believe it solves your grouping issue, but the solution is PDO and PDOStatement

<?php
    $dsn = 'mysql:dbname=testdb;host=127.0.0.1';
    $user = 'root';
    $password = 'senha';

    $pdo = new PDO($dsn, $user, $password);

    $sts = $pdo->prepare("SELECT b.setor, a.grupo_id, a.id, a.ramal, b.gestor
                         FROM tb_ramais a inner join tb_grupos b on a.grupo_id = b.id
                  ORDER BY b.setor");

    $sts->execute();

    $resultado = $sts->fetchAll(PDO::FETCH_NAMED | PDO::FETCH_GROUP);
    print_r($resultado['setorA']); 
    echo '<br>';    
    print_r($resultado['setorB']);
    echo '<br>';
//Setor A
Array
(
    [0] => Array
        (
            [grupo_id] => 1
            [id] => 2
            [ramal] => 2345
            [gestor] => Carlos
        )

    [1] => Array
        (
            [grupo_id] => 1
            [id] => 1
            [ramal] => 1234
            [gestor] => Carlos
        )

)

//Setor B
Array
(
    [0] => Array
        (
            [grupo_id] => 2
            [id] => 3
            [ramal] => 3456
            [gestor] => Jose
        )

    [1] => Array
        (
            [grupo_id] => 2
            [id] => 4
            [ramal] => 4567
            [gestor] => Jose
        )

)

Foreach

foreach ($resultado['setorA'] as $setorA) {
    print_r($setorA);
    print('<br>');
}
Array
(
    [grupo_id] => 1
    [id] => 2
    [ramal] => 2345
    [gestor] => Carlos
)
Array
(
    [grupo_id] => 1
    [id] => 1
    [ramal] => 1234
    [gestor] => Carlos
)

In terms of performance, I believe it will depend on factors, but you can use that peacefully in your projects.

    
19.05.2014 / 21:15
2

You have already tried to JOIN , in both tables, example:

SELECT
g.setor,
r.ramal,
g.gestor
FROM tb_ramais r
INNER JOIN tb_grupos g
ON r.grupo_id = g.id

SQL Fiddle Example

The result of this query returns:

Array
(
    [0] => Array
        (
            [setor] => setorA
            [ramal] => 1234
            [gestor] => Carlos
        )

    [1] => Array
        (
            [setor] => setorA
            [ramal] => 2345
            [gestor] => Carlos
        )
...

So you can do:

$ramais = array();
foreach ($result as $row){
    $ramais[$row['setor']][] = array('ramal'=>$row['ramal'],'gestor'=>$row['gestor']);
}

And you will have the associative array:

Array
(
    [setorA] => Array
        (
            [0] => Array
                (
                    [ramal] => 1234
                    [gestor] => Carlos
                )

            [1] => Array
                (
                    [ramal] => 2345
                    [gestor] => Carlos
                )

        )
        ...

Then you can work the array as:

foreach ($ramais['setorA'] as $setorA){
    echo $setorA['ramal'];
}

As far as feasibility deta solution, each case is a case, whether we are talking about tens, hundreds, thousands or millions of records.

    
19.05.2014 / 20:26
1

In response to this comment , in off-topic , even though this is not the Stack Overflow template, but valid in my opinion, so that doubts sourced from a comment made more broadly and completely.

  • PHP is an interpreted language, everything you do with it is by definition slower than compiled resources, in this case the PDO. Without it, you would suddenly need to do nested loops (bad), complex logics (worse), manipulation of arrays (which in a nested loop can be a death sentence).

  • If your application today uses MySQL, it will always use MySQL and there is no way to use another DBMS for whatever reason, almost always does not justify using the PDO, given that MySQLi gives and leaves.

    If you do not use the PDO, using the solution presented here although appropriate becomes wrong because you are making your application dependent on a very large resource for a very small, relatively speaking task.

  • The framework issue is a bit more delicate.

    A framework, either full-stack or domain-specific, aims to solve all the problems of the programmer by it (full stack) or all problems of a certain area (specific domain).

    Whatever the case, solving problems related to data access requires considering multiple scenarios because data can come from anywhere (database, XML, TXT, WebService ...).

    Let's forget about all other media and focus only on databases. A framework should consider MySQL, PostgreeSQL, SQLite, MSQL among others. And even before the PDO each database was manipulated by a different library, with a syntax and / or, mainly, a different signature of methods / functions.

    The PDO came to eliminate half of the problem by standardizing the operations it supports through the same interface, so the programmer would only worry about the pseudo-SQL language itself, since they vary between different DBMSs. >

    Now I get where I wanted to go. PHP is getting in the way gradually, but by itself, perhaps even by the excess of legacy that it carries until today, it still has ugly, confusing or even very verbose method signatures (GD that says so). >

    While some frameworks do not care about this and allow the PDO constants to be used normally in the respective fetching methods of the results, simply directing all the arguments received to the right one - one of the few func_get_args () - other frameworks go further and try to order in the house.

    It works, of course, but if you're using PDO, you're theoretically doing it because you might need another DBMS in the future, even if it's not in practice.

    And as I mentioned above there are differences between DBMSs, and suddenly this technique may not be available or even completely implemented in an Informix database (whatever it is) in the same way it is for MySQL .

    Some frameworks go even further and try to get around this type of problem. Others, "simply" (because it's not simple at all), rewrite the entire PDO interface.

    I have done this in the past, rewriting in an object-oriented model, renaming methods, changing the order of the arguments, rearranging the mess that was left here and there ...

    I will not say that what I did was right, wrong, better or worse, but because it is a good case, but very specific indeed, the solution presented may not work in my code because, perhaps, which I may have missed.

  • 20.05.2014 / 03:11