tags:

views:

305

answers:

3

Pretty new to all this, so if I am going about my puzzle in a crazy way please tell me!

I have a table in a mySQL database with the columns title, hyperlink, imagelink

I want the php to select a row at random, then be able to save the title, hyperlink and imagelink as php variables. (so I can then output them into html)

so I could have for e.g

psuedoey code to get the idea

chosenNumber = randomNumber();

$chosenTitle = title[chosenNumber]
$chosenHyperlink = hyperlink[chosenNumber]
$chosenImagelink = imagelink[chosenNumber]

echo "<a href = $chosenTitle><img src= $chosenImagelink/> $chosenTitle </a>";

I think I need to use an assoc array like this here but I am very confused, because I looked through the various php mySQL fetch_assoc fetch_row etc and can't find which one to do what i need :(

What I have so far is

// database table name information
$number = "number";
$title = "title";
$hyperlink = "hyperlink";
$imagelink = "imagelink";

// sql to select all rows of adverts
$sql = "SELECT $number, $title, $hyperlink, $imagelink FROM $table";

//execute the sql
$data = mysql_query($sql, $link);

//count the number of rows in the table
$bannerCount = mysql_num_rows($data);

//generate a random number between 0 and the number of rows
$randomNumber = mt_rand(0, $bannerCount); //do I need to do bannerCount-1 or similar here?
$chosenNumber = $randomNumber;

//select data from a random row

First time post, be kind please, and thanks for any replies or explanations!

A: 

If you want to get records randomly, you can simply modify your sql query and each time you will get random ordering of records, just add order by rand() to your query and limit clause if you want to get just one random record:

$sql = "SELECT $number, $title, $hyperlink, $imagelink FROM $table
order by rand() limit 1";

Once you have done that, you need to use functions like mysql_fetch_array or mysql_fetch_object to get the rows actually:

$data = mysql_query($sql, $link);

while ($row = mysql_fetch_array($data))
{
  echo $row['title'] . '<br />';
  echo $row['hyperlink'] . '<br />';
  echo $row['imagelink'] . '<br />';
}

With:

$row = mysql_fetch_array($data)

You have $row array available at your disposal to echo values at any place of your page like:

  echo $row['title'];
  echo $row['hyperlink'];
  echo $row['imagelink'];
Web Logic
`ORDER BY rand()` can be quite expensive on larger tables
gnarf
@gnarf -- Considering she was just grabbing every row, I think RAND would work.
Kerry
@Kerry - It would work, yes. However considering the OP was asking for a better way to do it, why suggest something that scales badly? I also notice that you (and the two people who upvoted your comment) didn't upvote the answer, so it must not be that recommended :)
gnarf
@gnarf: I have modified my answer by adding `limit` clause if the OP needed just one random row :)
Web Logic
`LIMIT 1` will only slightly reduce the performance penalty of using `ORDER BY RAND()` - MySQL will still need to generate a random number for every row, and then select the smallest value (without having an index to rely on)
gnarf
Thanks everyone, plenty to think about, I will use the most upvoted answer as I understood it best, and I might need to think about scale issues, as I don't know how large the live table might end up.Nice simple looking elegant solution, instead of my confused mess! Thanks :)
princessmarisa
A: 

I think if you use the "limit" clause, it would be quite efficient:

SELECT number, title, hyperlink, imagelink FROM $table order by rand() limit 1

Why do you set up variables for the table name and field names?

ChrisV
I set up variables for the fieldnames and tablename because I am making this for someone else, who has not yet given me the details of the names of the columns in their database, so I have had to make an "example" one of my own to show the code working. I didn't want to have to and change all the code to make it work when they give me the live datam just the info at the top all in one place.
princessmarisa
+1  A: 

Using ORDER BY RAND() LIMIT 1 is a decent way to get a single row out of a smaller table. The downside to using this method is that RAND() must be calculated for every row in the table, and then a sort must be performed on this non-indexed value to calculate the row you want. As your table grows, ORDER BY RAND() becomes horribly inefficient. The better way to handle this is to first get a count of the number of rows in the table, calculate a random row number to read, and use the LIMIT [offest,] count option on your SQL query:

$sql = "SELECT COUNT(*) as rows FROM $table"
$res = mysql_query($sql);
if (!$row = mysql_fetch_assoc($res)) {
  die('Error Checking Rows: '.mysql_error());
}
$rows = $row['rows'];

// now that we know how many rows we have, lets choose a random one:
$rownum = mt_rand(0, $rows-1);
$sql = "SELECT number, title, hyperlink, imagelink FROM $table LIMIT $rownum,1";
$res = mysql_query($sql);
$row = mysql_fetch_assoc($res);

// $row['number'] $row['title'] etc should be your "chosen" row

This first query asks the SQL Server how many rows are available, then LIMITs the result set of the actual query to only return 1 row, starting at the random number row we picked.

gnarf
Per this: http://stackoverflow.com/questions/684989/one-complex-query-vs-multiple-simple-queries it seems that multiple queries would not be the solution, especially in PHP where you can only perform on MySQL query at one call. Is there a reason this is not true?
Kerry
Faster than MySQL having to generate potentially thousands of random numbers and then index them - yes.
gnarf
Okay, then that doesn't mean it's an end-all solution. Both are good. It would depend on the size of your database. Where do you draw the line? 1000 records? 100,000? etc?
Kerry
Hence why I mentioned both methods.. `ORDER BY RAND() LIMIT 1` is okay for smaller data sets. I would think that anything over 1,000 or so records would save the SQL server a bit of overhead. The `RAND()` query can't be cached by MySQL, but the `COUNT(*)` and `LIMIT offset, 1` queries can and will be optimized. Creating a simple table and adding 5,000 rows to it made a 0.01sec query each time.
gnarf