0

I've been tasked with making output that fetches number of days passed between an order and its shipment, like this:

order_date orders Days0 Days1 Days7Plus
2022-11-01 12 9 3 1
2022-11-15 22 20 0 2
2022-12-02 77 65 5 7

I'm sure you can imagine example underlying data, where there's an orders table with a unique ID per record, an order date that can share multiple IDs, and each order has its own ship date.

The hard part is counting only business days, which required subtracting weekends and holidays from the date range days. I got that all figured out but it required copy-pasting these ugly sub-queries 7 more times :/ While this can be dynamically generated in other code, I figured there must be a cleaner way, since other people (some non-devs) may be testing or reviewing this, and I'll probably get grief about it.

Here's the query essentially:

# get orders shipped count
SELECT
    ...
  # orders that were shipped x number of days from receipt
    SUM(COALESCE(DATEDIFF(shipped, ordered), 0)
        - ( # subtract weekend days
            5 * (DATEDIFF('2022-12-05', '2022-11-01') DIV 7)
            + MID('0123444401233334012222340111123400012345001234550',
                    7 * WEEKDAY('2022-11-01') + WEEKDAY('2022-12-05') + 1, 1
            )
        )
        - ( # subtract holidays
            SELECT COUNT(`date`) FROM holiday WHERE active = 1
            AND `date` BETWEEN '2022-11-01' AND '2022-12-05'
            AND DAYOFWEEK(`date`) < 6
        )
        = 0) AS 0Days, # subsequently 1Days, 2Days, 3Days, etc
  ...
    SUM(COALESCE(DATEDIFF(shipped, ordered), 0)
            - ( # subtract weekend days
                5 * (DATEDIFF('2022-12-05', '2022-11-01') DIV 7)
                + MID('0123444401233334012222340111123400012345001234550',
                    7 * WEEKDAY('2022-11-01') + WEEKDAY('2022-12-05') + 1, 1
            )
        )
        - ( # subtract holidays
            SELECT COUNT(`date`) FROM holiday WHERE active = 1
            AND `date` BETWEEN '2022-11-01' AND '2022-12-05'
            AND DAYOFWEEK(`date`) < 6
        )
        >= 7) AS Days7Plus
FROM orders
WHERE
    AND ordered BETWEEN :startDate AND :endDate
GROUP BY CAST(ordered AS DATE)
ORDER BY ordered

I got the MID calculation from https://stackoverflow.com/a/6762805/14744970

I feel pretty proud of getting it all together, but I feel like I'm a small step away from collapsing the redundancy down somehow that I'm not quite understanding.

Note that I don't know if the GROUP BY actually matters with any sort of simplifying of the redundant statements.

SteveExdia
  • 321
  • 1
  • 3
  • 11
  • Calculate counts in value-per-row format `date, type, amount` (where type is "total", "days0", "days1", "days7plus"). Then pivot this rowset. – Akina Dec 06 '22 at 05:22

0 Answers0