【发布时间】:2016-07-24 23:55:11
【问题描述】:
为了更容易解释,我将尝试简化所有内容。
我有 3 个 SQL 表:Users、Certs、Serv
Users 表中存储了有关唯一用户的详细信息。
在Certs 表中存储有关证书的详细信息以及拥有此证书的用户的UserId(1 个用户可以拥有多个证书)
在Serv 表中存储有关海上服务的详细信息和用户的UserId(如Certs 表,1 个用户可以在Serv 表中拥有多个条目)
样本数据
用户
UserId Name
1 John
2 Lisa
证书
Id UserId CertName
1 1 A
2 1 B
3 1 C
4 2 A
5 2 C
服务
UserId Name
1 SA
1 SB
1 SC
1 SD
2 S2A
我需要通过 PHP 检索输出,例如(其中 UserId = 1),实际上每个表中都会有更多列(例如证书的更多详细信息,如签发日期、到期日期、签发地点等开):
Personal details:
Name
John
Certificates:
Certificate Id Certificate Name
1 A
2 B
3 C
Sea Services:
Sea Service Name
SA
SB
SC
SD
但是我得到了错误的输出,重复的条目,这是因为加入 2 个带有 UserId 的表,其中有多个带有这个 UserId 的记录。
PHP 代码
$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 } ?>
您可以查看SQL FIDDLE 以查看选择、复制行的结果。
您知道如何在不重复的情况下实现所需的输出吗?
更新
在使用GROUP_CONCAT 和DISTINCT 之后仍然是错误的。想象一下,在Serv 表中,我有如下列:UserId、Name、Rank 和 Country
如果同一用户在不同的公司工作(例如这个名字 - 公司名称)在不同的国家具有相同的排名,它选择了错误的数据。例如:
服务表 (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
如果我使用这样的查询:
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 = ?
所以GROUP_CONCAT(DISTINCT..) 回复我如下:
......
Sea Services:
Sea Service Name Rank Country
SA Captain USA
SB RUS
SC ENG
SD
只有第一行有排名,前 3 行有国家/地区返回,但在数据库中存储了每一行的排名和国家/地区。
包含此数据的完整期望输出应如下所示:
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
您可以在SQL FIDDLE查看它
更新 2
如果我删除 DISTINCT 我得到以下输出:
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
如果我使用DISTINCT,我会得到这样的结果:
Sea Services:
Sea Service Name Rank Country
SA Captain USA
SB RUS
SC ENG
SD
但它应该是:
Sea Services:
Sea Service Name Rank Country
SA Captain USA
SB Captain USA
SC Captain RUS
SD Captain ENG
更新 3
假设我有固定宽度的列,并且我有很长的海上服务名称,它将被包装到新行:
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 |
-----------------|
正如您现在看到的,每一列都是独立的,行不匹配。但它应该像 1 行。所以我想我无法用GROUP_CONCAT 实现它,看来我需要另一种方式。
真实的样子:
【问题讨论】:
-
一条建议:不要在 SQL 或任何数据访问层中对数据进行格式化。使用它来提取数据,然后使用应用程序逻辑来转换该数据以进行演示或用于其他用例。