У меня возникают трудности с поиском элегантного решения для сортировки результатов запроса mysql на основе строки с разделителями. Я объясню более подробно ниже
Я создаю базу данных контактов, в которой отдельные пользователи могут добавлять / удалять людей из списка. Когда пользователь добавляет новый контакт, я добавляю добавленный идентификатор контакта в строку с разделителями и сохраняю эти данные в столбце базы данных, связанном с этим пользователем (с именами контактов):
$userID = ?? //YOUR ID $contactID = ?? //WHATEVER THE ADDED USER ID IS $confirm = 0 //has the user been confirmed $sql = "SELECT contacts FROM user WHERE id = '$userID'"; $query = mysql_query($sql); $row = mysql_fetch_array($query); $contact = $row['contacts']; $contact .= '|'.$contactID.':'.$confirm; $update = mysql_query("UPDATE user SET contacts = '$contact' WHERE id = '$userID'"); //contact column data might be: |10:0|18:0|36:0|5:0
Когда пользователь ищет свои контакты, я беру данные из столбца контактов, вставляю / разделяю строку и возвращаю имена отдельных пользователей:
$userID = ?? //YOUR ID $sql = "SELECT contacts FROM user WHERE id = '$userID'"; $query = mysql_query($sql); $row = mysql_fetch_array($query); $contacts = explode("|", $row['contacts']); foreach($contacts as $item) { list($contactID,$confirm) = split(":", $item); $sql = "SELECT name FROM ".user." WHERE id = '$contactID'"; $query = mysql_query($sql); $row = mysql_fetch_array($query); echo($row['name'].'<BR>'); }
-$userID = ?? //YOUR ID $sql = "SELECT contacts FROM user WHERE id = '$userID'"; $query = mysql_query($sql); $row = mysql_fetch_array($query); $contacts = explode("|", $row['contacts']); foreach($contacts as $item) { list($contactID,$confirm) = split(":", $item); $sql = "SELECT name FROM ".user." WHERE id = '$contactID'"; $query = mysql_query($sql); $row = mysql_fetch_array($query); echo($row['name'].'<BR>'); }
Это действительно возвращает все имена, но возвращает их в порядке строки с разделителями. Кажется, я не могу найти элегантный способ сортировки по имени в алфавитном порядке.
Должен ли я не хранить список контактов в разделительной строке? Как бы вы решили это?
Вы правы, вы не должны хранить контакты в строке. Вместо этого используйте другую таблицу, которая содержит информацию о пользователе. Новая таблица должна выглядеть примерно так:
Table: user_contacts | user_id | contact_id | confirm | ------------------------------------------- | your data here... |
Затем, когда вам нужен ваш список контактов, вы можете просто выполнить другой запрос:
SELECT * FROM `user_contacts` JOIN `users` ON `users`.`id` = `user_contatcs`.`user_id` WHERE `users`.`id` = $id ORDER BY `users`.`name`;
Или, тем не менее, вам нужно заказать его.
Существует два очевидных подхода:
Для # 1 используйте usort()
:
$rows = array(); foreach ($contacts as $item){ list($contactID,$confirm) = split(":", $item); $query = mysql_query("SELECT name FROM user WHERE id = '$contactID'"); $rows[] = mysql_fetch_array($query); } usort($rows, 'sort_by_name'); function sort_by_name($a, $b){ return strcmp($a['name'], $b['name']); } foreach ($rows as $row){ echo($row['name'].'<BR>'); }
-$rows = array(); foreach ($contacts as $item){ list($contactID,$confirm) = split(":", $item); $query = mysql_query("SELECT name FROM user WHERE id = '$contactID'"); $rows[] = mysql_fetch_array($query); } usort($rows, 'sort_by_name'); function sort_by_name($a, $b){ return strcmp($a['name'], $b['name']); } foreach ($rows as $row){ echo($row['name'].'<BR>'); }
Для # 2 создайте список идентификаторов и используйте IN
:
$ids = array(); foreach ($contacts as $item){ list($contactID,$confirm) = split(":", $item); $ids[] = $contactID; } $ids = implode(',', $ids); $query = mysql_query("SELECT name FROM user WHERE id IN ($ids) ORDER BY name ASC"); while ($row = mysql_fetch_array($query)){ echo($row['name'].'<BR>'); }
-$ids = array(); foreach ($contacts as $item){ list($contactID,$confirm) = split(":", $item); $ids[] = $contactID; } $ids = implode(',', $ids); $query = mysql_query("SELECT name FROM user WHERE id IN ($ids) ORDER BY name ASC"); while ($row = mysql_fetch_array($query)){ echo($row['name'].'<BR>'); }
Если вы используете реляционную базу данных, то вам нужна отдельная таблица, в которой хранятся отношения между людьми. Затем вы измените свой SQL-запрос, чтобы выбрать его на основе объединения по двум таблицам
SELECT * FROM person, contact JOIN contact ON person.id = contact.personid JOIN person ON contact.contactid = person.id WHERE person.id = $id ORDER BY person.lastname
(Этот код, вероятно, не совсем правильный.)
Если вы используете реализацию типа no-sql, то, как вы это делаете, хорошо, за исключением того, что вам придется либо программно сортировать после факта, либо сортировать по вставке. Сортировка по вставке означает, что вам нужно будет запросить текущий список контактов при вставке, а затем выполнить сортировку, чтобы найти нужную позицию и вставить идентификатор в строку с разделителями. Затем сохраните это обратно к db. Недостатком этого является то, что вы сможете сортировать только один способ.
Как правило, люди используют реляционные базы данных и «нормализуют» их, как описано выше.