MySQL查询“一对多”问题

时间:2010-07-30 20:57:48

标签: mysql one-to-many

好的我会尽力解释这个,也许有人会理解它。我有一个我正在构建的CRM应用程序,并具有以下表格:联系人,电子邮件,电话,网站和地址。我一直在尝试创建一个Query,将所有信息收集到一个结果集中。我有点找到了99.9%的工作方式,但我认为我错过了1%的工作,并试图找到它自杀。

我的查询如下:

SELECT 
contacts.full_name,
contacts.title,
contacts.company,
contacts.background,
GROUP_CONCAT( email.email_type ORDER BY  email.email_type)as email_type,
GROUP_CONCAT( email.email ORDER BY  email.email_type)as email,
GROUP_CONCAT( phone.phone_type ORDER BY phone.phone_type)as phone_type,
GROUP_CONCAT( phone.phone ORDER BY phone.phone_type)as phone,
GROUP_CONCAT( website.website_type ORDER BY website.website_type)as website_type,
GROUP_CONCAT( website.website ORDER BY website.website_type)as website,
GROUP_CONCAT( address.type ORDER BY  address.type ) as address_type,
GROUP_CONCAT( address.address_street ORDER BY  address.type ) as street,
GROUP_CONCAT( address.address_city ORDER BY  address.type ) as city,
GROUP_CONCAT( address.address_state ORDER BY  address.type ) as state,
GROUP_CONCAT( address.address_zip ORDER BY  address.type ) as zip,
GROUP_CONCAT( address.address_country ORDER BY  address.type) as country
FROM
contacts
Left Join email ON contacts.id = email.contact_id
Left Join phone ON contacts.id = phone.contact_id
Left Join website ON contacts.id = website.contact_id
Left Join address ON contacts.id = address.contact_id
GROUP BY
contacts.id
ORDER BY
contacts.id ASC

现在就像我说它的工作方式类似于我想要的99.9%,但这里是结果集: (现在这是一个模拟结果对象,但它遵循查询后当前吐出的内容。)

stdClass Object
(
    [full_name] => John Mueller
    [title] => President
    [company] => Mueller Co.
    [background] => This is the contacts background info.
    [email_type] => 1,1,1,1
    [email] => jm@mc.com,jm@mc.com,jm@mc.com,jm@mc.com
    [phone_type] => 1,2,3,4
    [phone] => (123) 555-1212,(123) 555-1213,(123) 555-1214,(123) 555-1215
    [website_type] => 1,1,1,1
    [website] => www.mc.com,www.mc.com,www.mc.com,www.mc.com
    [address_type] => 1,1,1,1
    [street] => {address_1},{address_1},{address_1},{address_1}
    [city] => {city_1},{city_1},{city_1},{city_1}
    [state] => {state_1},{state_1},{state_1},{state_1}
    [zip] => {zip_1},{zip_1},{zip_1},{zip_1}
    [country] => 
)

现在你可以看到结果就像我想要的那样,除了当一个项目有多个有效项目时,即在这种情况下John有4种类型的电话号码,这导致DB中的其他记录成倍增加因此。因此,在这种情况下,您将在所有其他支持表中获得4个相同的项目。

我已尽力而为但也许无法完成但是我想我会再试一次,看看是否有人会看到它然后说哦,是的,你错过了5个字母,可以使它工作或者一些东西。在这一点上,即使是“你的愚蠢无法奏效”也应该是伟大的。

再次感谢任何人提供的任何帮助!

更新:

我觉得现在就像这样一个菜鸟,我拉了一个经典的错误:我检查了我的结果而没有完全验证,但同时我提供的信息也不清楚。我将解释我的原始解决方案有效,但是当我有3个工作(类型= 1)数字时,我最终会得到像phone_type =>这样的结果。 1和phone => 555-1212,555-1213,555-1214这很好,但是当我有2个工作和1个家庭时,类型标识符是无用的,但我从来没有说过你可以拥有一个以上任何类型的联系人,所以实际上两个我在下面的回答是正确的,有人说sql有点格格不入,但我知道他在说什么,所以它实际上更好,更正确的鼻子。 BTW只是从类型字段中拉出distint也不会这样做...我试过了。

新的查询解决方案:

SELECT

contacts.full_name,
contacts.title,
contacts.company,
contacts.background,

inner_phone.phone,
inner_phone_type.phone_type

FROM
contacts

left Join (SELECT phone.contact_id, GROUP_CONCAT(phone.phone ORDER BY phone.phone_type) as phone FROM phone GROUP BY phone.contact_id ) inner_phone ON contacts.id = inner_phone.contact_id
left Join (SELECT phone.contact_id, GROUP_CONCAT(phone.phone_type ORDER BY phone.phone_type) as phone_type FROM phone GROUP BY phone.contact_id ) inner_phone_type ON contacts.id = inner_phone_type.contact_id

ORDER BY
contacts.id ASC

感谢您的回答,并且作为旁注,我刚刚取消了过高的专家交换,这是更容易使用,找到您正在寻找的,最好的免费;) - 再次感谢。

3 个答案:

答案 0 :(得分:2)

问题是,只要您加入PHONE(在您的示例中),查询就会返回四条记录。在顶级SELECT列表中使用GROUP_CONCAT不会解决这个问题。首先想到的解决方案是使用内部查询来保证您只返回给定联系人的一条记录。

SELECT 
contacts.full_name,
[...]
inner_phone.phones
FROM contacts 
LEFT JOIN (SELECT GROUP_CONCAT(phone ORDER BY phone_type) AS phones, contact_id FROM phone) inner_phone ON contacts.ID = inner_phone.contact_id
[... etc. for other tables ...]

这应该让你走上正轨,除非MySQL与MSSQL / Oracle的子查询行为截然不同......

答案 1 :(得分:1)

在那里扔DISTINCT。

GROUP_CONCAT(DISTINCT email.email_type ORDER BY email.email_type)as email_type,

Ref

答案 2 :(得分:0)

首先将“基础”信息提供给应用程序(不重复的字段),然后使用主窗体中的子表单对重复信息使用单独的查询会不会更容易?

或者,作为折衷方案,创建一个最多显示N个重复字段的视图。

相关问题