Ad

Condition OrWhere Using Laravel 6 Not Work

I have two tables, salaries and pointages, and a belongsTo/hasMany relationship between them. I want to select the sum of the sold and payer columns on condition of date and condition of salarie_id and chantier_id. I want to be optional, if I choose salarie_id or chantier_id, I want to give me either the pointages of salarie_id or chantier_id chosen or both. But in my case even when I chose salarie_id or chantier_id, it showed me all of the rows.

$dataP = DB::table('salaries')
         ->join('pointages','pointages.salarie_id','salaries.id')
          ->selectRaw('SUM(pointages.sold) as sold,salaries.nom,salaries.prenom,salaries.id,SUM(pointages.payer) as payer')
          ->whereRaw(DB::raw('YEAR(pointages.datep) = ' .$request->annee))
          ->whereRaw(DB::raw('MONTH(pointages.datep) = ' .$request->mois))
          ->whereRaw( DB::raw('DAY(pointages.datep)>0 AND DAY(pointages.datep)<16')) 
          ->Orwhere('pointages.salarie_id','=',$request->salarie_id)
          ->OrWhere('pointages.chantier_id','=',$request->chantier_id)
          ->groupBy('pointages.salarie_id')
          ->get();
          return response($dataP);
Ad

Answer

I suspect you aren't familiar with how where/whereRaw and orWhere/orWhereRaw work when combined.

Currently your WHERE clause looks like this:

YEAR(pointages.datep) = ? and MONTH(pointages.datep) = ? and DAY(pointages.datep)>0 AND DAY(pointages.datep)<16 or `pointages`.`salarie_id` = ? or `pointages`.`chantier_id` = ?

Note no parentheses, meaning either of the final conditions can override the earlier ones. You can easily determine what your query will look like by using the toSql() or dd() query builder methods.

My guess is that you're looking for a query like this?

SELECT SUM(pointages.sold) AS sold, SUM(pointages.payer) AS payer,
    salaries.nom, salaries.prenom, salaries.id
FROM salaries
LEFT JOIN pointages ON (pointages.salarie_id = salaries.id)
WHERE YEAR(pointages.datep) = ?
    AND MONTH(pointages.datep) = ?
    AND DAY(pointages.datep) > 0
    AND DAY(pointages.datep) < 16
    AND (
        pointages.salarie_id = ?
        OR pointages.chantier_id = ?
    )
GROUP BY pointages.salarie_id

So a couple of notes first: 1) don't ever put raw data into an SQL query like you're doing above. The whereRaw() method works with placeholders; use them. 2) Try to avoid using raw statements at all where possible. There are helper functions to do things like the date calculations you're doing. 3)Grouping your constraints is done by passing a closure to where()/orWhere(). 4) Performing comparisons against function results (like you're doing with your YEAR, MONTH, and DAY functions) is very inefficient; the column effectively becomes an unindexed text column.

The following code will produce a query equivalent to the above, but makes the checks from the request optional:

$dateStart = Carbon\Carbon::create($request->annee, $request->mois, 1, 0, 0, 0);
$dateEnd = $dateStart->addDays(15)->subSecond(1);

DB::table('salaries')
    ->leftJoin('pointages', 'pointages.salarie_id', 'salaries.id')
    ->select(['salaries.nom', 'salaries.prenom', 'salaries.id'])
    ->selectRaw('SUM(pointages.sold) AS sold')
    ->selectRaw('SUM(pointages.payer) AS payer')
    ->whereBetween('pointages.datep', [$dateStart, $dateEnd])
    ->where(function($q) use($request) {
        if ($request->has('salarie_id')) {
            $q->orWhere('pointages.salarie_id', $request->salarie_id);
        }
        if ($request->has('chantier_id')) {
            $q->orWhere('pointages.chantier_id', $request->chantier_id);
        }
    })
    ->groupBy('pointages.salarie_id')
    ->get();
Ad
source: stackoverflow.com
Ad