Been waiting for help 3 years. Is it too complicated, or can't be done? Anyone have any ideas? There must be a way to do this. Thanks
Number the rows in a subquery using Query Builder (or Eloquent)?
I'm trying to line up two sets of players (users), who have drawn different colors, opposite each other on the same table row of the view. The players who will occupy the same row have no common field value to join them except their row number from their subqueries. I need to number the rows in the subqueries so the first player to draw green appears in the same row as the first to draw yellow, and so on. Each subquery joins the players table and the draws table, and the outer query joins the two subs using the player's row number from their subquery. The subquery row numbers don't need to be displayed, they're just for lining up the rows.
Tables:
players: id, name (simplified user);
draws: id, player_id, color
Desired result (greatly simplified):
Green |Row| Yellow
Name Draw Name Draw
Joe green 1 Ed yellow
Mary green 2 John yellow
Sam green 3 Clara yellow
I was able to produce that view last year experimenting with php and raw sql, before I even heard of Laravel (or tried OOP). Recently I recreated the desired result in Laravel by concatenating pure sql into "DB::select($query)" (shown below), but it won't let me paginate that (unless someone can show me how). So how can I do this with Query Builder or Eloquent? I've made many attempts with Query Builder (one below). But the row number attempts in the subqueries either cause errors or just don't work.
Errors
Mysql won't accept "DB::raw('(@rownum:=@rownum+1) AS RowNumY'))" coming from Query Builder as a member of the field list even tho it accepted it from "DB::select($query)" in the concatenated version. Or it rejects "(SELECT @rownum:=0) AS Outerrow_num" in the FROM clause. Or when it was accepted in the FROM clause, it overwrote the base table (draws), so that the fields from that table (draws.color) didn't exist.
Concatenated raw sql version (this works):
$query = 'select colorY, playerY, '; // outer query fields
$query .= '@rownum:= @rownum + 1 AS row_numOuter, '; // outer query row number
$query .= 'colorG, playerG '; // outer query fields
$query .= 'from (SELECT @rownum:=0) AS Outerrow_num, '; // set outer row number=0
$query .= '(select drawsG.color as colorG, '; // start green subquery field list
$query .= 'playersG.name as playerG, ';
$query .= '(@rownumG:=@rownumG + 1) AS RowNumG '; // green subquery row number
$query .= 'from (select @rownumG:=0) AS rownumG, '; // set green subquery row number=0
$query .= 'draws AS drawsG ';
$query .= 'inner join players as playersG '; // join draws w/ players – green
$query .= 'on playersG.id = drawsG.player_id ';
$query .= 'where color = "green") ';
$query .= 'as drawsGreen '; // green subquery alias
$query .= 'right join '; // join green and yellow subqueries (yellow on right-has more in my db)
$query .= '(select drawsY.color as colorY, '; // start yellow subquery field list
$query .= 'playersY.name as playerY, ';
$query .= '(@rownumY:=@rownumY + 1) AS RowNumY '; // yellow subquery row number
$query .= 'from (select @rownumY:=0) AS rownumY, '; // set yellow subquery row number=0
$query .= 'draws AS drawsY ';
$query .= 'inner join players as playersY '; // join draws w/ players - yellow
$query .= 'on playersY.id = drawsY.player_id ';
$query .= 'where color = "yellow") ';
$query .= 'as drawsYellow '; // yellow subquery alias
$query .= 'on RowNumG = RowNumY'; // ON clause for right join
$draws = DB::select($query);
return view('draws.index', compact(['draws']));
So here's my (latest?) attempt to do it via Query Builder:
$subQYellow = DB::table('draws AS drawsY') // yellow subquery, on draws table
->join('players AS playersY', 'playersY.id', '=', 'drawsY.player_id') // join to players table on id
->select('color AS colorY', 'playersY.name AS playerY', // yellow field list
DB::raw('(@rownum:=@rownum+1) AS RowNumY')) // set yellow subquery row number=0
->from(DB::raw('(select @rownum:=0) AS rownumY'), // from "list", yellow subquery row number
('draws AS drawsY')) // repeat draws table (??)
->where('color', 'yellow'); // color value filter
$subQGreen = DB::table('draws AS drawsG') // green subquery, on draws table
->join('players AS playersG', 'playersG.id', '=', 'drawsG.player_id') // join to players table on id
->select('color AS colorG', 'playersG.name AS playerG', // green field list
DB::raw('(@rownum:=@rownum+1) AS RowNumG')) // set yellow subquery row number=0
->from(DB::raw('(select @rownum:=0) AS rownumG'), // from "list", green subquery row number
('draws AS drawsG')) // repeat draws table (??)
->where('color', 'green'); // color value filter
$draws = DB::table($subgreen, 'drawsGrn') // QB on subgreen w/alias
->select('colorY AS colorYlw', 'playerY AS playerYlw', // outer query field list w/ aliases
'colorG AS colorGrn', 'playerG AS playerGrn') // more fields
->rightJoinSub($subyellow, 'drawsYlw', function ($join) { // joinSub on yellow with closure
$join->on('RowNumG', '=', 'RowNumY'); // outer query ON clause to join subs
})
->get();
Note: I had to repeat the draws table in FROM clause of each subquery because the row numbering code in the FROM clause seemed to overwrite it. If I put it in another ->from clause, the second FROM overwrites the first FROM. Catch 22. Note: I'm never sure when mysql needs aliases. Is there a rule? Any help? Thanks in advance.
Please or to participate in this conversation.