I can slightly expand upon that, but I'm going a slightly different direction.
Since you're pulling from the database, just select randomly an item whose ID is not in the Cookie or Session.
So for every new page, the fact would be "random" except that the random fact would only be chosen from those yet to be shown.
<?php
function showRandom()
{
// Get those already used facts into a local var
$already_seen = $_SESSION['_used_facts_'];
// Start a new query to select a random row
$query = "SELECT a.* FROM `table` as a
JOIN (SELECT RAND() * (SELECT MAX(id) FROM `table`)) as b";
// If we've already seen some facts, let's "eliminate" them
if(!empty($already_seen) && is_array($already_seen))
{
$query .= "
WHERE id NOT IN(" . implode(',', $already_seen) . ")";
}
// Okay, now time for the ordering and limiting of results
$query .= "
ORDER BY a.id ASC
LIMIT 1";
// Execute the query
$result = mysql_query($query) or die('Database Error: ' . mysql_error());
// If we have 0 rows, then we must be out of facts
if(mysql_num_rows($result) == 0)
{
// Reset our session so we don't get this error anymore...
$_SESSION['_used_facts_'] = array();
// Run the function over again, and return the result
return showRandom();
}
// Otherwise, we have a random row ;)
else
{
// Get the row into a local associative array
$row = mysql_fetch_assoc($result);
// Add the ID to the session array
$_SESSION['_used_facts_'][] = $row['id'];
// Return the row array for use elsewhere
return $row;
}
}
So you see, before we return the information from the database, we add the row's ID to the Session array so it can't be used again. And after our query, if the result is 0, then we "clear out" the IDs in our session, and run the function again.
This isn't full-proof, just meant as a proof of concept. And if you're wondering why the query looks so odd, it's just because "ORDER BY RAND()" isn't really optimized and isn't necessarily random 😉 Just read through the user notes at the mySQL documentation on ORDER BY for more info.
Hope that helps.