Search code examples
mysqlordinal

MySQL Create Ordinal


I'm trying to create a temp table or view that I can use for charting league members changing handicaps over the season. This requires creating a pivot table.

Even before that, however, I need to create an ordinal column to represent the nth match the person played that season. I can't use date_played since players can play on all different dates, and I'd like each player's 2nd match to line up vertically, and their third to do so as well, etc.

I used code from the answer to this question which seemed like it should work. Here's a copy of the relevant section:

SELECT books.*, 
if( @libId = libraryId, 
    @var_record := @var_record + 1, 
    if(@var_record := 1 and @libId := libraryId, @var_record, @var_record)
) AS Ordinal 
FROM books
JOIN (SELECT @var_record := 0, @libId := 0) tmp
ORDER BY libraryId;

`lwljhb_lwl_matches`        # One record for each match played
id
date_played
other fields about the match

id    date_played
1     2017-08-23
2     2017-08-29
3     2017-09-26
4     2017-08-24
5     2017-09-02
6     2017-09-21
7     2017-08-24
8     2017-08-31
9     2017-09-05
10    2017-09-15
11    2017-09-17
`lwljhb_users`
id
display_name

id    display_name
1     Alan
2     Bill
3     Dave


`lwljhb_lwl_players`  # One record per player per match
id
match_id              # Foreign key to matches.id
player_id             # Foreign key to users.id
end_hcp
other fields about the player's performance in the linked match

id   match_id  player_id  end_hcp
1    1         1          720
2    2         1          692
3    3         1          694
4    4         2          865
5    5         2          868
6    6         2          842
7    7         3          363
8    8         3          339
9    9         3          332
10   10        3          348
11   11        3          374

Normally there would be two records in PLAYERS for each MATCH record, but I didn't add them here. The fact that the id and match_id are the same in every record of PLAYERS is artificial because this isn't real data.

Before I used this snippet, my code looked like this:

SELECT u.display_name,
   m.date_played,
   p.end_hcp 
FROM `lwljhb_lwl_matches` AS m
INNER JOIN `lwljhb_lwl_players` AS p
INNER JOIN `lwljhb_users` AS u
ON    m.id = p.match_id AND
      p.player_id = u.id
WHERE league_seasons_id = 12 AND
      playoff_round = 0
ORDER BY u.display_name, m.date_played

and generated data that looks like this:

display_name  date_played  end_hcp
Alan          2017-08-23   720
Alan          2017-08-29   692
Alan          2017-09-26   694
Bill          2017-08-24   865
Bill          2017-09-02   868
Bill          2017-09-21   842 
Dave          2017-08-24   363
Dave          2017-08-31   339
Dave          2017-09-05   332
Dave          2017-09-15   348
Dave          2017-09-17   374 

At any time during the season there will be different numbers of matches played by each of the players, but by the end of the season, they will have all played the same number of matches.

I tried to incorporate Alin Stoian's code into mine like so, changing a variable name and field names as I thought appropriate.

SET @var_record = 1;
SELECT u.display_name,
   m.date_played,
   p.end_hcp, 
    if( @player = u.display_name, 
    @var_record := @var_record + 1, 
        if(@var_record := 1 and @player := u.display_name, @var_record, @var_record)
) AS Ordinal 
FROM `lwljhb_lwl_matches` AS m
INNER JOIN `lwljhb_lwl_players` AS p
INNER JOIN `lwljhb_users` AS u
JOIN (SELECT @var_record := 0, @player := 0) tmp
ON    m.id = p.match_id AND
      p.player_id = u.id
WHERE league_seasons_id = 12 AND
      playoff_round = 0
ORDER BY u.display_name, m.date_played

I was hoping for a new column with the ordinals, but the new column is all zeros. Before I move on to trying the pivot table, I have to get these ordinals, so I hope someone here can show me my mistake.


Solution

  • OK, it turns out that I wasn't getting all 1s in my Ordinal column after all, just in the 1st 25 records. Since it was obviously wrong I didn't look further.

    The sample data I provided is in physical order as well as logical order, but MY ACTUAL data is not. That was the only difference I could think of, so I investigated further and found that in the 1st 1,000 records of output I got 7 records with 2 as the ordinal, not coincidentally where the m.ids were consecutive.

    I created a view to put the data in order like in the sample and the JOINed that to the rest of the tables but still got bad data for the Ordinal.

    When I swapped out the view for a temporary table it worked. It turns out that an ORDER BY in a view will be ignored if there's an ORDER by joining to it.

    Bill Karwin pointed this out to me in a different question (46892912).