为了便于解释,我会尽量简化一切。
我有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
如果同一个用户在不同的公司工作(这个名称在示例中 - 公司名称),在不同的国家/地区具有相同的级别,则选择错误的数据。例如:
Serv表(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
只有第一行有排名,前三行有国家/地区返回,但在数据库中存储了每行的排名和国家/地区。
此数据的完整所需输出应如下所示:
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
实现它,看起来我需要另一种方式。
它看起来如何:
答案 0 :(得分:5)
您缺少group by
条款:
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
,(SELECT GROUP_CONCAT(ss.Rank SEPARATOR '<br>') FROM users uu
LEFT OUTER JOIN serv ss ON (uu.UserId = ss.UserId)
WHERE uu.user_id = u.user_id) 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
添加了不同内容,因为您要为每个用户加入多个行的多个表,您将有多个重复项。
答案 1 :(得分:2)
在使用重复条目获取整个数据并在 PHP 中分离它们之后,可以使用应用程序逻辑简单地完成此操作。永远记住,您可以拥有多个应用程序服务器来分配其负载,但您总是希望拥有单个数据库服务器,您需要最少的查询负载。此外,客户负载可以在应用程序服务器之间分配,其中相同数量的客户端将访问相同的数据库。
答案 2 :(得分:0)
您需要将DISTINCT
添加到GROUP_CONCAT
,因为您从certs
加入了来自serv
到 m 行的 n 行1}},导致 n * m 行有大量重复。
但是当您使用派生表为每个表执行GROUP_CONCAT
时,每个表只能获得一个行:
select u.Name
,c.Id
,c.certsName
,s.Name
,s.Rank
,s.Country
from users u
left join
( select UserId
,GROUP_CONCAT(Id SEPARATOR '<br>') AS Id
,GROUP_CONCAT(certsName SEPARATOR '<br>') AS certsName
from certs
where UserId = 1
group by UserId
) as c on u.UserId = c.UserId
left join
( select UserId
,GROUP_CONCAT(Name SEPARATOR '<br>') AS Name
,GROUP_CONCAT(Rank SEPARATOR '<br>') AS Rank
,GROUP_CONCAT(Country SEPARATOR '<br>') AS Country
from serv
where UserId = 1
group by UserId
) as s on u.UserId = s.UserId
where u.UserId = 1
请参阅this Q&A
当然,提交单独查询的建议仍然是最佳答案,其他一切只是解决方案。
答案 3 :(得分:0)
SELECT
u.name,
(SELECT GROUP_CONCAT(c.id SEPARATOR '<br>') FROM certs c WHERE c.userId = u.userId) AS Id,
(SELECT GROUP_CONCAT(c.CertsName SEPARATOR '<br>') FROM certs c WHERE c.userId = u.userId) AS certsName,
(SELECT GROUP_CONCAT(s.Name SEPARATOR '<br>') FROM serv s WHERE s.userId = u.userId) AS Name
FROM users u WHERE u.userId = ?
答案 4 :(得分:0)
从TABLE1(TB1)和TABLE2(TB2)中选择多行: 来自TABLE1的CM1_1,CM1_2和来自TABLE2的CM2_1,CM2_2,CM2_3
SELECT CM1_1 , CM1_2 , CM2_1 , CM2_2 , CM2_3 FROM TB1, TB2 WHERE CM1_2 = '1' AND CM1_1 = CM2_1 AND CM2_3 = 'John'