Reputation: 23
Let´s say I have two tables. The first table represents Accounts and the second table represents Characters. Tables are connected with "AccountId" column. According to o game, characters are connected to accounts and every account can contain 4 characters.
In my website I have two pages. The first page is called "Characterlist.php" and generates all characters in game with one specific Authority (Column in Accounts table) which would be equal to 0.
I'm using this query:
$query = "WITH
Acc AS
(SELECT AccountId, Authority
FROM Account
WHERE Authority = '0'),
Char AS
(SELECT Character.*
FROM Character, Acc
WHERE Character.AccountId = Acc.AccountId),
Res AS
(SELECT *,
ROW_NUMBER() OVER
(ORDER BY Reput DESC) AS row_number
FROM Char)
SELECT Res.Class,
Res.Name,
Res.Level,
Res.HeroLevel,
Res.Reput,
Res.row_number
FROM Res
WHERE Res.row_number >= '$charlistpagemin'
AND Res.row_number <= '$charlistpagemax'";
$charlistpagemin and $vharlistpagemax are php variables that I'm using to divide whole character list to several pages.
When I search characters of my testing account, their position according to their Reputation generated and ordered by row_number() is alright.
Then I have the second page userpanel.php which is shown only to signed users where they can see their game characters in another list.
I'm using almost the same query, just with different rules in the end.
$query =
"WITH
Acc AS
(SELECT AccountId,
Authority
FROM Account
WHERE Authority = '0'),
Char AS
(SELECT Character.*
FROM Character, Acc
WHERE Character.AccountId = Acc.AccountId),
Res AS
(SELECT *,
ROW_NUMBER()
OVER (ORDER BY Reput DESC) AS row_number FROM Char)
SELECT Res.AccountId,
Res.Class,
Res.Name,
Res.Level,
Res.HeroLevel,
Res.Reput,
Res.row_number
FROM Res
WHERE Res.AccountId = '" . $_SESSION["accountid"] . "'";
And there is the problem. Their position according to Reputation is different (bad) than in characterlist.php. Where is the problem?
Edit: The table "Account" looks like:
AccountId | Authority | ... |
The table "Character" looks like:
AccountId | Class | Name | Level | HeroLevel | Reput | ... |
My testing account has
AccountId: xxx | Authority: 0 | ... |
And has Characters
AccountId: XXX | Class: Dobrodruh | Name: Kryploij1 | Level: 15 | Herolevel: 0 | Reput: 0 | ... |
AccountId: XXX | Class: Dobrodruh | Name: Kryploid2 | Level: 15 | Herolevel: 0 | Reput: 0 | ... |
AccountId: XXX | Class: Dobrodruh | Name: Kryploij3 | Level: 15 | Herolevel: 0 | Reput: 0 | ... |
AccountId: XXX | Class: Dobrodruh | Name: Grakonecek<3 | Level: 15 | Herolevel: 0 | Reput: 0 | ... |
The expected result that is shown in characterlist.php is
Position: 139 | Class: Dobrodruh | Name: Kryploij1 | Level: 15 | Herolevel: 0 | Reput: 0 |
Position: 140 | Class: Dobrodruh | Name: Kryploid2 | Level: 15 | Herolevel: 0 | Reput: 0 |
Position: 141 | Class: Dobrodruh | Name: Kryploij3 | Level: 15 | Herolevel: 0 | Reput: 0 |
Position: 142 | Class: Dobrodruh | Name: Grakonecek<3 | Level: 15 | Herolevel: 0 | Reput: 0 |
But the bad result in userpanel.php is:
Position: 110 | Class: Dobrodruh | Name: Kryploij1 | Level: 15 | Herolevel: 0 | Reput: 0 |
Position: 111 | Class: Dobrodruh | Name: Kryploid2 | Level: 15 | Herolevel: 0 | Reput: 0 |
Position: 112 | Class: Dobrodruh | Name: Kryploij3 | Level: 15 | Herolevel: 0 | Reput: 0 |
Position: 113 | Class: Dobrodruh | Name: Grakonecek<3 | Level: 15 | Herolevel: 0 | Reput: 0 |
Simply, my problem is in changed positions in userpanel. True positions are shown in characterlist. To calculate position according to ordering data in tables by Reputation I'm using row_number() function as is shown in my queries.
Upvotes: 0
Views: 65
Reputation: 1269953
Your data has ties for reput
and your row_number()
expression is:
ROW_NUMBER() OVER (ORDER BY Reput DESC) AS row_number
Ordering in SQL is unstable. That means that rows with ties are in an arbitrary and indeterminate order -- and this order might change from one execution to the next.
Why is sorting unstable? Easy. SQL tables represent unordered sets, so there is no "underlying" ordering to define what happens in the case of ties.
The simple solution is to add another key. In your case, I think Name
might be sufficient:
ROW_NUMBER() OVER (ORDER BY Reput DESC, Name) AS row_number
Upvotes: 1
Reputation: 29629
This is really hard to answer without sample data and inputs, but I think it is because the two queries do different things.
The first query paginates through the results, and the pagination imposes the ordering - presumably, $charlistpagemin
and $charlistpagemax
are 0 and 10 when you first load the page, so you get the first ten results.
The second query has not ordering - it's just a list of results, in undefined order. If you add
order by Res.row_number desc
at the end of the query, it should work.
Upvotes: 0