Sorting the results of a mysql query - php

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?

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.

There are two obvious approaches:
Sort the results once you've fetched them
Fetch them all in one query and have the DB sort them
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>');
}

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.

Related

Retrieve certain row from array depending on a value

Echo out the right row from an array compiled from a mysql database.
I have extracted information from a database (locations) containing three fields: id, name, city into an array called $array. I want to loop through another database (events) in which the id's from the first database (locations) are stored in a field. When looped I want to display the corresponding name and city from the locations database.
Is this possible without having to fetch information every loop?
This is my first try
$query = "Select id, name, city FROM locations WHERE typ = '1'";
$result = mysqli_query($conn, $query);
$row = array();
while ($row = mysqli_fetch_assoc($result)) {
$array[] = $row;
}
And then I thought I could specify the key myself like this:
$query = "Select id, name, city FROM locations WHERE typ = '1'";
$result = mysqli_query($conn, $query);
$row = array();
while ($row = mysqli_fetch_assoc($result)) {
$array[$row['id']] = $row;
}
But I couldn't figure out how to echo the right row.
You can join both tables in a single query, using something like this:
Select locations.id, locations.name, locations.city, events.name
FROM locations
JOIN events ON locations.id = events.id
WHERE locations.typ = '1'
The events.id on the JOIN statement is assuming that this is the column name of the id in the events table. I also made the assumption that these are the two fields that will match between the two tables. Adjust accordingly if your matching criteria is different.
The SELECT statement was modified to pull columns from both tables. Add whichever fields are relevant to your needs.

WHERE query in MYSQL

I have two MySQL tables. One is called members and has a column called users. The other is called sex and has two columns: user_s and sex.
I am trying to create an array comprised of all users from the members table who are
1) in the sex table and 2) have "men" selected in the sex column.
When I print_r this array nothing is displayed even though I can see that there are users who met these criteria. Any thoughts?
<?php
// test.php
include_once("header.php");
$iaminterestedin = "men";
$result = queryMysql("SELECT `user` FROM `members`
WHERE `user` IN(SELECT `user_s` FROM `sex` WHERE sex='$iaminterestedin')");
$combination = array();
while(($row = mysql_fetch_assoc($result)))
{
$combination = $row['user'];
}
print_r($combination);
?>
You should add values to combination using $combination[] = $row['user'] or you will always overwrite value on each loop iteration
You also ought to read something about JOIN tables, this will help you a lot with queries like that. For example you will use:
SELECT user FROM members INNER JOIN sex ON sex.user_s = members.user
WHERE sex '$iamintererstedin'
If you add a foreign key (http://dev.mysql.com/doc/refman/5.0/en/innodb-foreign-key-constraints.html) from sex to users this will improve query performance when it gets bigger and time becomes a problem
Try replacing the line
$combination = array();
With
$combination[] = $row['user'];
This is the way to insert into an array:
I replaced $combination = $row['user'];
with
$combination[] = $row['user'];
That did the trick.

Explode multiple user Ids

Im having trouble getting explode to work I have a table field named Attending with multiple user Ids separated with commas 73,1,5 right now i can easily get user 73 to echo out but need explode for the rest, I want it to echo out each username of those 3 users or however many it ends up being. I was thinking it might be something like what i commented out with the //
Attending Field is list of users
http://imageshack.us/a/img38/1425/eventsne.jpg
Trying to Echo out like this once i get username working ill do the avatar and in a table
http://imageshack.us/a/img819/8210/events2d.jpg
$Attending1 = array();
$Attending1 = mysql_query("SELECT * FROM Events, Users WHERE Events.Attending = Users.UserId");
//$AttendingUserIds = $Attending1['Attending'];
//$AttendingExploded = explode(",", $AttendingUserIds);
//$Attending3 = array();
//$Attending3 = mysql_query("SELECT * FROM Events, Users WHERE $AttendingExploded = Users.UserId");
while ($Attending2 = mysql_fetch_array($Attending1)) {
echo $Attending2['username'];
}
Just tryed KyleK 3rd suggestion
$Attending1 = array();
$Attending1 = mysql_query("SELECT * FROM Events, Users WHERE Events.Attending = Users.UserId");
$AttendingUserIds = $Attending1['Attending'];
//$AttendingExploded = explode(",", $AttendingUserIds);
$Attending3 = array();
$Attending3 = mysql_query("SELECT * FROM Events, Users WHERE Users.UserId IN ($AttendingUserIds)");
It gives me Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource where the While starts.
You can do it all in just one SELECT, by joining Events and Users tables thru the find_in_set() function. That way, you will get all users which attended each event, because find_in_set() will look up the first parameter in the CSV string supplied as the second parameter. You may also want to add a WHERE to filter a specific event. And don't forget to replace the * with only the fields you need, to avoid unnecessary data traffic:
$Attending = array();
$Attending = mysql_query("
SELECT *
FROM Events e
INNER JOIN Users u ON find_in_set(u.UserId, e.Attending)
");
$Attending1 = mysql_query("SELECT * FROM Events, Users WHERE Events.Attending = Users.UserId");
while ($Attending2 = mysql_fetch_assoc($Attending1)) {
$arr[] = $Attending2['username'];
}
mysql_query doesn't give you an array, fetch_array (or fetch_assoc) does.
Its result will be similar to this: $arr[0]['username'], $arr[1]['username'], $arr[2]['username'], etc. I don't know how you want to "explode" so I can't answer, but after fetch_assoc you should get an array.
So if I understand you correctly you have values in a string that are comma seperated "73, 3, 5".
So then just use WHERE IN
Your string of values from the database, however you gonna get it...
$stringofids = "73,3,3";//You will obviously retrieve these from database
Then just pass that string into another query, with a WHERE IN statement...
That will return an array of all the users attending.
$AttendingUsers = mysql_query("SELECT * FROM Events, Users WHERE Users.UserId IN ($stringofids)");
while ($Attending = mysql_fetch_array($AttendingUsers)) {
echo $Attending['username'];
}

Efficiently maintaining order of a bullet point like list in mysql

I have a user editable list like bullet points. Points are being deleted and added(to the end or middle of the list) frequently. Is there any more efficient way of maintaining this list's ORDER than having each bullet have an id and keeping a SQL entry of the order split by commas? Example:
$result = mysql_query("SELECT order FROM users WHERE user = '$userId'"); //Get order for logged in user. returns id1,id2,id3,id4
$row = mysql_fetch_array($result);
$order = explode(',', $row['order']); //make the order an array
$result = mysql_query("SELECT id, data FROM bullets"); //get all the bullets
$bullets = array();
while($row = mysql_fetch_array($result)){
$project[$row['id']] = $row['data'];
}
Then run:
foreach($order as $k => $v){
echo '<li id="'.$k.'">'.$v.'</li>';
}
You can add an ordinal field to the bullets table.
Then your select looks like this:
SELECT id, data FROM bullets ORDER BY ordinal
Also, you shouldn't store denormalized data like you're doing with order in your users table.
Also, you shouldn't name a field order because it is a reserved word.

Building a dynamic HTML list from MySQL results

I have a set of tables (for this question I'll say two) in the database, one of which is the users table and one of which is one for storing URL's. The one that store URL's contains the URL ID (auto increment) and the User_ID. The user id is submitted when the add url form is submitted.
I'm trying to figure out how I can display these results as a table. For each user I need to get the list of URL's that are associated with their account and display them as a list. I have the user-id stored as a variable so it can be called from anywhere. How would I select items from the database that are only associated with the current logged in users id? and also how would I then generate a list of the results.
Thanks in advance.
This is a very basic php mysql question so you can probably find it by looking around the site but to save you some time:
//assuming the userid for logged in user is in $userid
$sql = "SELECT * FROM urls_table WHERE User_ID=$userid";
$result = mysql_query($sql); $data = array();
while($row=mysql_fetch_assoc($result)) {
$data[] = $row['URL'];
}
print_r($data);
//or foreach($data as $url) print "$url\n";
If instead of the user id of the logged in user you had the name then do an inner join like so:
//assuming the user name for logged in user is in $username
$sql = "SELECT * FROM urls_table INNER JOIN users_table ON urls_table.User_ID = users_table.User_ID WHERE User_Name=$username";
$result = mysql_query($sql); $data = array();
while($row=mysql_fetch_assoc($result)) {
$data[] = $row['URL'];
}
print_r($data);
//or foreach($data as $url) print "$url\n";

Categories