Having difficulties sorting data from mysql query using php - php

This code is used to get a specific list of ID's from one table, then use those ID's to get the information from another table. Once I get all the information from the 2nd table, I am attempting to sort the data alphabetically based on a field in the 2nd table.
Example, I am getting the name based on a correlating ID and then want to display the entire result in alphabetical order by name (artist_name).
Here is the code I have. When I execute this without the sort(), it works fine but is not in alphabetical order. When I add the sort() in the 2nd while statement, the page looks the same but the name and other data do not display. The source code in the browser shows that the results are being accounted for but the sort must be preventing the variables or information from being displayed for some reason.
I haven't used a sort function before and I tried looking at some examples but couldn't really find something specific to my situation. Any and all help would be greatly appreciated. I have already looked at the PHP manual for sort so no need to send me a link to it ;-)
<?php $counter = 0;
$artistInfo = mysql_query("SELECT DISTINCT event_url_tbl.artist_id FROM event_url_tbl WHERE (SELECT cat_id FROM artist_tbl WHERE artist_tbl.artist_id = event_url_tbl.artist_id) = 1");
while ($aID = mysql_fetch_array($artistInfo))
{
$getArtistInfo = mysql_query("SELECT * FROM artist_tbl WHERE artist_id = '" . $aID['artist_id'] . "'");
while($artist = mysql_fetch_array($getArtistInfo))
{
sort($artist);?>
<a class="navlink" href="<?=HOST?><?=$artist['page_slug']?>/index.html">
<?=$artist['artist_name']?>
</a><br />
<?php }
}
?>

Your best bet, as a commenter mentioned, is to use an ORDER BY clause in SQL.
SELECT *
FROM artist_tbl
WHERE artist_id = XXX
ORDER BY artist_name ASC
The other commenter who suggested using PDO or mysqli is also correct, but that's a different issue.
To answer your specific question about sorting, according to the manual,
Blockquote Note: This function assigns new keys to the elements in array. It will remove any existing keys that may have been assigned, rather than just reordering the keys.
This means all of your array keys ('page_slug', 'artist_name', etc) are wiped out. So when you try to refer to them later, there is no data there.
Were you to use this method, you would want to use asort to sort an associative array.
However, you don't want to use sort here. What you're sorting is the variables for one row of data (one individual artists), not all of your artists. So if you think of each artist row as an index card full of data (name, id#, page slug, etc) all you're doing is moving those items around on the card. You're not reorganizing your card catalog.
Using an order by clause in the SQL statement (and rewriting in PDO) is your best bet.
Here is how I would rewrite it. I have to take some guesses at the SQL because I'm not 100% sure of your database structure and what you're specifically trying to accomplish, but I think this would work.
$query_str = "
SELECT
artist.name,
artist.page_slug
FROM
artist_tbl AS artist
INNER JOIN event_tbl AS event
ON event.artist_id = artist.artist_id
WHERE
artist.cat_id = 1
ORDER BY
artist.name ASC";
$db_obj = new PDO (/*Connection stuff*/);
$artists_sql = $db_obj->prepare ($query_str);
$artists_sql->execute ();
while ($artist = $artists_sql->fetch (PDO::FETCH_ASSOC)) {
$return_str .= "<a class='navlink' href='{HOST}
{$artist['page_slug']}/index.html'>
{$artist['artist_name']}</a><br/>";
}
echo $return_str;
In all honesty, I would probably create an artist class with a display_link method and use PDO's fetchObject method to instantiate the artists, but that's getting ahead of ourselves here.
For now I stuck with procedural code. I don't usually like to mix my HTML and PHP so I assign everything to a return string and echo it out at the end. But this is close to what you had, using one SQL query (in PDO - seriously worth starting to use if you're creating new code) that should give you a list of artists sorted by name and their associated page_slugs.

You could do all of this in one query:
SELECT * FROM event_url_tbl AS event
INNER JOIN artist_tbl AS artist ON event.artist_id = artist.id
ORDER BY artist.name DESC;
This cuts out a lot of the complexity/foreaches in your script. You'll end up with
Label1 (Label 1 details..) Artist1 (Artist1 details..)
Label1 (Label 1 details..) Artist2 (Artist1 details..)
Label2 (Label 2 details..) Artist3 (Artist1 details..)
Always good to bear in mind "one query is better than many". Not a concrete rule, just if it's possible to do, try to do it. Each query has overheads, and queries in loops are a warning sign.
Hopefully that helps

Related

function render makes website 500% slow! can anyone fix that please?

Function render makes website 500% slow! Can anyone fix that please ?
Someone told me :
because it sends a database request on each iteration of the loop (it's not the only problem with this chunk of code but it's the most taxing one)
Yes I understand what that means. His way is:
you need to get all of the data before you start building the menu,
then you just insert the data instead of requesting more data on each
iteration
But i don't know how i must do it!
<?php
$menu_html='';
function render_menu($parent_id,$actmenuid)
{
$obj = new Database();
$con = $obj->dbconnectt();
global $menu_html;
$result=mysqli_query($con, "select * from tbl_menu where parent_id='$parent_id'");
if(mysqli_num_rows($result)==0) return;
if($parent_id==0){
$menu_html.='<ul class="topnav">';
}else{
$menu_html.='<ul>';
}
while($row=mysqli_fetch_array($result)) {
$childnum = $obj->recordcount("SELECT * FROM tbl_menu WHERE parent_id='".$row['id']."'");
if($childnum == 0){
$linkvalue='/category/'.$row['id'].'.html';
} else{
$linkvalue='#';
}
if($row['id']==$actmenuid && $actmenuid !=NULL){
$actv='class="active"';
}else{
$actv='';
}
$menu_html.='<li '.$actv.'>'.$row['title'].'';
render_menu($row['id'],$actmenuid);
$menu_html.='</li>';
}
$menu_html.='</ul>';return $menu_html;
}
if($isDsh==false){
echo render_menu(0,$actmenuid);
}
?>
Depending on how many records you have, try removing this query from inside the loop since it's running for every record on the first query.
$childnum = $obj->recordcount("SELECT * FROM tbl_menu WHERE parent_id='".$row['id']."'");
Change it a single query like this where it returns counts for each parent idea, and place it outside of the loop:
$parentcount = mysqli_query($con, ("SELECT parent_id, count(*) FROM tbl_menu GROUP BY parent_id");
There may be other issues, so please post the database structure and number of records that you're working with too.
Don't make recursive queries.
Having "more than 1000" rows is not too big. You can simply call everything from the table into php, then perform the recursive html build in php this will have a memory overhead, but far less processing overhead because you only ever make one trip to the db.
Alternatively (when your db table is prohibitively large), you should avoid gathering rows unnecessarily by adding a new column. The new column will store all "descendants" for the respective row when the row is INSERTed or update it when it is UPDATEd. Then you only need to reference this column when needing to call specific rows. In other words, do the recursive processing only once (when writing to the db) AND not when needing to display the data. This will, again, produce a finite result set in one query which can then be recursively traversed to build the desired output.
basically you need to do what #spudly has suggested.
But there is a small catch in his solution which depending on the number of the rows in yous tbl_menu table you may use a big chunk of memory to fetch all the records.
you can optimise it more with using his solution but changing the query to:
select
parent_tbl_menu.id,
count(child_tbl_menu.id) as cnt
from
tbl_menu as parent_tbl_menu
left join
tbl_menu as child_tbl_menu
on parent_tbl_menu.id = child_tbl_menu.parent_id
where
parent_tbl_menu.parent_id = ?
group by
parent_tbl_menu.id
This way you will only fetch the child records of a specific parent.
And please consider using prepared statements as your code has sql injection vulnerability.
Connect (from PHP to MySQL) only once for the entire web page.
Don't put a SELECT inside a loop if you can do all the work in a single SELECT, such as with a JOIN. (Exception: A "hierarchical" table needs the nested SELECT. Exception to the exception: MySQL 8.0 and MariaDB 10.2 can do it with a "recursive CTE".)
Don't fetch all the columns (SELECT *) when all you want it is a recordcount. Instead, SELECT COUNT(*) ... and use the number returned.
1000 of anything is probably excessive for a web page. Re-think the UI.

Multiple MYSQL Statements executed as a single statement

I've got a bit of a problem with my code. I'm sure that it is something simple, but I just can't figure it out! I have been on tons of forums and have read several books... but every answer that I have worked to has failed. I almost guarantee that it's the way that I am using my syntax (and yes I know... procedural PHP is not really used anymore) but I am really a bit of a newbie to this and I am just trying to pick up the basics before moving onto OOP and PDO connections.
Could you please help me? At the moment I can get the user to select their date from the date picker and the results specifically from that date only will return... only problem is that the event is displaying the event_id as opposed to the name of the event that it relates to (1 = 5km run) for example.
Somehow I need to access the events table and pull the row that relates to that specific event_id.
I have normalized my database, and according to my tutor it looks ok. To give you an idea what it looks like - logins table (all user logins details), results table (a history of submitted events) events table (the events themselves).
On the results table the foreign keys are logins_id and the event_id. The primary key is the results_id in the results table and the only data stored here is the time and data (individual columns).
<?php // -----Stage 1. On submission of the form run the following -----//
if (isset($_POST['submit_d'])) {
$mydate = $_POST ['MyDate'];
$my = preg_replace('/[^a-zA-Z0-9]+/', ' ', $mydate);
if ($mydate) {
$result = mysql_query("SELECT * FROM logins WHERE username = '$username' LIMIT 1");
//This function will take the above query and create an array...
while($row = mysql_fetch_array($result))
{
//With the array created above, I can create variables (left) with the outputted array (right)
$logins_id3 = $row['logins_id'];
}
$sql = "SELECT * FROM results where $logins_id3 AND date = $mydate ";
/* ----- Here is the code that I want to use in conjunction with the above statement --->
$query = "SELECT logins.username,events.event,results.time,results.date,logins.age,logins.gender
FROM logins INNER JOIN results ON logins.logins_id=results.logins_id INNER JOIN events ON results.event_id=events.event_id
ORDER BY time ASC LIMIT 10";
*/
$resultz = mysql_query($sql);
if( mysql_num_rows($resultz) ) {
while ($row = mysql_fetch_array($resultz)) {
echo "<table><tr><th>Username</th><th>Event</th><th>Time (HH:MM:SS)</th><th>Date (YY/MM/DD)</th><th>Age</th><th>Gender</th>
</tr><tr><td>".$username."</td>"
."<td>".$row['event_id']."</td>"."<td>".$row['time']."</td>"." <td>".$row['date']."</td>"."<td>".$row['age']."</td>".
"<td>" $row['gender']."</td></tr></table>";
}
}
}
}
?>
The other thing I would like to do.. although this is not crucial, is to strip special characters from the input. Basically I'm using a jquery calendar picker and I want the user to be able to select their date in the 2014-05-26 format and the php to remove the - before it is submitted to the database, that way it doesn't effect the users experience but it will work with my current code.
Anyways sorry to waffle on, any help on either of these matters would be much appreciated!
Yours Sincerely:
Peter Scales.
You can use a join to get the data that relates to the event ID:
SELECT * FROM results r LEFT JOIN events e ON r.event_id = e.event_id WHERE ...
You can then select where "e.event_id = $event_id"; and the rest of your query logic.
You can also filter out any unwanted characters by using preg_replace: http://ar2.php.net/preg_replace

PHP MySQL While loop for SELECT from two tables?

Hi there i am working on PHP code that is selecting columns from two tables.
Here is my code:
$result2 = mysql_query("SELECT *
FROM `videos`, `m_subedvids`
WHERE `videos.approved`='yes' AND
`videos.user_id`='$subedFOR'
ORDER BY `videos.indexer`
DESC LIMIT $newVID");
while($row2 = mysql_fetch_array($result2))
{
$indexer = addslashes($row2['videos.indexer']);
$title_seo = addslashes($row2['videos.title_seo']);
$video_id = addslashes($row2['videos.video_id']);
$title = addslashes($row2['videos.title']);
$number_of_views = addslashes($row2['videos.number_of_views']);
$video_length = addslashes($row2['videos.video_length']);
}
When i try to print $indexer with echo $indexer; it's not giving me any results.
Where is my mistake in this code?
It seems to me like the key 'indexer' isn't in your results. It's hard to tell, since you haven't listed a definition for your table and you're using SELECT * so we can't see the names.
It makes the program easier to read later, if instead of SELECT *..., you use SELECT col1, col2, .... Yes, SELECT * will save you some typing right now, but you'll lose that time later when you or anyone else who works on your code has to check the table definition every time they work with that line of code.
So, try changing your query to explicitly select the columns you use. If it's an invalid column you'll get an error right away rather than this silent failure you're getting now, and you'll thank yourself later as well.
So long as videos.indexer is a unique field name among all tables used in the query you can change
$indexer = addslashes($row2['videos.indexer']);
to
$indexer = addslashes($row2['indexer']);
You don't need to (or can not) use the table name when referring to the result.

How to filter by multiple fields in MySQL/PHP

I'm writing a filter/sorting feature for an application right now that will have text fields above each column. As the user types in each field, requests will be sent to the back-end for sorting. Since there are going to be around 6 text fields, I was wondering if there's a better way to sort instead of using if statements to check for each variable, and writing specific queries if say all fields were entered, just one, or just two fields, etc.
Seems like there would be a lot of if statements. Is there a more intuitive way of accomplishing this?
Thanks!
Any initial data manipulation, such as sorting, is usually done by the database engine.
Put an ORDER BY clause in there, unless you have a specific reason the sorting needs done in the application itself.
Edit: You now say that you want to filter the data instead. I would still do this at the database level. There is no sense in sending a huge dataset to PHP, just for PHP to have to wade through it and filter out data there. In most cases, doing this within MySQL will be far more efficient than what you can build in PHP.
Since there are going to be around 6 text fields, I was wondering if there's a better way to sort instead of using if statements to check for each variable
Definitely NO.
First, nothing wrong in using several if's in order.
Trust me - I myself being a huge fan of reducing repetitions of code, but consider these manually written blocks being the best solution.
Next, although there can be a way to wrap these condition ns some loop, most of time different conditions require different treatment.
however, in your next statements you are wrong:
and writing specific queries
you need only one query
Seems like there would be a lot of if statements.
why? no more than number of fields you have.
here goes a complete example of custom search query building code:
$w = array();
$where = '';
if (!empty($_GET['rooms'])) $w[]="rooms='".mesc($_GET['rooms'])."'";
if (!empty($_GET['space'])) $w[]="space='".mesc($_GET['space'])."'";
if (!empty($_GET['max_price'])) $w[]="price < '".mesc($_GET['max_price'])."'";
if (count($w)) $where="WHERE ".implode(' AND ',$w);
$query="select * from table $where";
the only fields filled by the user going to the query.
the ordering is going to be pretty the same way.
mesc is an abbreviation for the mysql_real_escape_string or any other applicable database-specific string escaping function
select * from Users
order by Creadted desc, Name asc, LastName desc, Status asc
And your records will be sorted by order from query.
First by Created desc, then by Name asc and so on.
But from your question I can see that you are searching for filtering results.
So to filter by multiple fileds just append your where, or if you are using any ORM you can do it through object methods.
But if its simple you can do it this way
$query = "";
foreach($_POST['grid_fields'] as $key => $value)
{
if(strlen($query) > 0)
$query .= ' and '
$query .= sprintf(" %s LIKE '%s' ", mysql_real_escape_string($key), '%' .mysql_real_escape_string($value) .'%');
}
if(strlen($query) > 0)
$original_query .= ' where ' . $query;
this could help you to achieve your result.
No. You cannot avoid the testing operations when sorting the set, as you have to compare the elements in the set in same way. The vehicle for this is an if statement.
Could you take a look at this?
WHERE (ifnull(#filter1, 1) = 1 or columnFilter1 = #filter1)
and (ifnull(#filter2, 1) = 1 or columnFilter2 = #filter2)
and (ifnull(#filter3, 1) = 1 or columnFilter3 = #filter3)
and (ifnull(#filter4, 1) = 1 or columnFilter4 = #filter4)
and (ifnull(#filter5, 1) = 1 or columnFilter5 = #filter5)
and (ifnull(#filter6, 1) = 1 or columnFilter6 = #filter6)
Please let me know if I'm misunderstanding your question.. It's not like an IF statement batch, and is pretty lengthy, but what do you think?

MySQL fetch_assoc question

Is it possible to use a nested mysql_fetch_assoc Basically I used the first one to populate text boxes, now from another table I need to fetch and image. How do I go about doing this without closing the first one, because I have more text boxes below this image that need to be fetched.
while($row = mysql_fetch_assoc($result)){
?>
<form id="myform" name="myform" action="profiledo.php" method="post">
<p>First Name
<input type="text" name="firstname" id="textfield" value="<?php echo( htmlspecialchars( $row['FirstName'] ) ); ?>" />
<br />
in order to be able to fetch $result more times (I see no reason though), you'll have to make single query for each fetch. I see no reason for doing so though
I think you are looking for a single query with a join. Something like:
SELECT * FROM `Profile` NATURAL JOIN `Table with Image`
But the exact query depends on the schemas of your two tables.
I think that it is more beneficial to put all of the information you want quickly into an array and accessing the retrieved data from memory, as opposed to slowly adding it while the query is looping through it.
// Read records
$query = "SELECT * FROM table WHERE condition";
$query = mysql_query($query);
// Put them in array
for($i = 0; $array[$i] = mysql_fetch_assoc($query); $i++) ;
// Delete last empty one
array_pop($array);
You can use print_r($array) to see the results.
If the image is not on the same table, you could join the tables via a similar identifier (unique user id?).
$query = "SELECT * FROM table1, table2 WHERE table1.id=table2.id";
Then the first user's First name would be: $array[0]['FirstName'], second would be $array[1]['FirstName'], etc.
Blake
The answer is, yes it is possible to use nested mysql_fetch_assoc().
Though I'm not very sure on the question and what does your current implementation looks like but here are some suggestion anyways:
Use a JOIN query: though it is possible only if the data contained in your text-boxes is related to the image. From what little information you have provided, I guess the image is the user's image and is stored in a separate table. If that is true, then the most obvious implementation is that the image table is referenced by some user id. Assuming that there is a User and UserImage tables, this is how the JOIN query might look like:
SELECT `User.*`, `UserImage`.`image`
FROM `User`
INNER JOIN `UserImage` ON `User`.`id` = `UserImage`.`user_id`
WHERE `User`.`id` = xxx;
Please note that the above is only a template query and you'll need to change this as per your schema and logic. Also, I missed to mention that the above implementation might need some extra logic if there can be multiple images per user.
A nested mysql_fetch_assoc() is possible but it depends on your implementation. As you've mentioned that the first (or outer) mysql_fetch_assoc() is used to fill-in text boxes. And within this, you would like to run another mysql_fetch_assoc() to fetch the image. So, if the image query is run on a separate table and is run as a separate query, then you might store its result in a separate variable, say $result1 and then run the inner mysql_fetch_assoc() on that resultset.
while ($row = mysql_fetch_assoc($result)) {
// $row array now contains the profile details
$result1 = mysql_query('the query for fetching the image');
while ($row1 = mysql_fetch_assoc($result1)) {
// $row1 array now contains the image
}
}
It is important that the inner mysql_fetch_assoc() runs on a separate resultset.
Hope the above helps! If it is none of the above that you are trying to do, I'd appreciate if you could provide more inputs on what you require.

Categories