Reputation: 37
Im having difficulties trying to figure out an elegant solution to sorting the results of a mysql query based on a delimited string. Ill explain in more detail below
I am creating a database of contacts where individual users can add/remove people from a list. When the user adds a new contact I append the added contact id to a delimited string and store that data in a database column associated with that user (named contacts):
$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
When the user searches their contacts I grab the data from the contacts column, explode/split the string and return the individual users names:
$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>');
}
This indeed does return all the names, but it returns them in the order of the delimited string. I cant seem to find an elegant way to sort by name alphabetically.
Should I not store the contacts list in a delimited string? How would you solve this?
Upvotes: 1
Views: 4266
Reputation: 21269
If you're using a relational database, then what you want is a separate table that stores person-contact relationships. Then you would modify your sql query to select based on a join across two tables
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
(That code is probably not quite correct.)
If you're using a no-sql type implementation, the way you're doing it is fine, except that you will either have to programmatically sort after the fact, or sort-on-insert. Sort on insert means you'd have to query the current list of contacts on inserting one, then sort through to find the right position and insert the id into the delimited string. Then save that back to the db. The downside to this is you'll only be able to sort one way.
Generally, people use relational databases and 'normalize' them as described above.
Upvotes: 1
Reputation: 7157
There are two obvious approaches:
For #1, use 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>');
}
For #2, build a list of IDs and use 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>');
}
Upvotes: 2
Reputation: 9937
You're right, you should not store the contacts in a string. Instead use another table which contains the user information. The new table should look something like the following:
Table: user_contacts
| user_id | contact_id | confirm |
-------------------------------------------
| your data here... |
Then when you need your contact list you can simply perform another query:
SELECT * FROM `user_contacts`
JOIN `users` ON `users`.`id` = `user_contatcs`.`user_id`
WHERE `users`.`id` = $id
ORDER BY `users`.`name`;
Or however you need to order it.
Upvotes: 2