For easier explaination I will try to simplify everything.
I have 3 SQL tables: Users
, Certs
, Serv
In Users
table are stored details about unique users.
In Certs
table are stored details about certificates and UserId
of user who have this certificate (1 user can have multiple certificates)
In Serv
table are stored details about sea services and UserId
of user (like Certs
table, 1 user can have multiple entries in Serv
table)
SAMPLE DATA
Users
UserId Name
1 John
2 Lisa
Certs
Id UserId CertName
1 1 A
2 1 B
3 1 C
4 2 A
5 2 C
Serv
UserId Name
1 SA
1 SB
1 SC
1 SD
2 S2A
I need to retrieve output via PHP something like (where UserId = 1) also for reality there will be more columns from each table (for example more details of certificates like date of issue, date of expire, place of issue and so on):
Personal details:
Name
John
Certificates:
Certificate Id Certificate Name
1 A
2 B
3 C
Sea Services:
Sea Service Name
SA
SB
SC
SD
But I got wrong output, duplicated entries, that because joining 2 tables with UserId
in whose are multiple records with this UserId
.
PHP CODE
$users = $con->prepare("
select u.Name
,GROUP_CONCAT(c.Id SEPARATOR '<br>') AS Id
,GROUP_CONCAT(c.certsName SEPARATOR '<br>') AS certsName
,GROUP_CONCAT(s.Name SEPARATOR '<br>') AS Name
from users u
left join certs c on u.UserId = c.UserId
left join serv s on u.UserId = s.UserId
where u.UserId = ?
");
$users->bind_param('i', $GetUserId);
$users->execute();
$users->bind_result(
$userName,
$certId,
$certName,
$servName
);
<?php
while ($users->fetch()) {
?>
<span>Personal Details</span>
<div class="grid-group">
<div class="grid-column">
<div class="grid-item header">User Name </div>
</div>
<div class="grid-column">
<div class="grid-item"><?php echo $userName; ?></div>
</div>
</div>
<span>Certificates</span>
<div class="grid-group">
<div class="grid-column">
<div class="grid-item header">Certificate Id</div>
<div class="grid-item header">Certificate Name</div>
</div>
<div class="grid-column">
<div class="grid-item"><?php echo $certId; ?></div>
<div class="grid-item"><?php echo $certName; ?></div>
</div>
</div>
<span>Sea Services</span>
<div class="grid-group">
<div class="grid-column">
<div class="grid-item header">Sea Service Name</div>
</div>
<div class="grid-column">
<div class="grid-item"><?php echo $servName; ?></div>
</div>
</div>
<?php } ?>
You can check SQL FIDDLE to see what results selecting, duplicating rows.
Have you ideas how can I achieve desired output without duplicates?
UPDATE
After using GROUP_CONCAT
with DISTINCT
It's still wrong. Imagine that In Serv
table I have columns like: UserId
, Name
, Rank
and Country
If the same user worked in different companies (this Name in example - Company Name) with the same rank in different countries, It selecting wrong data. For example:
Serv table (SQL)
UserId Name Rank Country
1 SA Captain USA
1 SB Captain USA
1 SC Captain RUS
1 SD Captain ENG
2 S2A Engineer USA
If I use query like this:
select u.Name
,GROUP_CONCAT(distinct c.Id SEPARATOR '<br>') AS Id
,GROUP_CONCAT(distinct c.certsName SEPARATOR '<br>') AS certsName
,GROUP_CONCAT(distinct s.Name SEPARATOR '<br>') AS Name
,GROUP_CONCAT(distinct s.Rank SEPARATOR '<br>') AS Rank
,GROUP_CONCAT(distinct s.Country SEPARATOR '<br>') AS Country
from users u
left join certs c on u.UserId = c.UserId
left join serv s on u.UserId = s.UserId
where u.UserId = ?
So GROUP_CONCAT(DISTINCT..)
returning me in following:
......
Sea Services:
Sea Service Name Rank Country
SA Captain USA
SB RUS
SC ENG
SD
Only first row have rank and first 3 rows have countries returned, but in database are stored ranks and countries for every row.
Full desired output with this data should be like this:
Personal details:
Name
John
Certificates:
Certificate Id Certificate Name
1 A
2 B
3 C
Sea Services:
Sea Service Name Rank Country
SA Captain USA
SB Captain USA
SC Captain RUS
SD Captain ENG
You can check It at SQL FIDDLE
UPDATE 2
If I remove DISTINCT
I got following output:
Sea Service Name Rank Country
SA Captain USA
SA Captain USA
SA Captain USA
SB Captain USA
SB Captain USA
SB Captain USA
SC Captain RUS
SC Captain RUS
SC Captain RUS
SD Captain ENG
SD Captain ENG
SD Captain ENG
If I'm using DISTINCT
I got like this:
Sea Services:
Sea Service Name Rank Country
SA Captain USA
SB RUS
SC ENG
SD
But It should be:
Sea Services:
Sea Service Name Rank Country
SA Captain USA
SB Captain USA
SC Captain RUS
SD Captain ENG
UPDATE 3
Imagine that I have fixed width of columns and I have long Sea Service Name which will be wrapped to new row:
Sea Service Name | Rank | Country
-----------------|--------|---------
This is long Sea | Captain| USA
Service Name |--------|---------
-----------------| Captain| RUS
Other Name |--------|---------
-----------------| Captain| ENG
Another long Sea |--------|---------
Service Name | Master | USA
-----------------|--------|---------
Other Sea Serv |
-----------------|
As you see now each column are separate, rows didn't match. But It should be like 1 row. So I think I can't achieve It with GROUP_CONCAT
, looks like I need another way.
How It looks in real: