Таблица от одной и многочисленных ссылок, вызывая возвращенные дублируемые ряды
-
18-09-2019 - |
Вопрос
Все, что я видел до сих пор, о автоматическом удалении дублирующих записей в базе данных. Я хочу подчеркнуть в начале этого, что нет дубликатов данных в базе данных. Я также начну с того факта, что я все еще узнаю о дизайне RDBMS, нормализации, отношениях и, прежде всего, SQL!
У меня есть таблица клиентов, с ClientId (PK) и Client_Name. У меня есть таблица ролей, с рориидом (PK) и Role_Name. Любой клиент может иметь несколько ролей, связанных с ним. Поэтому я создал таблицу client_role_link, с ClientId и Roleid в качестве двух полей. Затем я запускаю это:
SELECT client.client_name, role.role_name FROM client
LEFT JOIN client_role_link ON client_role_link.clientid=client.clientid
LEFT JOIN role ON client_role_link.roleid=role.roleid
WHERE (role.roleid='1' OR role.roleid='2')
Итак, допустим, у меня есть клиент, у которого есть две роли, связанные с ним (роли «1» и «2»). Этот запрос возвращает два ряда, по одному для каждой роли. Когда я верну эти результаты, я использую while
цикл, чтобы пройти через результаты и вывести их в <select>
список. Тогда это вызывает два <option>
с тем же клиентом в списке.
Я понимаю, почему мой запрос возвращает два ряда, это имеет смысл. Итак, есть два раза: вопрос:
- Есть ли лучший дизайн базы данных/таблицы, который я должен использовать, или более оптимизированный запрос?
- Или это с чем я должен справиться с PHP? Если так, есть ли более элегантное решение, которое добавляет все результаты в массив, а затем переходит через массив и удаляет дубликаты?
Мысли?
Решение
Если вы хотите показать обе роли, то ваш запрос OK
.
MySQL
не поддерживает массивы данных, поэтому вы должны заполнить ассоциативный массив на PHP
сторона, используя результаты с дублирующими именами клиентов.
Если вам просто нужно показать клиентам, которые имеют одну из ролей, используйте этот запрос:
SELECT c.*
FROM client c
WHERE c.clientid IN
(
SELECT roleid
FROM client_role_link crl
WHERE crl.roleid IN (1, 2)
)
Это вернет одну запись на одного клиента, но не покажет никаких ролей.
Третий способ взорвать имена ролей на стороне сервера:
SELECT c.*, GROUP_CONCAT(role_name SEPARATOR ';') AS roles
FROM client c
LEFT JOIN
client_role_link crl
ON crl.clientid = c.clientid
AND crl.roleid IN (1, 2)
LEFT JOIN
role r
ON r.roleid = crl.roleid
GROUP BY
c.id
и взорвать их на PHP
сторона, но убедитесь, что названия ролей не смешиваются с сепаратором.
Другие советы
Вы могли бы использовать mysql_fetch_assoc () Чтобы вернуть их в форму массива. Тогда у тебя может быть что -то вроде Код непроверенный, но может работать:
$sql = "SELECT client.id, client.client_name, role.role_name FROM client LEFT JOIN client_role_link ON client_role_link.clientid=client.clientid LEFT JOIN role ON client_role_link.roleid=role.roleid WHERE (role.roleid='1' OR role.roleid='2')";
$result = mysql_query($sql);
$res = array();
while ($row = mysql_fetch_assoc($result)) {
$res[$row['id']]['roles'][] = $row['role_name'];
$res[$row['id']]['client_name'] = $row['client_name']; //you'll be overwriting each iteration probably a better way
}