Looping through MySQL Results - php

I'm not sure exactly how this is called but I'll try to describe as good as I can what I want to acheive.
So, first of all, there is a variable, called $id, which is actually $_GET['id']. Assuming the user is entering the following page by requesting: /page.php?id=6. Now what I need to do is to provide the information about the next 3 pages from database. Here is the database:
TABLE `pages`
id | page_name
______________________
1 | AAAAA
2 | BBBBB
3 | CCCCC
4 | DDDDD
5 | EEEEE
6 | FFFFF
7 | GGGGG
8 | HHHHH
9 | IIIII
So, while requesting the page with id 6, the following script returns the next 3 pages (7,8,9):
$res = mysql_query("SELECT * FROM `pages` WHERE `id`>'".intval($id)."' ORDER BY `id` DESC LIMIT 3");
while($arr = mysql_fetch_assoc($res))
{
print("Page ID: ".$arr['id']."; Page Name: ".$arr['page_name']."\n");
}
And here is the output:
Page ID: 7; Page Name: GGGGG
Page ID: 8; Page Name: HHHHH
Page ID: 9; Page Name: IIIII
And it works fine until the $id is greater then 6. When it is (/page.php?id={7/8/9}), the output doesn't show 3 pages any more, but 2 pages, 1 page and respectively no output when $id is 9.
So my question is: Is there a way to go back and start from the beginning when there are not enough results (less than 3) to display?
When accessing /page.php?id=8, the output should contain pages with id 9, 1 and 2.
When accessing /page.php?id=9, the output should contain pages with id 1, 2, 3.
When accessing /page.php?id=3, the output should contain pages with id 4, 5, 6 and so on.

(SELECT *, 0 AS custom_order FROM `pages` WHERE `id`>'".intval($id)."' ORDER BY `id` ASC LIMIT 3)
UNION ALL
(SELECT *, 1 AS custom_order FROM `pages` ORDER BY `id` ASC LIMIT 3)
ORDER BY custom_order, id ASC
LIMIT 3
This way you always get 3 pages. If not enough next pages, you will get up to 3 from the beginning.

You could modify the query to be something like:
select * from
(select *, id-$inval($id) as order_by
from pages were id > $inval($id) order by id asc limit 3
union
select *, id as order_by
from pages order by id asc limit 3 ) as pages
order by order_by asc

I would solve this way (one possible issue is that the resultset could contain at most 6 records instead of 3):
$res = mysql_query("(SELECT * FROM `pages` WHERE `id`>'".intval($id)."' ORDER BY `id` ASC LIMIT 3) UNION DISTINCT (SELECT * FROM `pages` WHERE id>0 ORDER BY id ASC LIMIT 3)");
$counter = 0;
while($arr = mysql_fetch_assoc($res) && $counter<3)
{
$counter++;
print("Page ID: ".$arr['id']."; Page Name: ".$arr['page_name']."\n");
}

Related

" People Who Liked this Also Liked " Query in Mysql PHP

Music table
id | title
1 Rap God
2 Blank Space
3 Bad Blood
4 Speedom
5 Hit 'em up
Like table
u_id | m_id
1 1
1 2
1 4
1 5
2 3
2 4
2 5
3 1
3 5
4 1
4 2
4 5
Now if someone visits music with m_id = 1
Then the output might be like
m_id
5
2
4
To explain this a bit...
As m_id = 1 is liked by users -> {1,3,4} which in turn likes ->{2,4,5} musics. Since m_id=5 is liked by max number of users its first followed by m_id = 2 and m_id = 4.
My Try
I queried the users who liked m_id = 1
SELECT u_id FROM likes WHERE m_id =1
Then i stored in in an array and selected each of their likes and
arranged them in desc order of count.
But it is a very slow and long process is there any way i can do this ?
p.s I have heard of Association Rules and Bayesian theorem can be user to achieve this. But can anyone help me out with an example ?
You can JOIN back on the Like table and do something like this.
SELECT also_like.m_id, COUNT(also_like.m_id)
FROM [like] AS did_like
JOIN [like] AS also_like ON
also_like.u_id = did_like.u_id
AND also_like.m_id != did_like.m_id
WHERE did_like.m_id = 1
GROUP BY also_like.m_id
ORDER BY COUNT(also_like.m_id)
Essentially you are getting a list of users who liked an item then getting a complete list of those user's likes excluding the item they just liked.
You can then add a HAVING clause or LIMIT to filter things down a bit more.
using a subquery ...
SELECT m_id, count(u_id) as Rank FROM `like`
WHERE u_id in
(
SELECT u_id
FROM `like`
WHERE m_id = 1
)
AND m_id <> 1
GROUP BY m_id
ORDER BY Rank DESC
and optionally
LIMIT 0, 10
or how many "alsolikes" you want to display

mysql - order by field not working properly

suppose I've a database , the table contains rows with ides from 1 to 20 .
i want to return 3 rows with id 3,4,1 first and then return the other rows . this is my code :
SELECT id
FROM prod
ORDER BY field( id, 3, 4, 1 )
LIMIT 20
this is the result of this code :
id
13
17
16
15
7
6
5
2
3
4
1
strangely the 3 rows that I need to come first are showing at the end ,
How can I bring these 3 rows to the top of the list ?
Thanks
You can use DESC:
SELECT id
FROM prod
ORDER BY field( id, 3, 4, 1 ) DESC
LIMIT 20
The issue is that MySQL puts NULL values first when you do an ascending order by.
If you actually want the rows in the order 3, 4, 1, then reverse them in the field statement:
SELECT id
FROM prod
ORDER BY field( id, 1, 4, 3 ) DESC
LIMIT 20
Or, if you wanted to be fancy:
ORDER BY - field( id, 3, 4, 1 ) DESC
The other way is to use case-when and giving each id an order value
select * from prod
order by
case
when id = 3 then 0
when id=4 then 1
when id=1 then 2
else 3
end,id
limit 20
;
Try with DESC
SELECT id
FROM prod
ORDER BY field( id, 3, 4, 1 ) DESC
LIMIT 20
It seems your id order is important. Reverse numbers to get correct result
SELECT id
FROM prod
ORDER BY field( id, 1, 4, 3 ) DESC
LIMIT 20
Not tested but you can try
SELECT id,
(
CASE
WHEN id = '3' THEN 0
WHEN id = '4' THEN 1
WHEN id = '1' THEN 2
END
) as rank
FROM prod
ORDER BY rank
LIMIT 20;

How to get the next row in sql

I have a table that is something like this
id | names | value
1 Vicky 43
2 Erica 23
3 Rueben 33
4 Bob 54
5 Chris 60
Then I set them in order according to their value. Now the table looks like this.
id | names | value
5 Chris 60
4 Bob 54
1 Vicky 43
3 Rueben 33
2 Erica 23
Now the starting point is id 5 which has a name of Chris and a value of 60. My goal is, to get the next row which has an id of 4 and name of Bob and a value of 54.
You just need to limit the resultset:
SELECT * from table
ORDER BY value DESC
LIMIT 1, 1
Output:
| ID | NAMES | VALUE |
|----|-------|-------|
| 4 | Bob | 54 |
Fiddle here.
The LIMIT basically works this way: the first number sets the starting point (being 0 the minimal value) and the second number the amount of items to fetch (in this case only one).
Edit:
A different way of understanding the question would be: Given a value for a particular field (EG: id field with value of 5)... what would be the previous record? As we have the id 4 in the data we should return that one.
That could be accomplished this way:
SELECT * from t
WHERE id < 5
ORDER BY id DESC
LIMIT 1
Fiddle here.
This way you can traverse the results in both orders (ASC and DESC) and also get both the next or previous (> or <) rows.
If your current ID is for example 4 then
Next:
select * from foo where id = (select min(id) from foo where id > 4)
previous:
select * from foo where id = (select max(id) from foo where id < 4)
sql server:
with temp as
(
SELECT ROW_NUMBER() OVER (ORDER BY value desc) AS ROWID, * FROM table_name
)
SELECT * from temp where ROWID=2
mysql:
SELECT * from table
ORDER BY value DESC
LIMIT 1, 1
I get the feeling that this is a PHP related question?
If that's so, then you can use PHP's mysql or mysqli_fetch functions to get what you want... along with a loop
This is your basic loop-through-a-mysql-query
$sql = mysql_query( "SELECT * from table ORDER BY value DESC" );
while ( $r = mysql_fetch_array( $sql ) ) {
echo $r['value'] . "<br />\n";
}
If you want to have them all at your disposal and be able to call either one of them at will, you will need to store the data in an accessible array, like so
$sql = mysql_query( "SELECT * from table ORDER BY value DESC" );
$theData = array();
while ( $r = mysql_fetch_array( $sql ) ) {
$theData[] = $r['value'];
}
Then, to access the SECOND value, use this
echo $theData[1];

MYSQL sorting and limit using a certain row and selecting previous and next rows

I have a simple table called users with the following data:
id | hops
1 | 3
2 | 1
3 | 5
4 | 2
5 | 4
6 | 5
I want to select the number of hops of any given id that I specify and also select the next and previous ids according to the number of hops sorted from highest to lowest.
To explain more I use the following query:
SELECT * FROM test WHERE id = 1
OR (id > 1 AND hops >= (SELECT hops FROM test WHERE id= 1) )
OR (id < 1 AND hops <= (SELECT hops FROM test WHERE id= 1) )
LIMIT 3
So in the above query I tried to get id=1, next id with the same or higher number of hops, and the previous id with the same or lower number of hops.
This is the result i get:
id | hops
1 | 3
3 | 5
5 | 4
As you can see it selected id=1 and two higher ids although I want only one higher id and one lower id. So, in this case the result should be like this instead:
id | hops
1 | 3
3 | 5
As there is no lower id than 1, so nothing lower to fit the criteria and selects only 1 higher id. The wrong result is because of using LIMIT 3 but I can't use a LIMIT for each condition. So don't know how to approach this at all.
Have another question, would using the sub-query
"SELECT hops FROM test WHERE id= 1"
slow down the server on a large scale?? I heard that it's not preferable to use sub-queries but have no other way to get this number except using a separate query.
Thanks
here you go, change the order by ID according to your liking...you didn't say if you wanted the closest number of hops or the closest ID, just one greater or lower
SELECT * FROM test
WHERE id IN (1,(
SELECT id FROM test WHERE id > 1 AND hops >= (
SELECT hops FROM test WHERE id = 1
) ORDER BY id LIMIT 1
), (
SELECT id FROM test WHERE id < 1 AND hops <= (
SELECT hops FROM test WHERE id = 1
) ORDER BY id DESC LIMIT 1
))
If I understand your question correctly, I believe the following will work.
-- Previous Rec
SELECT t2.*
FROM test as t1
JOIN test as t2 ON t2.hop <= t1.id
WHERE t1.id = 1
ORDER BY t2.id DESC
LIMIT 1
UNION ALL
-- Current Rec
SELECT *
FROM test as t
WHERE id = 1
UNION ALL
-- Following Rec
SELECT t2.*
FROM test as t1
JOIN test as t2 ON t2.id >= t1.hop
WHERE t1.id = 1
ORDER BY t2.id ASC
LIMIT 1

Order by ID if two users have same number of credits

:-)
I have this script, which find a users position taken from the number of credits.
It all works, but i have a little problem. If two users have the same credits, both of them will be on the same position.
Can I do, so if there are more users with same credits, then the system need to order by the users ID and out from that give them a position?
This is my code so far:
$sql = "SELECT COUNT(*) + 1 AS `number`
FROM `users`
WHERE `penge` >
(SELECT `penge` FROM `users`
WHERE `facebook_id` = ".$facebook_uid.")";
$query_rang = $this->db->query($sql);
So if i have this:
ID -------- Credits
1 -------- 100
2 -------- 100
3 -------- 120
Then the rank list should be like this:
Number 1 is user with ID 3
Number 2 is user with ID 1
Number 3 is user with ID 2
ORDER BY credits DESC, id ASC. This will sort by credits and break ties with the id.
UPDATE
I understand now that you want the ranking information for the user, not just to sort the users by credits and ids. This will give you the complete list of users and their rankings:
SELECT #rank:=#rank+1 AS rank, users.id, users.facebook_id FROM users, (SELECT #rank:=0) dummy ORDER BY penge DESC, id ASC
Getting the row number is the tricky bit solved by this blog post:
http://jimmod.com/blog/2008/09/displaying-row-number-rownum-in-mysql/
$sql = "SELECT COUNT(*) + 1 AS `number` FROM `users` WHERE `penge` > (SELECT `penge` FROM `users` WHERE `facebook_id` = ".$facebook_uid.") ORDER BY COUNT(*) + 1 desc, users.ID";
$query_rang = $this->db->query($sql);
Later EDIT:
I don't understand why you still have the same results....
I made a quick test. I have created a table:
Test: ID (Integer) and No (Integer)
I have inserted some values:
id no
1 1
1 1
1 1
2 1
3 1
4 1
4 1
5 1
Now, if I run:
SELECT
id, COUNT(*) + 1 AS `number`
FROM
test
GROUP BY
id
I get:
id number
1 4
2 2
3 2
4 3
5 2
But if I add ORDER BY:
SELECT
id, COUNT(*) + 1 AS `number`
FROM
test
GROUP BY
id
ORDER BY
count(*) desc, id
then I get:
id number
1 4
4 3
2 2
3 2
5 2

Categories