数据库多对多关联问题
三张表
表 employee 员工表
---------------
编号 姓名
id name
---------------
表 contract 合同
------------------------
编号 项目 签单时间 客户名称
id project signTime customer
------------------------
表 mapping 员工-合同映射表
------------------------
eid cid
员工表和合员表通过映射表关联,关系是一个员工可以签多个合同,而一个合同也可能是几个员工一起签的。就是一个多对多的关系。
目前在合同列表时出现问题。
在无任何查询条件下,单一列出合同列表的项目如下
----------------------------------------------------------
客户名称 项目 签单时间 签单人
CSDN 建站 2005-03-03 小王,小张,小李
.....
这种情况可以采用如下SQL取得
SELECT c.*, e.name, group_concat(e.name) AS signPerson
FROM contract AS c
LEFT JOIN mapping AS m ON c.id=m.cid
LEFT JOIN employee AS e ON m.eid=e.id
GROUP BY c.id;
----------------------------------
注:group_concat函数在mysql4.1以上才有效,是否有别的方法可替代
----------------------------------
但在查询某一个员工的合同列表时就有问题
SELECT c.*, e.name, group_concat(e.name) AS signPerson
FROM contract AS c
LEFT JOIN mapping AS m ON c.id=m.cid
LEFT JOIN employee AS e ON m.eid=e.id
WHERE m.eid = 1
GROUP BY c.id;
----------------------------------------------------------
客户名称 项目 签单时间 签单人
CSDN 建站 2005-03-03 小王
.......
这样会把m.eid不是1的过滤掉,在group_concat时,签单人只有一个员工,就是id=1的员工
目前采用的解决办法是先将mapping表中eid=1对应的合同ID取出来,
在执行第一条SQL,用 WHERE c.id IN( .... )来做,
但是IN效率不高,如果合同数据量大的话,会不会有问题?
-----------
求解决思路
问题点数:300、回复次数:19Top
1 楼meizz(梅花雪)回复于 2006-02-16 10:03:13 得分 30
沙发?Top
2 楼ashchen(老陳)回复于 2006-02-16 11:02:29 得分 30
板凳Top
3 楼yh801216(艾奥利斯)回复于 2006-02-16 11:10:24 得分 100
有个想法,等我测试下,
希望能帮到大大们。Top
4 楼eglic(圪圪) (理由永远是谎言,信仰永远是自慰)回复于 2006-02-16 11:12:15 得分 0
group_concat 是个什么函数?Top
5 楼eglic(圪圪) (理由永远是谎言,信仰永远是自慰)回复于 2006-02-16 11:15:12 得分 0
最好的办法还是,在Contract表里面加一个字段,用来记录签单人
反正一个合同签下来 签单人就定了,也不会修改
这样也就不用这么复杂了Top
6 楼yh801216(艾奥利斯)回复于 2006-02-16 11:48:49 得分 0
SELECT c.*, e.name, group_concat(e.name) AS signPerson
FROM mapping AS m
LEFT JOIN contract AS c ON c.id=m.cid LEFT JOIN mapping AS m2 ON c.id=m2.cid LEFT JOIN employee AS e ON m2.eid=e.id
WHERE m.eid = 1
GROUP BY c.id;Top
7 楼yh801216(艾奥利斯)回复于 2006-02-16 11:49:30 得分 0
错了,再改改。Top
8 楼yh801216(艾奥利斯)回复于 2006-02-16 11:51:00 得分 0
SELECT c.*, e.name, group_concat(e2.name) AS signPerson
FROM mapping AS m
LEFT JOIN contract AS c ON c.id=m.cid LEFT JOIN mapping AS m2 ON c.id=m2.cid LEFT JOIN employee AS e ON m.eid=e.id LEFT JOIN employee AS e2 ON m2.eid=e2.id WHERE m.eid = 1
GROUP BY c.id;Top
9 楼helloyou0(你好!)回复于 2006-02-16 12:58:08 得分 0
来迟了~~Top
10 楼zalvsa(水米)回复于 2006-02-16 13:19:04 得分 30
这样会把m.eid不是1的过滤掉,在group_concat时,签单人只有一个员工,就是id=1的员工
你的目的不就是要把m.eid不是=1的给过滤掉吗?那过滤掉不就正好满足你的目的了?
Top
11 楼zalvsa(水米)回复于 2006-02-16 13:30:24 得分 0
而且好象主表的选择有问题,应该是FROM mapping.
group_concat(e.name),那既然只有选择某个人,那group_concat(e.name)不就没有意义了?
select c.*,e.name from mapping as m left join employee as e on m.eid=e.id left join
contract on m.cid=c.cid where e.eid='1' order by e.idTop
12 楼yh801216(艾奥利斯)回复于 2006-02-16 13:39:16 得分 0
查询结果explain后的结果是 查询员工 所签的每个合同包含的员工数的总和。
效率应该可以。
楼主看下:P
另外,group_concat的替代方法在mysql中可能很难找。。
只能不group by 而用order by ,然后在程序里组合字符串。。。
SELECT c.*, e.name, e2.name FROM mapping AS m
LEFT JOIN contract AS c ON c.id=m.cid LEFT JOIN mapping AS m2 ON c.id=m2.cid LEFT JOIN employee AS e ON m.eid=e.id LEFT JOIN employee AS e2 ON m2.eid=e2.id WHERE m.eid = 1
ORDER BY c.id;
仅仅是我能想到的哈。:P
Top
13 楼ice_berg16(寻梦的稻草人)回复于 2006-02-16 15:04:37 得分 0
to zalvsa(水米)
我的目的是得到该员工的合同列表,如果一个合同有二个以上的签单人,
那么m.eid!=1的人员就被过滤了,也就是说本来这个人也有签单的份,列表中的签单人却没人他,举个例子
----mapping表----
eid cid
1 1
2 1
2 2
1 3
----employee表----
id name
1 小王
2 小李
----contract表----
id project signTime customer
1 建站 2005-11-29 CSDN
2 推广 2006-01-02 CSDN
3 Google 2006-02-13 CSDN
-----------------------
不指定条件的结果应该是这样
客户名称 项目 签单时间 签单人
CSDN 建站 2005-03-03 小王,小李
CSDN 推广 2006-01-02 小李
CSDN Google 2006-02-13 小王
------------------------
指定条件后(假如查eid=1的,即小王)
客户名称 项目 签单时间 签单人
CSDN 建站 2005-03-03 小王
CSDN Google 2006-02-13 小王
可以看到本来小李也参与了建站的项目,却没显示出来,
因为where m.eid=1的时候把m表中的 eid=2 cid=1这条记录过滤了,
group_concat的时候无论什么合同都只有变成只有小王一人了,
这就是问题。Top
14 楼ice_berg16(寻梦的稻草人)回复于 2006-02-16 15:05:47 得分 0
to yh801216(艾奥利斯)
由员签单人的个数不是固定的,
仅通过join多个m和e表是不能解决所有问题的。Top
15 楼yh801216(艾奥利斯)回复于 2006-02-16 16:26:11 得分 0
...
楼主仔细看看嘛。。。
小子再菜,你也该仔细看看再评价吧。。。Top
16 楼zalvsa(水米)回复于 2006-02-16 16:33:30 得分 0
明白LZ的意思了,是如果合同有A,则这个合同的所有人员都要列出来,而不是只列A。
那这样的话,估计只有通过PHP来实现了。group_concat没办法拿来做条件判断。Top
17 楼Cain(一苇渡江)回复于 2006-02-16 16:40:44 得分 40
留个记号,一会回来再看Top
18 楼yh801216(艾奥利斯)回复于 2006-02-16 17:20:08 得分 30
。。。
这都哪是哪啊。。。。
我闪了。
楼主试验一下我的行不行吧,我想能够满足你的要求。
你们继续:PTop
19 楼helloyou0(你好!)回复于 2006-02-17 12:50:59 得分 40
笑坏了,小艾的明明是对的,就是无处伸冤~~~~~~
那个sql里包括了第一个sql,然后再做一个自连接到employee表
Top




