简体   繁体   中英

How to get one set of data from a SQL query from multiple table?

My table structure is

TABLE_1
|------|------|-------|
|  ID  | NAME | PHONE | = 1 ROW
|------|------|-------|
TABLE_2
|------|------------|----------|
|  ID  | TABLE_1_ID | CATEGORY | = 5 ROW
|------|------------|----------|
TABLE_3
|------|------------|----------|
|  ID  | TABLE_1_ID | ADDRESS  | = 3 ROW
|------|------------|----------|

I am working with the above table. But my result generating 1 row but in the CATEGORY cell its displaying 5 CATEGORY but it's repeating 3 times and in the ADDRESS cell the 3 addresses repeating 5 times, like below -

RESULT
|----|------|-------|----------------------------|------------------|
|    |      |       |                            | (ADR1,ADR2,ADR3) |
|    |      |       | (CAT1,CAT2,CAT3,CAT4,CAT5) | (ADR1,ADR2,ADR3) |
| ID | NAME | PHONE | (CAT1,CAT2,CAT3,CAT4,CAT5) | (ADR1,ADR2,ADR3) |
|    |      |       | (CAT1,CAT2,CAT3,CAT4,CAT5) | (ADR1,ADR2,ADR3) |
|    |      |       |                            | (ADR1,ADR2,ADR3) |
|----|------|-------|----------------------------|------------------|

My PHP+SQL is

$db = new Database;
$getData = "SELECT a.name, a.phone, b.category, c.address
FROM table_1 a JOIN table_2 b JOIN table_3 c
WHERE a.id = b.table_1_id AND a.id = c.table_1_id
ORDER BY a.id ASC";
$execute = $db->select($getData);
$result        = [];
$currentParent = false;
$data          = null;
foreach ($execute as $row) {
    if ($currentParent != $row['id']) {
        if($data != null){ 
            $result[]= $data;
        }
        $data = [
            'name'     => $row['name'],
            'phone'    => $row['phone'],
            'category' => '',
            'address'  => ''
        ];
        $currentParent = $row['id'];
    }
    $data['category'] = empty($data['category']) ? $row['category'] : $data['category'] .", ". $row['category'];
    $data['address']  = empty($data['address'])  ? $row['address']  : $data['address']  .", ". $row['address'];
}
$result[]= $data;
echo json_encode($result);

Now the question is, How am I going to achieve 1 set of 5 category and 1 set of 3 address in my result. Thanks in advance.

My Data

TABLE_1 DATA
|------|------|-------|
|  ID  | NAME | PHONE |
|------|------|-------|
|  1   | JON  | 123   |
|------|------|-------|
TABLE_2 DATA
|------|------------|----------|
|  ID  | TABLE_1_ID | CATEGORY |
|------|------------|----------|
|  1   |      1     |   CAT1   |
|------|------------|----------|
|  2   |      1     |   CAT2   |
|------|------------|----------|
|  3   |      1     |   CAT3   |
|------|------------|----------|
|  4   |      1     |   CAT4   |
|------|------------|----------|
|  5   |      1     |   CAT5   |
|------|------------|----------|
TABLE_3 DATA
|------|------------|----------|
|  ID  | TABLE_1_ID | ADDRESS  |
|------|------------|----------|
|   1  |      1     |   ADR1   |
|------|------------|----------|
|   2  |      1     |   ADR2   |
|------|------------|----------|
|   3  |      1     |   ADR3   |
|------|------------|----------|

My new query with GROUP_CONCAT

SELECT a.id, a.name, a.phone, 
 GROUP_CONCAT(b.category ORDER BY b.category SEPARATOR ',') category,
 GROUP_CONCAT(c.address ORDER BY c.address SEPARATOR ',') address
    FROM table_1 a INNER JOIN table_2 b ON (a.id = b.table_1_id) INNER JOIN table_3 c ON (a.id = c.table_1_id)
    GROUP BY a.id, a.name, a.phone

This query also generating same result and my PHP is same as above.

I will try to answer using SQL only.

Use group_concat with distinct,

select t.id,name,phone,
 group_concat(distinct a.addr separator ',') as address,
 group_concat(distinct c.cat separator ',') as category
  from table1 t
  left join address a 
    on t.id = a.refid
  left join category c
    on t.id = c.refid
  group by t.id,name, phone

OR

As inline column,

select t.id,name,phone,
 (select group_concat(a.addr separator ',')
    from address a 
   where a.refid = t.id) as address,
 (select group_concat(c.cat separator ',') 
    from category c
   where c.refid = t.id) as category
  from table1 t

Reference Db<>fiddle

Your query involves multiple joins that is why you are getting multiple rows for category and address, In your application code you can display set of category and address once by tweaking your existing logic.

Maintain temporary variables of category and address ($categories,$addresses) for each item of table_1 and use in_array() to make sure no duplicate address and categories are added to your temporary variables $categories & $addresses and inside loop when your iteration changes from one item to different one then create a comma separated string of previously collected categories and addresses

$currentParent = false;
$data          = null;
$categories =$addresses = [];
foreach ($execute as $row) {
    if ($currentParent != $row['id']) {
        if($data != null){ 
            $data['category'] = implode (", ", $categories);
            $data['address'] = implode (", ", $addresses);
            $result[]= $data;
            $categories =$addresses = [];
        }
        $data = [
            'name'     => $row['name'],
            'phone'    => $row['phone'],
            'category' => '',
            'address'  => ''
        ];
        $currentParent = $row['id'];
    }
    if (in_array($row['category'], $categories) === false) {
        array_push($categories, $row['category']);
    }
    if (in_array($row['address'], $addresses) === false) {
        array_push($addresses, $row['address']);
    }
}

$data['category'] = implode (", ", $categories); // for last item
$data['address'] = implode (", ", $addresses); // for last item
$result[]= $data;
echo json_encode($result);

Since you have not porvided the complete data I can only suggest that you can make use of GROUP_CONCAT funtion in MYSQL.

So your query will be something like this.

Demo

    SELECT a.id, a.name, a.phone, 
 GROUP_CONCAT( distinct b.cat ORDER BY b.cat SEPARATOR ',') category,
 GROUP_CONCAT(distinct c.addr ORDER BY c.addr SEPARATOR ',') address
    FROM table1 a INNER JOIN category b ON (a.id = b.refid) INNER JOIN address c ON (a.id = c.refid )
    GROUP BY a.id, a.name, a.phone;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM