SQLite: How to achive RANDOM ORDER and pageintation at the same time? - sql

I have a table of movies, I want to be able to query the database and get a randomized list of movies, but also I don't want it to return all movies available so I'm using LIMIT and OFFSET. The problem is when I'm doing something like this:
SELECT * FROM Movie ORDER BY RANDOM() LIMIT 50 OFFSET 0
and then when querying for the next page with LIMIT 50 OFFSET 50 the RANDOM seed changes and so it's possible for rows from the first page to be included in the second page, which is not the desired behavior.
How can I achieve a random order and preserve it through the pages? As far as I know SQLite doesn't support custom seed for it's RANDOM function.
Thank you!

You cant preserve the random values. You have to add another field name to your table to keep the random order
UPDATE movie
SET randomOrder = Random();
Then you can retrive the pages
SELECT *
FROM Movie
ORDER BY randomOrder
LIMIT 50 OFFSET 0

Related

Dealing with value based pagination given a number of a page

When using value based pagination
select * from articles
where id > #start_value
limit #page_size
how can I calculate #start_value given only page number?
Namely: say, I had a website and html page with a list of articles that I needed to paginate. But even to render the very 1st page, I'd need to calculate #start_value somehow. The input from a user would be a number of a page which he clicked; for the very first page it'd be 1 - by default.
given that 1, how would I calcualate #start_value?
or given any random page, still how would I calcualate #start_value?
Note that the values of the column id of a table aren't necessarily sequential, even if id is autoincremented.
First off, pagination without any sorting is not ideal. You can't guarantee how SQL will sort your results without including and order by clause.
You will also need to know the page size to calculate your start value, but given #page_num, and #page_size: #start_value is calculated by #start_value = #page_num * #page_size;.
Here it is without the where clause and with limit/offset instead
select *
from articles
order by id
limit #page_size
offset (#page_size * #page_num)
You don't need the "where id > ..." part. The right way of achieving this is using limit #page_size offset #offset construct. This way you don't have to worry about the gaps. To calculate the offset based on page number, you just have to multiply page_size * page_number. Another important thing is that you should order your registers if you want to have the same result always. If you don't trust the IDs, you can order by date or another field. So:
select * from articles
order by date
limit #page_size
offset (#page_size * (#page_num-1))
Note: I used (#page_num-1) to start with a 0 offset for page 1.

How can I get a specific chunk of results?

Is it possible to retrieve a specific range of results? I know how to do TOP x but the result I will retrieve is WAY too big and will time out. I was hoping to be able to pick say the first 10,000 results then the next 10,000 and so on. Is this possible?
WITH Q AS (
SELECT ROW_NUMBER() OVER (ORDER BY ...some column) AS N, ...other columns
FROM ...some table
) SELECT * FROM Q WHERE N BETWEEN 1 AND 10000;
Read more about ROW_NUMBER() here: http://msdn.microsoft.com/en-us/library/ms186734.aspx
Practically all SQL DB implementations have a way of specifying the starting row to return, as well as the number of rows.
For example, in both mysql and postgres it looks like:
SELECT ...
ORDER BY something -- not required, but highly recommended
LIMIT 100 -- only get 100 rows
OFFSET 500; -- start at row 500
Note that normally you would include an ORDER BY to make sure your chunks are consistent
MS SQL Server (being a "pretend" DB) don't support OFFSET directly, but it can be coded using ROW_NUMBER() - see this SO post for more detail.

Displaying data in grid view page by page

I have more than 30,000 rows in a table. It takes a lot of time to load all the data in the gridview. So I want to display 100 rows at a time. When I click next page button, another 100 rows should be displayed. When I click previous page button, previous 100 rows should be displayed. If I type page 5 in a text box, then I want to jump over to the 5th lot of rows.
I also want to display how many pages there will be. Can we implement this concept in vb.net [winform] gridview. I am using database PostgreSQL.
Can anybody give me a hint or some concept?
Look at OFFSET and LIMIT in PostgreSQL.
Your query for the 5th page could look like this:
SELECT *
FROM tbl
ORDER BY id
OFFSET 400
LIMIT 100;
id is the primary key in my example, therefore an index is in place automatically.
If you access the table a lot in this fashion, performance may profit from using CLUSTER.
Total number of pages:
SELECT ceil(1235::real / 100)::int
FROM tbl;
If you wanted the number rounded down, just simplify to:
SELECT 1235 / 100
FROM tbl;
With both numbers being integer the result will be an integer type and fractional digits truncated automatically. But I think you need to round up here.

sql direct way to get number of rows in table

Hi again people of stackoverflow.
I have a routine that has a step that I find unnecessary
lets say you want to get all the images from a gallery, and limit a certain number of images per page.
$db = PDO object
$start = (pagenum x images per page)
$limit = (images per page)
$itemsdata = $db->query("SELECT id,name FROM gallery LIMIT $start,$limit")->fetchAll();
$numitems = $db->query("SELECT id FROM gallery")->rowCount();
$imgsdata is a array of all the images in a gallery for example.
$numimgs is the number of images that the gallery has.
you would need $imgsdata to do a foreach loop on each image in the array, while
$numimgs is needed to generate the page numbering (e.g. << 1 2 3 4 >>)
my grudge is with $db->query("SELECT id FROM gallery")->rowCount();
It feels completely like some sort of cheat, isn't there a direct way to get the number of rows in a table, something like SELECT gallery.Rows?
p.s. currently I'm using SQLite, but I'd need it for MySQL and PostgreSQL as well.
This will tell you the number of rows:
SELECT COUNT(*) FROM gallery
A simple count() aggregate function will return the number of rows quickly
Select count(*) from table
select count(*) from gallery
Me too!
SELECT COUNT(*) FROM gallery
Yes, this should work the same just fine in MySQL, SQLite, and PostgreSQL.

Paging in SQL with LIMIT/OFFSET sometimes results in duplicates on different pages

I'm developing an online gallery with voting and have a separate table for pictures and votes (for every vote I'm storing the ID of the picture and the ID of the voter). The tables related like this: PICTURE <--(1:n, using VOTE.picture_id)-- VOTE. I would like to query the pictures table and sort the output by votes number. This is what I do:
SELECT
picture.votes_number,
picture.creation_date,
picture.author_id,
picture.author_nickname,
picture.id,
picture.url,
picture.name,
picture.width,
picture.height,
coalesce(anon_1."totalVotes", 0)
FROM picture
LEFT OUTER JOIN
(SELECT
vote.picture_id as pid,
count(*) AS "totalVotes"
FROM vote
WHERE vote.device_id = <this is the query parameter> GROUP BY pid) AS anon_1
ON picture.id = anon_1.pid
ORDER BY picture.votes_number DESC
LIMIT 10
OFFSET 0
OFFSET is different for different pages, of course.
However, there are pictures with the same ID that are displayed on the different pages. I guess the reason is the sorting, but can't construct any better query, which will not allow duplicates. Could anybody give me a hint?
Thanks in advance!
Do you execute one query per page to display? If yes, I suspect that the database doesn't guarantee a consitent order for items with the same number of votes. So first query may return { item 1, item 2 } and a 2nd query may return { item 2, item 1} if both items have same number of votes. If the items are actually items 10 and 11, then the same item may appear on page 1 and then on page 2.
I had such a problem once. If that's also your case, append an extra clause to the order by to ensure a consistent ordering of items with same vote number, e.g.:
ORDER BY picture.vote, picture.ID
The simples explanation is that you had some data added or some votes occured when you was looking at different pages.
I am sure if you would sorte by ID or creation_date this issue would go away.
I.e. there is no issue with your code
in my case this problem was due to the Null value in the Order By clause, i solved this by adding another Unique ID field in Order By Clause along with other field.