MySQL Query "Один ко многим" вопрос - PullRequest
1 голос
/ 31 июля 2010

ОК, я постараюсь объяснить это как можно лучше, и, возможно, кто-то поймет это. У меня есть приложение CRM, которое я создаю, и у меня есть следующие таблицы: контакты, электронная почта, телефон, веб-сайт и адрес. Я пытался создать запрос, который собирает всю информацию в один набор результатов. Я нашел способ, который работает на 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] => 
)

Теперь, как вы можете видеть, результат действует так, как я хочу, за исключением случаев, когда на одном элементе имеется несколько допустимых элементов, то есть в этом случае у Джона есть 4 типа телефонных номеров, и это приводит к умножению других записей в БД. соответственно. Таким образом, в этом случае вы получаете 4 одинаковых предмета во всех других вспомогательных таблицах.

Я перепробовал все, что мог, и, возможно, это не может быть сделано, но я подумал, что попробую еще раз и посмотрю, если кто-нибудь посмотрит на это и скажет: о, да, вы пропускаете 5 букв, которые заставят его работать или что-то. На этом этапе даже «ваш глупый, который не будет работать» тоже будет здорово.

Еще раз спасибо за любую помощь, которую может предложить каждый!

UPDATE:

Теперь я чувствую себя таким нубом, я совершил классическую ошибку: я проверил свой результат без полной проверки, но в то же время по предоставленной мною информации это было неясно. Я объясню, как работало мое оригинальное решение, за исключением того, что, когда у меня было 3 рабочих (type = 1) номера, я получал бы такой результат, как phone_type => 1 и phone => 555-1212,555-1213,555-1214, это хорошо, но когда у меня есть 2 работы и 1 дом, идентификаторы типа были бесполезны, но я никогда не говорил, что у вас может быть больше одного типа для контакта, так что на самом деле оба моих ответа ниже верны, с тем, что sql был немного уродливый, но я знал, что он говорил, так что на самом деле это работало лучше и правильно на носу. Кстати, просто вытащив дистанцию ​​из полей типа, я бы тоже этого не сделал ... Я попробовал это.

Новое решение для пациентов:

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 ]

2 голосов
/ 31 июля 2010

Проблема в том, что как только вы присоединяетесь к PHONE (в вашем примере), запрос возвращает четыре записи.Использование GROUP_CONCAT в списке SELECT верхнего уровня не исправит это.Первое решение, которое приходит на ум, - это использовать внутренние запросы, чтобы гарантировать, что вы вернете только одну запись для данного контакта.

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 голос
/ 31 июля 2010

Добавьте туда DISTINCT.

GROUP_CONCAT (DISTINCT email.email_type ORDER BY email.email_type) как email_type,

Ref

0 голосов
/ 31 июля 2010

Не проще ли сначала получить «базовую» информацию для приложения (поля, которые не повторяются), а затем использовать отдельные запросы для повторяющейся информации с использованием подформ в основной форме?

Или, в качестве компромисса, создайте представление, которое отображает до N числа повторяющихся полей.

...