2010-06-28 4 views
1

У меня есть несколько таблиц, которые мне нужно запросить, чтобы получить все строки для определенного пользователя. Таблицы в основном похожа на этойLeft Join duplicates

contact 
======= 
id_contact PK 
firstName 
lastName 
... 

contact_phone 
=============== 
id_contact_phone, PK 
id_contact, FK 
id_phone_type, FK 
phone 
... 

phone_type 
============ 
id_phone_type PK 
phone_type 
.... 

И есть куча таблиц похожа на те, за исключением того, что они для email, phone и т.д. Мне нужно, чтобы отобразить всю эту информацию для данного контакта, я использую несколько LEFT JOIN но я не уверен, как выводить информацию.

Это мой запрос

SELECT contact.id_contact, contact.lastName, contact.firstName, contact_email.email, email_type.email_type, contact_phone.phone, phone_type.phone_type, contact_company.contact_title, company.company_name 
FROM contact 
    LEFT JOIN contact_email 
     ON contact.id_contact = contact_email.id_contact 
    LEFT JOIN email_type 
     ON contact_email.id_email_type = email_type.id_email_type 
    LEFT JOIN contact_phone 
     ON contact.id_contact = contact_phone.id_contact 
    LEFT JOIN phone_type 
     ON contact_phone.id_phone_type = phone_type.id_phone_type 
    LEFT JOIN contact_company 
     ON contact.id_contact = contact_company.id_contact 
    LEFT JOIN company 
     ON contact_company.id_company = company.id_company 
WHERE contact.id_contact = $cid 

Моя проблема заключается в том, что если некоторый контакт имеет несколько номеров телефонов, электронной почты и т.д. запрос будет явно возвращать более 1 строку, так что я точно не знаю, как отобразить информация, поскольку большинство столбцов будут дублировать друг друга. Вот пример того, что этот запрос может вернуть

+===========================================================================================+ 
| id_contact | lastName | firstName | email   | email_type | phone | phone_type | 
+===========================================================================================+ 
| 1   | Doe  | John  | [email protected] | Work  | 555-1234 | Work  | 
+------------+----------+-----------+------------------+------------+----------+------------+ 
| 1   | Doe  | John  | [email protected] | Work  | 555-2222 | Mobile  | 
+-------------------------------------------------------------------+----------+------------+ 
| 1   | Doe  | John  | [email protected] | Personal | 555-1234 | Work  | 
+------------+----------+-----------+------------------+------------+----------+------------+ 
| 1   | Doe  | John  | [email protected] | Personal | 555-2222 | Mobile  | 
+-------------------------------------------------------------------+----------+------------+ 

Как я могу отобразить информацию в PHP без избыточных данных и может быть оптимизирован мой запрос?

+0

Я не уверен, что вы спрашиваете здесь. Вы хотите, чтобы первые столбцы (id, lastName и firstName) были NULL? Почему этот результат не работает для вас?- должно быть построено таблицей с пустыми ячейками для «повторных данных» с этим набором результатов, – Artefacto

+0

Я хочу отобразить информацию на странице профиля контакта с помощью 'mysql_fetch_array', но прямо сейчас, которая будет отображать только первую строку (которые будут отсутствовать) или если я использую цикл while, я не смогу сказать, являются ли электронные письма дублирующими. Я обновил свой пример – Serge

+0

Довольно легко определить, являются ли они дублирующими, когда вы используете цикл: просто закажите их с предложением ORDER BY, а затем включите что-то вроде 'if ($ prev_value! = Row ['email']) {$ prev_value = строка ['email']; ...} 'и вставьте другой код обработки в ... часть. Если вы хотите сделать это с каждым полем, то по-прежнему довольно легко сделать что-то подобное с массивом предыдущих значений и просто обрабатывать каждый отдельно. –

ответ

0

У mysql есть замечательная функция group_concat. В сочетании с GROUP BY id_contact` это сделает то, что вы хотите. Для примера:

SELECT contact.id_contact, contact.lastName, contact.firstName, 
    GROUP_CONCAT(CONCAT(contact_email.email, ' : ', email_type.email_type) SEPARATOR ', ') AS email, 
    GROUP_CONCAT(CONCAT(contact_phone.phone, ' : ', phone_type.phone_type) SEPARATOR ', ') AS phone, 
    contact_company.contact_title, company.company_name 
FROM contact 
    LEFT JOIN contact_email 
     ON contact.id_contact = contact_email.id_contact 
    LEFT JOIN email_type 
     ON contact_email.id_email_type = email_type.id_email_type 
    LEFT JOIN contact_phone 
     ON contact.id_contact = contact_phone.id_contact 
    LEFT JOIN phone_type 
     ON contact_phone.id_phone_type = phone_type.id_phone_type 
    LEFT JOIN contact_company 
     ON contact.id_contact = contact_company.id_contact 
    LEFT JOIN company 
     ON contact_company.id_company = company.id_company 
WHERE contact.id_contact = $cid 

Обратите внимание, что я никогда не использовал GROUP_CONCAT вокруг нормального CONCAT, но я не вижу никаких причин, почему она не будет работать.

+0

Я не думаю, что это хорошая идея. Если он хочет создать таблицу, проще связать определенную электронную почту с определенным типом контакта, если они находятся в одной строке, а не в той же строке и в той же позиции, разделенной запятыми. – Artefacto

+0

Я должен был упомянуть, что я пробовал это раньше, и это заканчивается тем, что дает повторяющиеся записи. Если у контакта есть 2 письма и 2 телефонных номера, запрос вернет 4 строки (2 с 'john.doe @ 123.com' и 2 с помощью' jdoe @ email.com'). Кроме того, контакт может иметь больше, чем тот же тип электронной почты, телефон и т. Д. – Serge

0

Если ваши электронная почта и телефонные типы последовательны вы могли бы могли придавить его к одной строке, возвращая различные типы как спроецированные столбцы, например, для типов электронной почты:

SELECT contact.id_contact, contact.lastName, contact.firstName, 
    contact_company.contact_title, company.company_name, work_email.email AS work_email, 
    personal_email.email as personal_email, mobile_phone.phone as mobile_phone, 
    work_phone.phone as work_phone 
FROM contact 
    LEFT JOIN contact_email AS work_email 
    ON (contact.id_contact = work_email.id_contact AND 
     work_email.id_email_type = email_type.id_email_type AND 
     email_type.email_type = 'Work') 
    LEFT JOIN contact_email AS personal_email 
    ON (contact.id_contact = personal_email.id_contact AND 
     personal_email.id_email_type = email_type.id_email_type AND 
     email_type.email_type = 'Personal') 
    LEFT JOIN contact_phone AS mobile_phone 
    ON (contact.id_contact = mobile_phone.id_contact AND 
     mobile_phone.id_phone_type = phone_type.id_phone_type AND 
     phone_type.phone_type = 'Mobile') 
    LEFT JOIN contact_phone AS work_phone 
    ON (contact.id_contact = work_phone.id_contact AND 
     work_phone.id_phone_type = phone_type.id_phone_type AND 
     phone_type.phone_type = 'Work') 
WHERE contact.id_contact = $cid 
+0

вот что, они не будут согласованы, тип может быть изменен или новые могут быть добавлены, предоставлено не будет сотни разных типов, но Я не думаю, что я мог бы жестко записать его – Serge

+0

В этом случае вам, вероятно, придется обработать его на стороне вашего экрана в PHP, добавит еще одно сообщение о том, как вы можете это сделать. – Turnkey

0

Если у вас есть непоследовательный/неизвестно количество электронных писем или телефонных номеров и т. д., тогда вам может быть лучше получить данные с помощью нескольких операторов выбора. На самом деле все зависит от того, как вы хотите использовать данные на стороне веб-сервера. Скорее всего, вы действительно не нуждаетесь в этом в этом табличном формате.

Если вы беспокоитесь о производительности выполнения нескольких запросов, помните, что иногда вы можете поместить несколько операторов в один запрос и вернуть несколько наборов результатов. Я не знаю, это то, что вы можете сделать с PHP, но я бы предположил, что это так.

0

Поскольку типы неизвестны вы можете использовать некоторые группировки на стороне PHP путем расширения на другой ответ на подобный вопрос на PHP: Grouping Records from While Loop

Сначала убедитесь, что Вы заказываете на id_contact и типов в запрос:

... 
WHERE contact.id_contact = $cid 
ORDER BY contact.id_contact, email_type.email_type, phone_type.phone_type 

Затем сделайте ручную группировку на строке отображается в то время как цикл через строку результата:

$contact_id = 0; 
while($row = mysql_fetch_array($result)) 
{ 
    if($row['contact_id'] != $contact_id) 
    { 
     echo '<hr><br><h3>Contact: ' . $row['first_name'] . $row['last_name'] . '</h3>'; 
     $contact_id= $row['contact_id']; 
     $phone_type = null; 
     $email_type = null; 
    } 
    if ($row['email_type] != $email_type) 
    { 
     echo $row['email_type'] . ' Email: ' . $row['email']; 
     $email_type = $row['email_type'] 
    } 
    if ($row['phone_type] != $phone_type) 
    { 
     echo $row['phone_type'] . ' Phone: ' . $row['phone']; 
     $phone_type = $row['phone_type'] 
    } 
} 
+0

Я надеялся, что смогу добиться этого по-другому. Я сделаю несколько тестов и посмотрю, что я получаю. Система предназначена только для внутреннего использования, так что на данный момент не будет более 20 пользователей, зарегистрированных в одно и то же время, я думаю, что это не должно сильно ухудшать производительность. – Serge

+0

. Хорошая идея провести некоторый бенчмаркинг, я думаю, что влияние производительности будет быть пренебрежимо малым, должно быть способно отображать многие сотни контактов за долю секунды. – Turnkey

+0

У нас не было времени, чтобы попробовать до сих пор, и запрос фактически возвращает то же, что и в моем примере, что означает, что он все равно будет отображать повторяющиеся записи для телефонов .... – Serge