Таблица от одной и многочисленных ссылок, вызывая возвращенные дублируемые ряды

StackOverflow https://stackoverflow.com/questions/2201534

  •  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>с тем же клиентом в списке.

Я понимаю, почему мой запрос возвращает два ряда, это имеет смысл. Итак, есть два раза: вопрос:

  1. Есть ли лучший дизайн базы данных/таблицы, который я должен использовать, или более оптимизированный запрос?
  2. Или это с чем я должен справиться с 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
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top