Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Inquisitive's avatar

Help required to minimize query duplication

Here, is the exact query,

SELECT    Ifnull(Round(Sum(b.revtotal),2),0) AS comrevenuew,
     ifnull(
     (  SELECT Sum(daily_target)
        FROM   `live_statsb`
        WHERE  type= '".$businessunit."'
        AND    ( businessunit LIKE '%".$bu."%'
               OR     businessunit LIKE '%".$bu2."%')),0) AS goal,
     round(ifnull(round(sum(b.revtotal),2),0)/ifnull(
     (
            SELECT sum(daily_target)
            FROM   `live_statsb`
            WHERE  type= '".$businessunit."'
            AND    ( businessunit LIKE '%".$bu."%'
                   OR     businessunit LIKE '%".$bu2."%')),0) * 100,2) AS per
FROM      (
            SELECT jobs.jobid AS jobscompleted
            FROM   jobs
            WHERE  jobs.active = 1
            AND    upper(jobs.status) = 'COMPLETED'
            AND    jobs.businessunit IN
                   (SELECT businessunit
                          FROM   `live_statsb`
                          WHERE  type = '".$businessunit."')
            AND    ( jobs.completedon BETWEEN '".$startdate."' AND    '".$enddate."' )
            AND    (jobs.businessunit LIKE '%".$bu."%'
                   OR     jobs.businessunit LIKE '%".$bu2."%') )a
LEFT JOIN
     (
              SELECT   invoices.jobid          AS injobid,
                       sum(invoiceitems.total) AS revtotal
              FROM     invoices,
                       `invoiceitems`,
                       incomeitems
              WHERE    invoices.invoiceid=invoiceitems.invoiceid
              AND      invoiceitems.ledgerid=incomeitems.ledgerid
              AND      invoiceitems.active=1
              GROUP BY invoices.jobid) b
ON        a.jobscompleted=b.injobid
ORDER BY  `a`.`jobscompleted` ASC

Here, currently, this query is running in the loop, the only thing which gonna be different here is the $businessunit basically, there are around 6 types: type1, type2, type3, type, type5, type6, how could I get values for these 6 types in a single query.

0 likes
1 reply
rodrigo.pedra's avatar
Level 56

So many things...

  • Do not interpolate php variables into your query string. This can lead to SQL injection. Use query parameters. Search for SQL Injection to learn about it.
  • Do not use unsanitized strings in like operators, unless you want your users to use % and _ to enhance their queries.

Try this:

$types = ['type1', 'type2', 'type3', 'type', 'type5', 'type6'];

$sql = vsprintf(<<<'SQL'
SELECT
    IFNULL(ROUND(SUM(`b`.`revtotal`), 2), 0) AS `comrevenuew`,
    IFNULL((
        SELECT SUM(`daily_target`)
        FROM `live_statsb`
        WHERE
            `type` IN (%s)
            AND (`businessunit` LIKE ? OR `businessunit` LIKE ?)), 0) AS `goal`,
    ROUND(IFNULL(ROUND(SUM(`b`.`revtotal`), 2), 0) / IFNULL((
        SELECT SUM(`daily_target`)
        FROM `live_statsb`
        WHERE
            `type` IN (%s)
            AND (`businessunit` LIKE ? OR `businessunit` LIKE ?)), 0) * 100, 2) AS `per`
FROM (
    SELECT `jobs`.`jobid` AS `jobscompleted`
    FROM `jobs`
    WHERE
        `jobs`.`active` = 1
        AND UPPER(`jobs`.`status`) = 'COMPLETED'
        AND `jobs`.`businessunit` IN (
            SELECT `businessunit`
            FROM `live_statsb`
            WHERE `type` IN (%s))
        AND (`jobs`.`completedon` BETWEEN ? AND ?)
        AND (`jobs`.`businessunit` LIKE ? OR `jobs`.`businessunit` LIKE ?)
) `a`
LEFT JOIN (
    SELECT
        `invoices`.`jobid` AS `injobid`,
        SUM(`invoiceitems`.`total`) AS `revtotal`
    FROM
        `invoices`,
        `invoiceitems`,
        `incomeitems`
    WHERE
        `invoices`.`invoiceid` = `invoiceitems`.`invoiceid`
        AND `invoiceitems`.`ledgerid` = `incomeitems`.`ledgerid`
        AND `invoiceitems`.`active` = 1
    GROUP BY
        `invoices`.`jobid`) `b` ON `a`.`jobscompleted` = `b`.`injobid`
ORDER BY `a`.`jobscompleted` ASC
SQL, [
    implode(',', array_fill(0, count($types), '?')),
    implode(',', array_fill(0, count($types), '?')),
    implode(',', array_fill(0, count($types), '?')),
]);

$sanitize = fn ($value) => Str::of($value)
    ->replaceMatches('/\s+/', ' ')
    ->trim()
    ->replace('\\', '\\\\\\')
    ->pipe(fn ($str) => \addcslashes($str->value(), '%_'))
    ->replace(' ', '%')
    ->wrap('%')
    ->value();

$records = DB::select($sql, [
    ...$types,
    $sanitize($bu),
    $sanitize($bu2),
    ...$types,
    $sanitize($bu),
    $sanitize($bu2),
    ...$types,
    $startdate,
    $enddate,
    $sanitize($bu),
    $sanitize($bu2),
]);

dd($records);

You'll need these imports on the top of your file:

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

Good luck =)

1 like

Please or to participate in this conversation.