Skip to content

Same record on different pages with PSQL and Order By Non-Unique column #266

@robbykrlos

Description

@robbykrlos

This is a bug.

Prerequisites

  • Are you running the latest version?
  • Are you reporting to the correct repository?
  • Did you check the documentation?
  • Did you perform a cursory search?

Description

This is a bug coming from this: https://stackoverflow.com/questions/13580826/postgresql-repeating-rows-from-limit-offset

Basically, whenever a table column is sorted by, using the table header sort action, if there are more rows with the same value on this column, and this set of data exceeds the page limit(ex Status column has Active value set for 100 users, but we only see 10 users per page - we will have 10 pages with Active users), it can be possible to see the same record from page one, on page two as well, because all rows that are returned have the same value for the non-unique column (ex: Status). In that case the database is free to return the rows in any order it wants.

On PostgreSQL I've tested and it is indeed generating a random order for the records with the same ordered-by-non-unique-column, and I can see record ID 197 on page 1,3,4...

On MySQL, I see that this is not happening, at least not on laravel-enso.com, on Company table, with Status column. In the link attached someone explained that maybe MySQL uses a cluster index ordering after the order set by query on Status, so that's why it might not behave the same.

With this context set, a possible solution for us, for PostgreSQL, is to to override the following class/method (and bind it):

vendor/laravel-enso/tables/src/Services/Data/Sorts/Sort.php

 public function handle(): void
    {
        $sort = new CustomSort($this->config, $this->query);

        if ($sort->applies()) {
            $sort->handle();
           //INJECT HERE AN ADDITIONAL ALWAYS-ON SORTING ON "ID" HAVING THE SAME TYPE (ASC/DESC) AS EXISTING SORT
        } elseif (! $this->query->getQuery()->orders) {
            $this->query->orderBy($this->config->template()->get('defaultSort'));
        }
    }

So that in the end, no matter what the user is sorting by (ex: Status), we will add an additional sorting step, in order to avoid the repeating record issue:

Before:

... ORDER BY Table.Status ...

After:

... ORDER BY Table.Status, Table.Id ...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions