I am trying to make an article website, but I want to normalize my current database. I have four tables each labeling a category except for one. The four tables are: Entertainment, Lifestyle, Science, and Articles. Articles is the combination of all the entries of Entertainment, Lifestyle, and Science. I want to delete Entertainment, Lifestyle, and Science and just leave the Articles table, thus saving space and increasing performance. The only problem I am facing though is with a query that generates random articles by getting the last ID of the table, and then getting a random number between 6 and the max ID.
All my tables have the following structure: id (unique), category (the type of article this is, i.e Entertainment), title (title of the article), image (image URL of the article), link (URL of the article), Counter (number of views this article has), and dateStamp (the date the article was published). Here's the query I am trying to update based on my normalized database.
<?php
//SELECT the MAX id from the Entertainment table
$MAX_ID = $db->query("SELECT MAX(id) FROM Entertainment");
//Get Max id value
$MAX_ID = $MAX_ID->fetch_array();
$MAX_ID = $MAX_ID[0];
//Create random number variable
$RAND_NUM;
//If the Max ID is less than 6, make $MAX_ID the $RAND_NUM
if ($MAX_ID < 6) {
$RAND_NUM = $MAX_ID;
}
//Else get a random value between 6 and the Max ID
else {
$RAND_NUM = mt_rand(6, $MAX_ID);
}
//Grab 6 articles by descending from the random number, example: If $RAND_NUM is 7, get all entries from 7-2
$resultSet = $db->query("SELECT * FROM Entertainment WHERE id <= $RAND_NUM ORDER BY id DESC LIMIT 6");
if ($resultSet->num_rows != 0) {
//Booleans to check where we are at in the print off
$conditional = true;
$conditional2 = true;
echo "<div class='row'>";
while ($rows = $resultSet->fetch_assoc()) {
$image = $rows["image"];
$title = $rows["title"];
$link = $rows["link"];
$count = number_format($rows["Counter"]);
//Print off these articles on the left
if ($conditional == true && $conditional2 == true) {
echo "<div class='left'><a href='$link'><img src=$image><p>$title</p></a><p id='article-views'><span class='glyphicon glyphicon-fire'></span> $count Views</p></div>";
$conditional2 = false;
}
//Print off these articles on the right
else {
echo "<div class='right'><a href='$link'><img src=$image><p>$title</p></a><p id='article-views'><span class='glyphicon glyphicon-fire'></span> $count Views</p></div><hr>";
$conditional2 = true;
}
}
echo "</div>";
}
?>
How should I change/update this query to make it so that I get random Entertainment articles from the Articles table? I am open to any changes that improve the performance of the query as well.
Instead of selecting a random ending ID, just randomize all the rows and select 6 from them.
SELECT *
FROM Articles
WHERE category = 'Entertainment'
ORDER BY RAND()
LIMIT 6
If you need to avoid ORDER BY RAND() because it doesn't perform well enough, see How can i optimize MySQL's ORDER BY RAND() function?
Related
I have a database with multiple users. Each user has an id, name and position. I want to display users by position. To take an example I have a table with 7 numbered positions.
Position Name
1.
2.
3.
4.
5.
6.
7.
And 4 users in the database that I want to display according to their position.
Name Position
User_1 4
User_2 7
User_3 1
User_4 3
How can I do this without using the loop for or while for display?
I tried
for ($j=1; $j<=$no_rows; $j++){
$rand = mysqli_fetch_array($tabel);
$name[$j]=trim($rand['user']);
}
And then display for each number in that table that name[j].
Position Name
1. $name[1]
2. $name[2]
3. $name[3]
4. $name[4]
5. $name[5]
6. $name[6]
7. $name[7]
If those 4 users have positions 1,2,3,4, they are arranged by position, if one has the position higher than the total number of users then nothing is displayed, or it is displayed chaotically.
I also tried with j <= 7 but again the same problem.
The question needs more info but here is a rough idea based on what you have so far and my making some assumptions that this is a leader board style list.
// Something like: $query = 'SELECT * FROM users ORDER BY point DESC';
$count = 1;
while ($row = mysqli_fetch_array($query_results_object))
{
// Process data here.
echo $count . ': ' . $row['username'];
// Bail on 7.
if ($count >= 7)
{
break;
}
$count ++;
}
// Fill in empty values.
while ($count < 7)
{
echo $count . ': Space available.';
}
You did say without using the loop for display and your modified example appears to indicate you want rank instead of leader board position.
// Something like: $query = 'SELECT * FROM users';
$list = array_fill(1, 7, 'empty_value');
while ($row = mysqli_fetch_array($query_results_object))
{
// Process data here.
$list[$row['rank']] = $row['name'];
}
echo $list[1];
echo $list[2]];
...
This would be very inefficient as if you had 100 users you would be adding all of them to an in-memory table only to display 7 of them. So make sure you query does something like: SELECT TOP 7 * FROM users ORDER BY position DESC
I've a table that has three columns id, points, rank. Timely I update data for all fields so points go up and down but old rankings remains same, so I'm trying to find out a way that entitles each id its deserving rank based on points earned.
I've got more than 2000 rows in this table. I wish to do it in php5+ with mysqli? I think I've a solution but it times out even with 1200 seconds timeout setting and memory gets exhausted.
I think my solution works accurately but any of the loops needs some doctor. Here my rough target is 'update' query to go accurate that takes all points in desc order, and awards id a rank against the points earned:
<?php
require_once $_SERVER['DOCUMENT_ROOT'].'/includes/db.inc.php';
$a2= mysqli_query($link, "SELECT COUNT(*) as count FROM p1");
$b2 =mysqli_fetch_array($a2);
$count = $b2['count'];
$i=1;
while($i<=$count){
$a1= mysqli_query($link, "SELECT points FROM p1 ORDER BY points DESC LIMIT $i");
if(!$a1){
echo mysqli_error($link);
}
while($po = mysqli_fetch_array($a1)){
$ross[] = $po;
}
foreach($ross as $pot){
$points=$pot['points'];
}
$a5a= mysqli_query($link, "SELECT id FROM p1 WHERE points = '$points'");
while($popo = mysqli_fetch_array($a5a)){
$idi=$popo;
}
foreach($idi as $idm){
$id=$idm['id'];
$rank = $i;
$update = mysqli_query($link,"UPDATE p1 SET rank = '$rank' WHERE points = '$points' AND id ='$id'");
}
if(!$update){
echo "Error updating Rank".mysqli_error($link);
} else {
echo "Succuessul for where id = '$id' and points = '$points' set rank = '$rank'<br/>";
}
$i++;
}
?>
I have replaced my original answer with much leaner and shorter code, you can of course include modification to the rank counter if consecutive users have same points but you can figure this yourself
This code have just one loop and is conserving memory and your DB as well
<?php
require_once $_SERVER['DOCUMENT_ROOT'].'/includes/db.inc.php';
$a = mysqli_query($link, "SELECT id, points, rank FROM p1 ORDER BY points DESC "); // lets get users in new ordering
$rank = 1; // new ranks
while($line = mysqli_fetch_array($a)){
if ($rank != $line["rank"]) { //if old rank is different we will hit db with new value
echo "updating id ".$line["id"]." from rank ".$line["rank"]." to rank ".$rank." <br>";
if(!mysqli_query($link,"UPDATE p1 SET rank = '".mysqli_real_escape_string($link,$rank)."' WHERE id ='".mysqli_real_escape_string($link,$line["id"])."'")) {
echo "Error updating Rank".mysqli_error($link);
}
}else { //if its the same we just leave the message for now
echo "ignoring id ".$line["id"]." previous rank ".$line["rank"]." , new rank ".$rank." <br>";
}
$rank++; // next user so lets increment the counter
}
?>
Recently went through same kind of issue and found a simple solution like below after struggling a lot. I would like to clear it out that, it depends on your input and expected result as well which you didn't mention in your post.
if (preg_match('/"'.<value>.'"/i' , json_encode(<your array>))) {
echo "Match";
} else {
echo "Doesn't match";
}
Please replace values accordingly when trying! Thanks for reading it.
The following answer code takes all points, and relevant ids and sets high to low ranks against high to low points respectively. However, it does not assign same rank for same points holder id as it keeps rolling with Rank+1 until end. That could be done, but isn't presently required.
<?php
require_once $_SERVER['DOCUMENT_ROOT'].'/includes/db.inc.php'; //connection to the DB
$a1= mysqli_query($link, "SELECT id, points FROM p1 ORDER BY points DESC"); //Selecting High to low all points
if(!$a1){
echo mysqli_error($link);
}
while($po = mysqli_fetch_array($a1)) {
$rose[] = $po;
}
$rank=0;//set rank 0
foreach($rose as $ro) { //splitting each row of array with unlimited rows
$points=$ro['points'];
$id=$ro['id'];
$rank++; //adding 1 each time foreach loops repeats itself until no row left
$update = mysqli_query($link,"UPDATE player1 SET rank = '$rank' WHERE points = '$points' AND id ='$id'"); //sending update command
if(!$update) { //echoing out what the hell this code is f******
echo "Error updating Rank".mysqli_error($link);
} else {
echo "Succuessul for where id = '$id' and points = '$points' set rank = '$rank'<br/>";
}
}
?>
This question already has answers here:
Rank function in MySQL
(13 answers)
Closed 8 years ago.
I have a text based mafia game and I am selected some GameRecords. The game records are all defined in the "users" table. For this example I am using "totalcrimes". I need to select all the rows from the users table and order it by totalcrimes and then find out which row each specific user is that is viewing the page.
If I was the user that was "ranked" 30th it would echo "30". The code I use to find the top 5 is here however I need to expand on it:
<?php
$i = 0;
$FindCrimes = mysql_query("SELECT * FROM players WHERE status='Alive' AND robot = 0 ORDER BY `totalcrimes` DESC LIMIT 5");
while($Row = mysql_fetch_assoc($FindCrimes)){
$Username = $Row['playername'];
$TotalCrimes = number_format($Row['totalcrimes']);
$i++;
echo "
<tr>
<td bgcolor='#111111' width='5%'>$i</td>
<td bgcolor='#111111' width='50%'><a href='viewplayer?playerid=$Username'>$Username</a></td>
<td bgcolor='#333333' width='45%'>$TotalCrimes</a></td></td>
</tr>
";
}
?>
I am going to assume that you already have a variable set to hold the current users ID number and total crimes, so in this case I will use $user as my variable.
Change yours to fit.
Now, I see 2 instances in which you could mean as your post wasn't very specific, so I will address both.
To show the number at the top of the page, you would use something like;
<?php
$sql = "SELECT * FROM `players` WHERE `totalcrimes` > '{$user['totalcrimes']}'";
$run = mysql_query($sql);
$rank = mysql_num_rows($run) + 1;
echo 'Your rank: ' . $rank;
Other than that, I see it's possibly being used to highlight your row, so something like this would suffice;
<?php
$i = 0;
$FindCrimes = mysql_query("SELECT * FROM players WHERE status='Alive' AND robot = 0 ORDER BY `totalcrimes` DESC LIMIT 5");
while($Row = mysql_fetch_assoc($FindCrimes))
{
$Username = $Row['playername'];
$TotalCrimes = number_format($Row['totalcrimes']);
$i++;
$primary = '#111111';
$secondary = '#333333';
if ($Row['id'] == $user['id'])
{
$primary = '#222222';
$secondary = '#444444';
}
echo "<tr>
<td bgcolor='$primary' width='5%'>$i</td>
<td bgcolor='$primary' width='50%'><a href='viewplayer?playerid=$Username'>$Username</a></td>
<td bgcolor='$secondary' width='45%'>$TotalCrimes</a></td></td>
</tr>";
}
If neither of those give your requirements, please comment and I'll edit to suit.
edit: I've worked on games for a few years - care to share the link to yours?
This can do the trick
SELECT COUNT(*)+1 as rank
FROM users
WHERE totalcrimes > (SELECT totalcrimes
FROM users
WHERE user_id='12345' AND status='Alive' AND robot='0');
So it counts all rows with greater totalcrimes than selected user (in this example I have used user_id column and some id 12345), than adds 1 on that sum and returns as rank value.
Course, modify WHERE clause inside the brackets to make it work for you.
I assumed that table name is users and user's id is integer user_id.
Test preview (Navicat Premium):
What this query does? It returns number of selected rows + 1 as rank column, from the table users where totalcrimes is greater than totalcrimes of some user. That user's totalcrimes is selected by another query (by its user_id). If you have multiple users with same totalcrimes value, this query will return same rank for all of them.
I know this is probably really simple but I have tried to find some similar examples and failed.
The problem is that I would like to list 8 random images from a gallery in a database, sorted by added date. And I have managed to do this, but only with several iterating query's that becomes really slow. So if someone would be so kind to teach me about combining them for faster speed, I guess UNION is the way to go? Here is my working (but slooow code)
<?php
$latestPictures = mysql_query("SELECT pictureID, addedDate FROM picture ORDER BY addedDate DESC LIMIT 8");
$latestConcerts = mysql_query("SELECT concertID, addedDate FROM concert WHERE pictureID is null ORDER BY addedDate DESC LIMIT 8");
// Add concerts and pictures to array
while($curFestival = mysql_fetch_object($latestPictures))
{
$array[$curFestival->addedDate] = "p" . $curFestival->pictureID;
}
while($curConcert = mysql_fetch_object($latestConcerts))
{
$array[$curConcert->addedDate] = "c" . $curConcert->concertID;
}
// Order array by key
krsort($array);
$latestArray = array_slice($array, 0, 8);
foreach($latestArray as $key => $value) {
$type = substr($value, 0, 1);
$ID = substr($value, 1);
// If type == picture
if($type == 'p')
{
$picturesPicturesID = mysql_query("SELECT concertID, name FROM photo WHERE concertID IN(SELECT concertID FROM concert WHERE pictureID = $ID) ORDER BY photoID");
// Get random picture
$curRandomPicture = rand(0, (mysql_num_rows($picturesPicturesID) - 1));
$curPictureConcertID = mysql_result($picturesPicturesID, $curRandomPicture, "concertID");
$curPictureName = mysql_result($picturesPicturesID, $curRandomPicture, "name");
$curPicture = mysql_fetch_object(mysql_query("SELECT c.URL, p.name FROM concert c, picture p WHERE p.pictureID = c.pictureID AND c.concertID = $curPictureConcertID"));
echo "Some image";
}
// If type == concert
if($type == 'c')
{
$concertPicturesID = mysql_query("SELECT concertID, name FROM photo WHERE concertID = $ID ORDER BY photoID");
// Get random picture
$curRandomPicture = rand(0, (mysql_num_rows($concertPicturesID) - 1));
$curPictureConcertID = mysql_result($concertPicturesID, $curRandomPicture, "concertID");
$curPictureName = mysql_result($concertPicturesID, $curRandomPicture, "name");
$curPicture = mysql_fetch_object(mysql_query("SELECT URL, name FROM concert WHERE concertID = $curPictureConcertID"));
echo "Some image";
}
}
?>
I realized that I forgot to include the tables, here they are:
TABLE OF photo:
PKEY: photoID
FKEY: concertID
name
TABLE OF concert:
PKEY: concertID
FKEY: pictureID
name
URL
addedDate
TABLE OF picture
PKEY: pictureID
name
date
So every post is part of TABLE photo AND concert, but only some is part of picture witch is only used sometimes to group differens albums together. When they are grouped together I whant a random name post from that grouping ID (picture) and if they are by them self a random name post from there (concert).
Accckkk! (In the infamous words of Bill the Cat.)
It's hard to figure out what result set your code really wants from the database.
This query isn't the most efficient, but it will return 8 random rows from the photos table, with those rows ordered by addedDate:
SELECT r.*, c.*
FROM (SELECT p.*
FROM photo p
WHERE p.concertid IS NOT NULL
ORDER BY RAND()
LIMIT 0,8
) r
JOIN concert c
ON c.concertid = p.concertid
ORDER BY r.addedDate ASC
If you have a really large photo table, this is going to be slow, because that RAND() function has to get called for every single row in the table, and MYSQL has to produce a temporary result set (a copy of the table) and then sort it on that derived column.
(NOTE: I'm assuming here that it's the photo table that you want to return "random" rows from, and I'm assuming that concertid is the primary key on the concert table, and a foreign key from the photo table. It's apparent that you have three tables... concert, picture and photo, but it's not clear which columns are the primary keys and which columns are the foreign keys, so it's likely I have it wrong.)
(NOTE: replace the p.* and c.* with a list of expressions you actually want to return.)
There are more efficient approaches to returning a single random row. In your case, you want exactly eight rows, and you presumably don't want to return a duplicate.
how can i check current number in mysql where....
my query is
$aid = 16;
$get_prev_photo = mysql_query("SELECT * FROM photos WHERE album_id='$aid' AND pic_id<'$picid' ORDER BY pic_id LIMIT 1");
$get_next_photo = mysql_query("SELECT * FROM photos WHERE album_id='$aid' AND pic_id>'$picid' ORDER BY pic_id LIMIT 1");
while i am getting current photo with following query
$photo = mysql_query("SELECT * FROM photos WHERE pic_id='$picid' LIMIT 1");
and getting total photos in album with following query
$photos = mysql_query("SELECT * FROM photos WHERE album_id='$aid'");
$total_photos = mysql_num_rows($photos);
now i want to check where i am and show it as Showing 1 of 20, showing 6 of 20 and so on...
now i want to check where i am actually...
i think you are referring to pagination, which can be achieved using LIMIT and OFFSET sql
decide the number of results you want per page, then select that many
create links like:
View the next 10
and dynamically change those every time
queries look ~like~
$offset=$_GET['view'];
SELECT * FROM table WHERE `condition`=true LIMIT 5 OFFSET $offset
this translates roughly as
select 5 from the table, starting at the 10th record
This is bad:
$photos = mysql_query("SELECT * FROM photos WHERE album_id='$aid'");
Because it grabs all the fields for the entire album of photos when all you really want is the count. Instead, get the total number of photos in the album like this:
$result = mysql_query("SELECT count(1) as total_photos FROM photos
WHERE album_id='$aid'");
if ($result === false) {
print mysql_error();
exit(1);
}
$row = mysql_fetch_object($result);
$total_photos = $row->total_photos;
mysql_free_result($result);
Now you have the count of the total number of photos in the album so that you can set up paging. Let's say as an example that the limit is set to 20 photos per page. So that means that you can list photos 1 - 20, 21 - 40, etc. Create a $page variable (from user input, default 1) that represents the page number you are on and $limit and $offset variables to plug into your query.
$limit = 20;
$page = $_POST['page'] || 1; // <-- or however you get user input
$offset = $limit * ($page - 1);
I'll leave the part where you code the list of pages up to you. Next query for the photos based on the variables you created.
$result = mysql_query("SELECT * FROM photos WHERE album_id='$aid'
ORDER BY pic_id LIMIT $limit OFFSET $offset");
if ($result === false) {
print mysql_error();
exit(1);
}
$photo_num = $offset;
while ($row = mysql_fetch_object($result)) {
$photo_num++;
$pic_id = $row->pic_id;
// get the rest of the variables and do stuff here
// like print the photo number for example
print "Showing photo $photo_num of $total_photos\n";
}
mysql_free_result($result);
I'll leave better error handing, doing something with the data, and the rest of the details up to you. But that is the basics. Also I did not check my code for errors so there might be some syntax problems above. To make a single photo per page just make $limit = 1.