MySQL - запрос не суммирует «итоговые» строки - PullRequest
0 голосов
/ 18 июня 2020

Среда

  • mysql версия : 5.7.16
  • Java версия : 7
  • mysql jdb c версия коннектора : 5.1.44
  • схема базы данных : Fishbowl Inventory 2019, версия: 19 Производство
  • Отчет об изменении : Сводка заказа на продажу

Описание проблемы

Суммы заказов на продажу отражают те же значения, что и значения отдельных позиций, поэтому суммирование происходит не так, как хотелось бы. Ожидается, что каждая строка покажет одно и то же значение в столбцах, связанных с SO. Я предполагаю, что это как-то связано с группировкой, но мне нужно показать каждую позицию. Я слишком долго смотрел и пробовал то, то и то, и другое, и просто не вижу деревьев за лесом. Бьюсь об заклад, это то, что заставляет меня go "дох!" когда вы указываете мне на это. : 0)


Соответствующие таблицы

  • SO - это основная таблица заказов на продажу.
  • SOITEM - это таблица отдельных позиций, одна ко многим из SO table.
  • SOITEM_AUD - это таблица истории позиций, одна ко многим из таблицы SOITEM. Мне нужно go в таблице аудита, чтобы рассчитать количество / количество отгруженных до даты, на дату и оставшееся количество.

Примеры результатов запроса

щелкните, чтобы увидеть изображение


Строки неисправностей

    SUM(soshipped.LIAMTORDERTOTAL) as SOAMTORDERTOTAL,
    SUM(soshipped.LIAMTSHIPPEDPRIOR) as SOAMTSHIPPEDPRIOR,
    SUM(soshipped.LIAMTSHIPPEDTODAY) as SOAMTSHIPPEDTODAYTOTAL,
    SUM(soshipped.LIAMTREMAINING) as SOAMTREMAININGTOTAL

Полный запрос

SELECT

    /* ORIG: $P!{cbGroupBy} AS GROUPBY,*/
    LOCATIONGROUP.NAME AS GROUPBY,
    LOCATIONGROUP.NAME AS LG,
    CUSTOMER.NAME AS CUSTOMER,
    so.NUM,
    soitem.SOID,

    soitem.SOLINEITEM,
    soshipped.UNITPRICE,
    soshipped.ADJUSTAMOUNT,

    soshipped.QTYTOFULFILL,
    soshipped.LIAMTORDERTOTAL as LIAMTORDERTOTAL,
    SUM(soshipped.LIAMTORDERTOTAL) as SOAMTORDERTOTAL,

    soshipped.LIQTYSHIPPEDPRIOR,
    soshipped.LIAMTSHIPPEDPRIOR, 
    SUM(soshipped.LIAMTSHIPPEDPRIOR) as SOAMTSHIPPEDPRIOR,

    soshipped.LIQTYSHIPPEDTODAY,
    soshipped.LIAMTSHIPPEDTODAY,
    SUM(soshipped.LIAMTSHIPPEDTODAY) as SOAMTSHIPPEDTODAYTOTAL,

    soshipped.LIQTYREMAINING,
    soshipped.LIAMTREMAINING,
    SUM(soshipped.LIAMTREMAINING) as SOAMTREMAININGTOTAL

FROM SO
LEFT JOIN stateconst ON so.shiptostateid = stateconst.id
INNER JOIN locationgroup ON locationgroup.id = so.locationgroupid
INNER JOIN customer ON customer.id = so.customerid
INNER JOIN sostatus ON sostatus.id = so.statusid
INNER JOIN soitem ON soitem.soid = so.id
LEFT JOIN product ON soitem.productid = product.id
JOIN qbclass ON qbclass.id = so.qbclassid
LEFT JOIN currency ON currency.homeCurrency = 1

 INNER JOIN (
    SELECT
        soitem_aud.SOID,
        soitem_aud.SOLINEITEM,
        soitem_aud.UNITPRICE,
        soitem_aud.ADJUSTAMOUNT,
        soitem_aud.QTYTOFULFILL,
        ROUND(
            ((soitem_aud.QTYTOFULFILL * soitem_aud.unitprice) +
                (IF(soitem_aud.qtytofulfill = 0,0,soitem_aud.adjustamount / soitem_aud.qtytofulfill) * soitem_aud.QTYTOFULFILL)) * 10
            ,1) / 10 AS LIAMTORDERTOTAL,
        IFNULL(IFNULL(sia.qtyalreadyfulfilled, 0), 0) AS LIQTYSHIPPEDPRIOR,
        ROUND(
            ((IFNULL(IFNULL(sia.qtyalreadyfulfilled, 0), 0) * soitem_aud.unitprice) +
                (IF(soitem_aud.qtytofulfill = 0,0,soitem_aud.adjustamount / soitem_aud.qtytofulfill) * IFNULL(IFNULL(sia.qtyalreadyfulfilled, 0), 0))) * 10
            ,1) / 10 AS LIAMTSHIPPEDPRIOR,
        soitem_aud.QTYFULFILLED - IFNULL(IFNULL(sia.qtyalreadyfulfilled, 0), 0) AS LIQTYSHIPPEDTODAY,
        ROUND(
            (((soitem_aud.qtyfulfilled - IFNULL(IFNULL(sia.qtyalreadyfulfilled, 0), 0)) * soitem_aud.unitprice) +
                (IF(soitem_aud.qtytofulfill = 0,0,soitem_aud.adjustamount / soitem_aud.qtytofulfill) * (soitem_aud.qtyfulfilled - IFNULL(IFNULL(sia.qtyalreadyfulfilled, 0), 0)))) * 10
            ,1) / 10 AS LIAMTSHIPPEDTODAY,
        soitem_aud.QTYTOFULFILL - soitem_aud.QTYFULFILLED AS LIQTYREMAINING,  
        ROUND(
            (((soitem_aud.QTYTOFULFILL - soitem_aud.qtyfulfilled) * soitem_aud.unitprice) +
                (IF(soitem_aud.QTYTOFULFILL = 0,0,soitem_aud.adjustamount / soitem_aud.QTYTOFULFILL) * (soitem_aud.QTYTOFULFILL - soitem_aud.qtyfulfilled))) * 10
            ,1) / 10 AS LIAMTREMAINING                 
    FROM
        soitem_aud            
    LEFT OUTER JOIN ( SELECT 
              SOID
            , SOLINEITEM
            , IFNULL(MAX(QTYFULFILLED),0) AS qtyalreadyfulfilled
           FROM SOITEM_AUD
        /* withPARAMETER: WHERE DATE_FORMAT(DATELASTFULFILLMENT, '%Y %m %d') < DATE_FORMAT($P{dateRange1}, '%Y %m %d') */
         WHERE DATE_FORMAT(DATELASTFULFILLMENT, '%Y %m %d') < DATE_FORMAT('2020-05-27', '%Y %m %d')
         GROUP
             BY SOID, SOLINEITEM ) AS sia
    ON soitem_aud.SOID = sia.SOID
    AND soitem_aud.SOLINEITEM = sia.SOLINEITEM
    /* withPARAMETER: WHERE soitem_aud.typeid IN (10,11,12,$P!{ckIncludeReturns},21,30,31,50,60,80)*/
    WHERE soitem_aud.typeid IN (10,11,12,900,21,30,31,50,60,80)
    /* withPARAMETER:AND DATE_FORMAT(soitem_aud.DATELASTFULFILLMENT, '%Y %m %d') = DATE_FORMAT($P{dateRange1}, '%Y %m %d') */
    AND DATE_FORMAT(soitem_aud.DATELASTFULFILLMENT, '%Y %m %d') = DATE_FORMAT('2020-05-27', '%Y %m %d')
    AND soitem_aud.PRODUCTNUM NOT IN ('Shipping', 'Shipping Out')
    GROUP BY soitem_aud.soid, soitem_aud.solineitem
) AS soshipped ON soitem.soid = soshipped.soid AND soitem.SOLINEITEM = soshipped.SOLINEITEM 

/* limit for testing purposes -------------------------------------------------- */    
WHERE so.NUM = 11834
AND soitem.SOID IN (SELECT ID FROM SO WHERE CUSTOMERID = 361)
/* ----------------------------------------------------------------------------- */

GROUP BY GROUPBY, LG, CUSTOMER, soitem.SOID, soitem.SOLINEITEM
ORDER BY GROUPBY, LG, CUSTOMER, soitem.SOID, soitem.SOLINEITEM

1 Ответ

0 голосов
/ 19 июня 2020

Хорошо, я закончил тем, что выбрал позиции из SOITEM, присоединил их к первому запросу для деталей позиции, а затем ко второму запросу для итоговых данных по заказу на продажу.

Это некрасиво, это повторяется, и должен быть лучший способ (да, CTE, но MySQL 5.7 не позволяет этого), но он работает. Если у кого-то есть предложение, совместимое с версией 5.7, чтобы сделать это менее повторяющимся, я был бы рад его увидеть. : 0)

SELECT

      /* ORIG: $P!{cbGroupBy} AS GROUPBY*/
      LOCATIONGROUP.NAME AS GROUPBY
    , LOCATIONGROUP.NAME AS LG
    , CUSTOMER.NAME AS CUSTOMER
    , SO.NUM AS SO
    , SO.DATEISSUED
    , SOSTATUS.NAME AS STATUS /* SO status */
    , SO.SALESMAN AS "user"
      /* wPARAMETER: , (case when $P{ckShowHistoricalProductNumber} = 1 then soitem.productnum else product.num end) AS PRODUCTNUM*/
    , (case when 1 = 1 then soitem.productnum else product.num end) AS PRODUCTNUM
    , UOM.CODE AS SOITEMUOMCODE
    , SOITEM.DESCRIPTION
    , SOITEM.ID AS ITEMID

    , soitem.SOID

    , soitem.SOLINEITEM
    , solineitems.SOITEMSTATUS

    , soitem.UNITPRICE
    , soitem.ADJUSTAMOUNT    
    , soitem.QTYTOFULFILL

    , IFNULL(solineitems.LIAMTORDEREDTOTAL, 0) as LIAMTORDEREDTOTAL /* OPRICE equivalent */
    , IFNULL(solineitems.LIQTYSHIPPEDPRIOR , 0) as LIQTYSHIPPEDPRIOR
    , IFNULL(solineitems.LIAMTSHIPPEDPRIOR , 0) as LIAMTSHIPPEDPRIOR
    , IFNULL(solineitems.LIQTYSHIPPEDTODAY , 0) as LIQTYSHIPPEDTODAY
    , IFNULL(solineitems.LIAMTSHIPPEDTODAY , 0) as LIAMTSHIPPEDTODAY /* FPRICE replacement; limited to date of report ONLY */
    , IFNULL(solineitems.LIQTYSHIPPEDTODATE , 0) as LIQTYSHIPPEDTODATE
    , IFNULL(solineitems.LIAMTSHIPPEDTODATE , 0) as LIAMTSHIPPEDTODATE
    , IFNULL(solineitems.LIQTYREMAINING , 0) as LIQTYREMAINING 
    , IFNULL(solineitems.LIAMTREMAINING , 0) as LIAMTREMAINING /* OPRICE - FPRICE replacement */

    , IFNULL(sototals.SOAMTORDERTOTAL, 0) as SOAMTORDERTOTAL /* SORDER.ORDERED equivalent */
    , IFNULL(sototals.SOAMTSHIPPEDPRIOR, 0) as SOAMTSHIPPEDPRIOR
    , IFNULL(sototals.SOAMTSHIPPEDTODAY, 0) as SOAMTSHIPPEDTODAY /* SORDER.SHIPPED replacement; limited to date of report ONLY */
    , IFNULL(sototals.SOAMTSHIPPEDTODATE, 0) as SOAMTSHIPPEDTODATE
    , IFNULL(sototals.SOAMTREMAINING, 0) as SOAMTREMAINING /* SORDER.ORDERED - SORDER.SHIPPED replacement */

    , MIN(SOITEM.DATESCHEDULEDFULFILLMENT) AS DATESCHEDULEDFULFILLMENT
    , SOITEM.DATESCHEDULEDFULFILLMENT AS ITEMFULFILLMENT
    , MIN(SO.DATEISSUED) AS MINDATEISSUED
    , POSTSO.POSTDATE
    , CURRENCY.SYMBOL
    , SO.CUSTOMERPO
    , STATECONST.CODE AS SHIPTOSTATE
    , SOITEM.DATELASTFULFILLMENT
    , SO.DATEFIRSTSHIP
    , SO.DATECOMPLETED

FROM SOITEM
LEFT OUTER JOIN SO ON soitem.SOID = so.ID
LEFT JOIN STATECONST ON so.SHIPTOSTATEID = stateconst.ID
INNER JOIN LOCATIONGROUP ON locationgroup.ID = so.LOCATIONGROUPID
INNER JOIN CUSTOMER ON customer.ID = so.CUSTOMERID
INNER JOIN SOSTATUS ON sostatus.ID = so.STATUSID
LEFT JOIN PRODUCT ON soitem.PRODUCTID = product.ID
JOIN QBCLASS ON qbclass.ID = so.QBCLASSID
LEFT JOIN CURRENCY ON currency.HOMECURRENCY = 1
LEFT JOIN (
    SELECT
        postso.SOID AS SOID,
        MAX(postso.POSTDATE) AS POSTDATE
    FROM POSTSO
    /* withPARAMETER: WHERE postso.POSTDATE BETWEEN $P{dateRange1} AND DATE_SUB($P{dateRange2}, INTERVAL 1 SECOND)*/
    WHERE postso.POSTDATE BETWEEN '2020-05-27' AND DATE_SUB('2020-05-27', INTERVAL 1 SECOND)
    GROUP BY postso.SOID
) AS postso ON so.ID = postso.SOID
INNER JOIN UOM ON uom.ID = soitem.UOMID

/* SO TOTALS */
LEFT OUTER JOIN (
    SELECT 

          soitem.SOID      

        , SUM(soitem.UNITPRICE * soitem.QTYTOFULFILL + soitem.ADJUSTAMOUNT) AS SOAMTORDERTOTAL

        , SUM(ROUND(
            ((IFNULL(qsp.QTYFULFILLEDPRIOR, 0) * soitem.UNITPRICE) +
                ((IF(soitem.QTYTOFULFILL = 0,0,soitem.ADJUSTAMOUNT / soitem.QTYTOFULFILL) * IFNULL(qsp.QTYFULFILLEDPRIOR, 0)))) * 10
            ,1) / 10) AS SOAMTSHIPPEDPRIOR

        , SUM(ROUND(
            (((IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, 0)) - IFNULL(qsp.QTYFULFILLEDPRIOR, 0)) * soitem.UNITPRICE) +
                (IF(soitem.QTYTOFULFILL = 0,0,soitem.ADJUSTAMOUNT / soitem.QTYTOFULFILL) * (IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, 0)) - IFNULL(qsp.QTYFULFILLEDPRIOR, 0)))) * 10
            ,1) / 10) AS SOAMTSHIPPEDTODAY

        , SUM(ROUND(
            ((IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, 0)) * soitem.UNITPRICE) +
                (IF(soitem.QTYTOFULFILL = 0,0,soitem.ADJUSTAMOUNT / soitem.QTYTOFULFILL) * IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, 0)))) * 10
            ,1) / 10) AS SOAMTSHIPPEDTODATE

        , SUM(ROUND(
            (((soitem.QTYTOFULFILL - IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, 0))) * soitem.UNITPRICE) +
                (IF(soitem.QTYTOFULFILL = 0,0,soitem.ADJUSTAMOUNT / soitem.QTYTOFULFILL) * (soitem.QTYTOFULFILL - IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, 0))))) * 10
            ,1) / 10) AS SOAMTREMAINING 

    FROM SOITEM  

    /* get quantity shipped PRIOR to this date */
    LEFT OUTER JOIN 
    (
        SELECT
              SOID
            , SOLINEITEM
            , IFNULL(MAX(soitem_aud.QTYFULFILLED),0) as QTYFULFILLEDPRIOR
        FROM SOITEM_AUD 
        /* withPARAMETER: WHERE DATE_FORMAT(soitem_aud.DATELASTFULFILLMENT, '%Y %m %d') < DATE_FORMAT($P{dateRange1}, '%Y %m %d') */
        WHERE DATE_FORMAT(soitem_aud.DATELASTFULFILLMENT, '%Y %m %d') < DATE_FORMAT('2020-05-27', '%Y %m %d')
        AND soitem_aud.PRODUCTNUM NOT IN ('Shipping', 'Shipping Out')
        GROUP BY 
              SOID
            , SOLINEITEM 
    ) AS qsp ON soitem.SOID  = qsp.SOID AND soitem.SOLINEITEM = qsp.SOLINEITEM

    /* get quantity shipped ON this date */
    LEFT OUTER JOIN 
    (
        SELECT
              soitem.SOID
            , soitem.SOLINEITEM
            , IFNULL(soitem_aud.QTYFULFILLED, 0) as QTYFULFILLEDTODATE /* INCLUDES items fulfilled THIS DATE */
        FROM SOITEM
        LEFT OUTER JOIN SOITEM_AUD  ON soitem.SOID = soitem_aud.SOID AND soitem.SOLINEITEM = soitem_aud.SOLINEITEM
        /* withPARAMETER: WHERE DATE_FORMAT(soitem_aud.DATELASTFULFILLMENT, '%Y %m %d') = DATE_FORMAT($P{dateRange1}, '%Y %m %d') */
        WHERE DATE_FORMAT(soitem_aud.DATELASTFULFILLMENT, '%Y %m %d') = DATE_FORMAT('2020-05-27', '%Y %m %d')
        AND soitem_aud.PRODUCTNUM NOT IN ('Shipping', 'Shipping Out')
        GROUP BY 
              SOID
            , SOLINEITEM 
    ) AS qftd ON soitem.SOID  = qftd.SOID AND soitem.SOLINEITEM = qftd.SOLINEITEM

    WHERE soitem.PRODUCTNUM NOT IN ('Shipping', 'Shipping Out')
    GROUP BY 
          soitem.SOID
) as SOTOTALS ON soitem.SOID = sototals.SOID

/* LINE ITEM DETAILS */
LEFT OUTER JOIN (
    SELECT 
          soitem.SOID
        , soitem.SOLINEITEM
        , IFNULL(qftd.SOITEMSTATUSNAME, IFNULL(qsp.SOITEMSTATUSNAME, 'Unknown')) AS SOITEMSTATUS

        , soitem.QTYTOFULFILL * soitem.UNITPRICE + soitem.ADJUSTAMOUNT as LIAMTORDEREDTOTAL

        , IFNULL(qsp.QTYFULFILLEDPRIOR, 0) as LIQTYSHIPPEDPRIOR    
        , ROUND(
            ((IFNULL(qsp.QTYFULFILLEDPRIOR, 0) * soitem.UNITPRICE) +
                ((IF(soitem.QTYTOFULFILL = 0,0,soitem.ADJUSTAMOUNT / soitem.QTYTOFULFILL) * IFNULL(qsp.QTYFULFILLEDPRIOR, 0)))) * 10
            ,1) / 10 AS LIAMTSHIPPEDPRIOR

        , IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, 0)) - IFNULL(qsp.QTYFULFILLEDPRIOR, 0) as LIQTYSHIPPEDTODAY
        , ROUND(
            (((IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, 0)) - IFNULL(qsp.QTYFULFILLEDPRIOR, 0)) * soitem.UNITPRICE) +
                (IF(soitem.QTYTOFULFILL = 0,0,soitem.ADJUSTAMOUNT / soitem.QTYTOFULFILL) * (IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, 0)) - IFNULL(qsp.QTYFULFILLEDPRIOR, 0)))) * 10
            ,1) / 10 AS LIAMTSHIPPEDTODAY

        , IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, 0)) as LIQTYSHIPPEDTODATE
        , ROUND(
            ((IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, 0)) * soitem.UNITPRICE) +
                (IF(soitem.QTYTOFULFILL = 0,0,soitem.ADJUSTAMOUNT / soitem.QTYTOFULFILL) * IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, IFNULL(qsp.QTYFULFILLEDPRIOR, 0))))) * 10
            ,1) / 10 AS LIAMTSHIPPEDTODATE

        , soitem.QTYTOFULFILL - IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, 0)) as LIQTYREMAINING
        , ROUND(
            (((soitem.QTYTOFULFILL - IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, 0))) * soitem.UNITPRICE) +
                (IF(soitem.QTYTOFULFILL = 0,0,soitem.ADJUSTAMOUNT / soitem.QTYTOFULFILL) * (soitem.QTYTOFULFILL - IFNULL(qftd.QTYFULFILLEDTODATE, IFNULL(qsp.QTYFULFILLEDPRIOR, 0))))) * 10
            ,1) / 10 AS LIAMTREMAINING 

    FROM SOITEM  

    /* get quantity shipped PRIOR to this date */
    LEFT OUTER JOIN 
    (
        SELECT
              SOID
            , SOLINEITEM
            , soitemstatus.NAME as SOITEMSTATUSNAME
            , IFNULL(MAX(soitem_aud.QTYFULFILLED),0) as QTYFULFILLEDPRIOR
        FROM SOITEM_AUD 
        INNER JOIN SOITEMSTATUS ON soitem_aud.STATUSID = soitemstatus.ID
        /* withPARAMETER: WHERE DATE_FORMAT(soitem_aud.DATELASTFULFILLMENT, '%Y %m %d') < DATE_FORMAT($P{dateRange1}, '%Y %m %d') */
        WHERE DATE_FORMAT(soitem_aud.DATELASTFULFILLMENT, '%Y %m %d') < DATE_FORMAT('2020-05-27', '%Y %m %d')
        AND soitem_aud.PRODUCTNUM NOT IN ('Shipping', 'Shipping Out')
        GROUP BY 
              SOID
            , SOLINEITEM 
        ORDER BY SOID, SOLINEITEM, soitem_aud.DATELASTFULFILLMENT DESC
    ) AS qsp ON soitem.SOID  = qsp.SOID AND soitem.SOLINEITEM = qsp.SOLINEITEM

    /* get quantity shipped ON this date */
    LEFT OUTER JOIN 
    (
        SELECT
              soitem.SOID
            , soitem.SOLINEITEM
            , soitemstatus.NAME as SOITEMSTATUSNAME
            , IFNULL(soitem_aud.QTYFULFILLED, 0) as QTYFULFILLEDTODATE /* INCLUDES items fulfilled THIS DATE */
        FROM SOITEM
        LEFT OUTER JOIN SOITEM_AUD  ON soitem.SOID = soitem_aud.SOID AND soitem.SOLINEITEM = soitem_aud.SOLINEITEM
        INNER JOIN SOITEMSTATUS ON soitem_aud.STATUSID = soitemstatus.ID
        /* withPARAMETER: WHERE DATE_FORMAT(soitem_aud.DATELASTFULFILLMENT, '%Y %m %d') = DATE_FORMAT($P{dateRange1}, '%Y %m %d') */
        WHERE DATE_FORMAT(soitem_aud.DATELASTFULFILLMENT, '%Y %m %d') = DATE_FORMAT('2020-05-27', '%Y %m %d')
        AND soitem_aud.PRODUCTNUM NOT IN ('Shipping', 'Shipping Out')
        GROUP BY 
              SOID
            , SOLINEITEM 
    ) AS qftd ON soitem.SOID  = qftd.SOID AND soitem.SOLINEITEM = qftd.SOLINEITEM

    WHERE soitem.PRODUCTNUM NOT IN ('Shipping', 'Shipping Out')
    GROUP BY 
          soitem.SOID
        , soitem.SOLINEITEM
) as SOLINEITEMS ON soitem.SOID = solineitems.SOID AND soitem.SOLINEITEM = solineitems.SOLINEITEM

WHERE soitem.PRODUCTNUM NOT IN ('Shipping', 'Shipping Out')
/* withPARAMETER: AND
    soitem.TYPEID IN (10,11,12,$P!{ckIncludeReturns},21,30,31,50,60,80)
    AND so.LOCATIONGROUPID IN ($P!{locationGroupID})
    AND so.CUSTOMERID LIKE $P{customerID}
    AND soitem.QBCLASSID LIKE $P{qbClassID}
    AND UPPER(so.SALESMAN) LIKE UPPER($P{salesPerson})
    AND so.STATUSID IN ($P{ckEstimate}, $P{ckIssued}, $P{ckInProgress}, $P{ckFulfilled}, $P{ckClosedShort}, $P{ckVoided}, $P{ckExpired})
    AND COALESCE(product.NUM,'') LIKE $P{productNum}
    AND COALESCE(stateconst.NAME,'') LIKE $P!{cbShipToState/Province}
*/

AND soitem.SOID = 8369 /* TESTING PURPOSES ONLY */
GROUP BY soitem.SOID, soitem.SOLINEITEM
ORDER BY soitem.SOID, soitem.SOLINEITEM
...