Urgent.News

What's breaking now, across thousands of outlets.

Tech

Your SQL Pagination Can Repeat Rows. A Cursor Fixes Only Part of It.

Page one looks right. You click Load more , and the last item appears again. Someone deletes a record, and now an item disappears between pages instead. This can happen with a perfectly valid ORDER BY . The problem is that OFFSET 20 skips twenty rows in the result as it exists now , rather than continuing after the twenty rows you already saw. For a changing feed, keyset pagination gives you a…

When you paginate an SQL result set using OFFSET and LIMIT, you may encounter an issue where rows are repeated or skipped. This occurs because OFFSET skips a certain number of rows from the beginning, not from where you left off. For example, if you have a feed sorted by newest first and you request the second page (OFFSET 2) with a page size of 2, you might see the same row twice if a new row is inserted between your first and second pages.

Deleting a row can also cause gaps in the pagination results. A cursor-based pagination can help fix this issue, but it still doesn't guarantee that you get a snapshot of the data as it existed at a specific point in time. To demonstrate both the problem and the solution, consider a simple SQLite database with six rows. When you request the first page (OFFSET 0), you get IDs 6 and 5.

If you add a new row with ID 7, the next page (OFFSET 2) will return ID 5 again because the order has changed. If you delete the row with ID 6, the second page will skip ID 4 entirely. To solve this, you can use keyset pagination, also known as cursor-based pagination. This method keeps track of the last row's sort values and uses them to fetch the next set of rows.

For instance, after fetching the first page, you would remember the timestamp and ID of the last row (400, 5). The next page would then be fetched using a WHERE clause that checks for rows with a created_at value less than 400 and an id value less than 5. This ensures that you get the correct set of rows, even if new rows are inserted or existing rows are deleted.

This solution works with SQLite, which supports row-value comparisons. However, it's important to note that this approach does not guarantee a snapshot of the data at a specific moment in time. It only ensures that you get the correct rows based on the current state of the database.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

Step-by-Step: A Travel Agent That Can Actually Book

Most travel agent tutorials end at "the model suggested a hotel". That is the easy 20%. The other 80% is making the suggestion real: a hotel that exists, a price that is current, and a link a user can…

  • Travel agent tutorial breaks down booking process into eight steps
  • First step involves deciding user involvement level with redirect model
  • Technical setup includes server communication with booking provider API

Day 3: Connecting an interface with Wireshark

Welcome back to another day where we did not hit 167 lloc but we came close. Regardless of the lines of code today (I did not check what I started at today) I did want to share a pretty cool…

Dev News Digest: 5 Nov 2026, 06:00

A quick roundup of developer news since the last digest. Security Mobile phones infected via iOS and Android flaws : Attackers chained vulnerabilities in both major mobile platforms to compromise…

  • Attackers exploit iOS, Android vulnerabilities to compromise devices
  • DreamHost hosting breach exposes customer files, inboxes
  • White House network uses residential proxy traffic

How I Check a Download Is a Real MP4, Not an HTML Error Page Wearing a .mp4 Name

A download link can lie. I learned that the hard way while building ramrom.io, my little video downloader. A provider would return a 200 status, a filename ending in .mp4, and a body that was actually…

  • Verify Content-Type header as a hint, not sole confirmation
  • Scan initial bytes for "ftyp" to confirm MP4 format
  • Check file size against Content-Length header for sanity

More from Thursday 5 November →