Laravel Eloquent Union query

2020-02-14 03:00发布

问题:

So I have the following query:

$a = Model::where('code', '=', $code)
    ->where('col_a', '=' , 1)
    ->orderBy(DB::raw('FIELD(layout, "normal", "split", "flip", "double-faced", "") ASC, layout'))

$b = Model::where('code', '=', $code)
    ->where('col_b', '=' , 1)
    ->orderBy(DB::raw('FIELD(layout, "normal", "split", "flip", "double-faced", "") ASC, layout'))

$a->union($b)->get();

No sorting is happening when I 'orderBy()' first and then union.

When I do query '$a' or '$b' individually the 'orderBy()' works fine.

When I do it in the following way 'orderBy()' happens as a whole.

$a->union($b)
    ->orderBy(DB::raw('FIELD(layout, "normal", "split", "flip", "double-faced", "") ASC, layout'))
    ->get();

How can I make it so the 'orderBy()' applies for each individually and then union the results back? It seems like it should work.

EDIT: If anyone can provide a way to do this, even if it's normal MySQL, I will choose yours as the answer as I think there may be a bug with Eloquent.

回答1:

The "merge" function in Laravel collection might be able to help you.
The big differnt is that I close off the query with a ->get() in advance, and I use merge() instead of union()

$a = Model::where('code', '=', $code)
->where('col_a', '=' , 1)
->orderBy(DB::raw('FIELD(layout, "normal", "split", "flip", "double-faced", "") ASC, layout'))->get();

$b = Model::where('code', '=', $code)
->where('col_b', '=' , 1)
->orderBy(DB::raw('FIELD(layout, "normal", "split", "flip", "double-faced", "") ASC, layout'))->get();

$result = $a->merge($b);

Note: I don't have your data so I can't proof it work, but it least it work on my data so should worth your try



回答2:

Just try to apply orderBy() after union()

Try this

$a->union($b)->orderBy(DB::raw('FIELD(layout, "normal", "split", "flip", "double-faced", "") ASC, layout'))->get();

EDIT

Researched about and found and prepared eloquent query just try this

$modelA = Model::where('code', '=', $code)
    ->where('col_a', '=' , 1)
    ->orderBy(DB::raw('FIELD(layout, "normal", "split", "flip", "double-faced", "") ASC, layout'))

$modelB = Model::where('code', '=', $code)
    ->where('col_b', '=' , 1)
    ->orderBy(DB::raw('FIELD(layout, "normal", "split", "flip", "double-faced", "") ASC, layout'))

$a = DB::table(DB::raw("({$modelA->toSql()}) as a"))
    ->mergeBindings($modelA->getQuery())
    ->selectRaw("a.*");

$b = DB::table(DB::raw("({$modelB->toSql()}) as b"))
    ->mergeBindings($modelB->getQuery())
    ->selectRaw("b.*");

$a->union($b)->get();


回答3:

Try the following:

$a = Model::where('code', '=', $code)
->where('col_a', '=' , 1);

$b = Model::where('code', '=', $code)->where('col_b', '=' , 1)
->union($a)
->get();

$result = $b;


回答4:

Refer MySql Documentation

Use of ORDER BY for individual SELECT statements implies nothing about the order in which the rows appear in the final result because UNION by default produces an unordered set of rows. Therefore, the use of ORDER BY in this context is typically in conjunction with LIMIT, so that it is used to determine the subset of the selected rows to retrieve for the SELECT, even though it does not necessarily affect the order of those rows in the final UNION result. If ORDER BY appears without LIMIT in a SELECT, it is optimized away because it will have no effect anyway.