How can I get the offset of a particular row in MySQL? - php

I'm trying to make an image database which does not keep a consistent record of ID's. For example it might go 1,2,6,7,12, but as you can see that is only 5 rows.
Inside the table I have fileid and filename. I created a PHP script to show me the image when I give the fileid. But if I give it the ID 5 which does not exist I get an error. That's fine as I want an error for that, but not for users who will browse through these images using forward and back buttons. The forward and back buttons would need to retrieve the true fileid which comes after the given ID. Hopefully that makes sense.
This is how I imagine the code to look like:
SELECT offset( WHERE fileid=4 )
That would give me the offset of the row where fileid is equal to 4. I think this is easy enough to understand. The reasons I need this are for creating the forward and back button. So I planned to add 1 or take 1 from the offset which gives me the new ID, and the new filename. That way when users browse it will skip the dead ID values automatically, but it will give an error when giving a false ID.

Going up:
SELECT * FROM table WHERE id > 'your_current_id' ORDER BY id LIMIT 1;
Going down:
SELECT * FROM table WHERE id < 'your_current_id' ORDER BY id DESC LIMIT 1;
ps: it is better to make LIMIT 2, so that you can see that you are at the first or at the last records in the database when only one record is returned.

If your results are ordered by x, ascending, the following will give you your current offeset in the table:
SELECT COUNT(*) FROM tablename WHERE x < x_of_your_current_item;
If you just want to SELECT the next or previous row, you can skip having to do two queries by just directly selecting one row:
SELECT * FROM tablename WHERE x > x_of_your_current_item ORDER BY x LIMIT 1;
will give you the next item (and similarly < and adding DESC to the order-by would give you previous).

You can use offset. Initially set offset as zero.
First time your query will be
SELECT * FROM TABLE order by table_id LIMIT 0,1
and next
SELECT * FROM TABLE order by table_id LIMIT 1,1
..
and so on
This way one will get records from the beginning till the end.
Now about back and forward buttons.
Back Button: First time or whenever offset is zero disable back button
Forward Button:
when you query for a current record you check for the next record too
i.e. after this query
SELECT * FROM TABLE order by table_id LIMIT 0,1 fire a query like this
SELECT * FROM TABLE order by table_id LIMIT current_offset+1,1 and check if the query produces any results if it produces a result then set a boolean say next = TRUE else next = FALSE;
Using this boolean enable or disable Forward button.
One more thing on click of back button send the offset as current_offset - 1 and for forward button current_offset + 1
I hope this helps. I just came across this and thought of this solution.

SELECT * FROM table WHERE ... ORDER BY id DESC LIMIT 50,10;
SELECT * FROM table WHERE ... ORDER BY id DESC LIMIT 60,10;
SELECT * FROM table WHERE ... ORDER BY id DESC LIMIT 70,10;

Related

Mariadb: Pagination using OFFSET and LIMIT is skipping one row

I have this MariaDB table:
id, name
The id column has these attributes: Primary, auto_increment, unique.
The table has 40,000 rows.
I'm using this PHP & MariaDB to load rows from this table.
This is the PHP code:
$get_rows = $conn->prepare("SELECT * FROM my_table where id> 0 ORDER BY id ASC LIMIT 30 OFFSET ?");
$get_rows->bind_param('i', $offset);
//etc.
The query returned everything correctly at the first time, but in the next query (made through AJAX), I received the next 30 rows with a gap of one row between the current result and the next one. And this goes on and on.
In the table, the row #1 had been deleted. So, I restored it, and now the query works. However, I will definitely have to delete more rows in the future. (I don't have the option of soft-deleting).
Is there any way I can keep deleting rows, and have these queries return correct results (without skipping any row)?
EDIT
Here's an example of the range of the ids in the first 2 queries:
Query 1:
247--276
Query 2:
278--307
(277 is missing)
NB I asked ChatGPT, but it couldn't help. :')
LIMIT and OFFSET query rows by position, not by value. So if you deleted a row in the first "page," then the position of all subsequent rows moves down by one.
One solution to ensure you don't miss a row is to define pages by the greatest id value on the preceding page, instead of by the offset.
$get_rows = $conn->prepare("
SELECT * FROM my_table where id> ?
ORDER BY id ASC LIMIT 30");
$get_rows->bind_param('i', $lastId);
This only works if your previous query viewed the preceding page, so you can save the value of the last id in that page.

How to get the data before the max id

I'm doing an info system that has announcements, so I wanted to get the data from announce table, first should be the one with max id of course since it is the latest announcement and here is my code for it:
SELECT image FROM announce where id=(SELECT max(id) FROM announce);
Now I wanted to get the data before the max id and I'm using this code here:
SELECT image FROM announce where id=(SELECT max(id)-1 FROM announce);
But it only works if there are no deleted rows,if there are some deleted rows it doesn't work like max id is 10 and the id's 9,8,7 are deleted. That means the present id's are: 1,2,3,4,5,6,10, how will I be able to get the data in the id 6,5,4,3,2,1?
If you ORDER the query by descending order (DESC), and have an OFFSET of one (OFFSET 1), you would get the second to last row. And offset of two would give the row before that, and so on. This also uses LIMIT 1, so we just get one row. LIMIT 1, 1 is the same as LIMIT 1 OFFSET 1.
SELECT image
FROM announce
ORDER BY id DESC
LIMIT 1, 1
MySQL on SELECT statements
You can just use one query with order by and limit instead of the two queries you use:
select image
from announce
order by id desc
limit 2
In case you want to query them separately, you can change limit 2 to limit 1, 1 for you second query to work as you wish.

MySQL - Fetching more records when ordered by integer

So, I'm writing an application to fetch records from the database, and my client has asked if I could sort the data by area. I've got the following query:
SELECT
*
FROM
customers
WHERE
account_type != 'x'
AND
account_type != 'tor'
ORDER BY
area ASC,
id ASC
LIMIT 30
The query returns 30 rows worth of data, all with an area value of 1.
I've got an AJAX query set up to fetch another 30 rows, however as I am ordering the data by area, I am unable to just fit a simple range string to my query as shown in the example below:
...
AND
id > 30
...
How would I write a query that would collect the next 30 records from the database?
Also, there is a record with an area value of 0. This is not shown as the first record in the list. Why is this? And how can I fix this?
Thanks
First, combine the where conditions into a single not in:
SELECT c.*
FROM customers c
WHERE account_type NOT IN ('x', 'tor')
ORDER BY area ASC, id ASC
LIMIT 30;
Then, for the next set, use:
SELECT . . .
OFFSET 30
LIMIT 30
This assumes that id is unique in the table. That is important, because that makes the sort stable.
Have a look at the the SELECT query documentation:
https://dev.mysql.com/doc/refman/5.7/en/select.html
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
In summary, just limit returns you x records. With the offset you can set a starting position, basically allows you for paging.
MySQL LIMIT take an optional parameter offset, so you could send in a parameter telling where to start when picking the 30 results you want
SELECT
*
FROM
customers
WHERE
account_type != 'x'
AND
account_type != 'tor'
ORDER BY
area ASC,
id ASC
LIMIT 30, 30
Should give you the next 30 rows starting from row 30

I need to select newest rows from a MySQL database, but verify that I am also returning a row with a given ID

I'm new to this, sorry if the title is confusing. I am building a simple php/mysql gallery of sorts. It will show the newest 25 entries when a user first goes to it, and also allows off-site linking to individual items in the list. If the URL contains an ID, javascript will scroll to it. But if there are 25+ entries, it's possible that my query will fetch the newest results, but omit an older entry that happens to be in the URL as an ID.
That means I need to do something like this...
SELECT * FROM `submissions` WHERE uid='$sid'
But after that has successfully found the submission with the special ID, also do
SELECT * FROM `submissions` ORDER BY `id` DESC LIMIT 0, 25`
So that I can populate the rest of the gallery.
I could query that database twice, but I am assuming there's some nifty way to avoid that. MySQL is also ordering everything (based on newest, views, and other vars) and using two queries would break that.
You could limit across a UNION like this:
(SELECT * FROM submissions WHERE uid = '$uid')
UNION
(SELECT * FROM submissions WHERE uid <> '$uid' ORDER BY `id` LIMIT 25)
LIMIT 25
Note LIMIT is listed twice as in the case that the first query returns a result, we would have 26 results in the union set. This will also place the "searched for" item first in the returned sort result set (with the other 24 results displayed in sort order). If this is not desirable, you could place an ORDER BY across the union, but your searched for result would be truncated if it happened to be the 26th record.
If you need 25 rows with all of them being sorted, my guess is that you would need to do the two query approach (limiting second query to either 24 or 25 records depending on whether the first query matched), and then simply insert the uid-matched result into the sorted records in the appropriate place before display.
I think the better solution is:
SELECT *
FROM `submissions`
order by (case when usid = $sid then 0 else 1 end),
id desc
limit 25
I don't think the union is guaranteed to return results in the order of the union (there is no guarantee in the standard or in other databases).

MySQL query for ID < variable

Hey, so what I am looking to accomplish is a MySQL query which grabs just the FIRST row whos ID is less than my current one. So basically a next button. Here is what I would like to modify:
$next = mysql_query("select * from posts where id<'$id'");
So how would I change this so it only selects the first value which is less than my ID value (which is the id of my current page)
Thanks! I will be doing this the reverse way for a previous button too.
select * from posts where id<'$id' order by id desc limit 1
This will get you the first id smaller than the provided parameter $id.
$next=mysql_query("SELECT * FROM posts WHERE id<'{$id}' ORDER BY id LIMIT 1");

Categories