withSequentialPeriodMetrics() for period-over-period analytics#59766
Open
NurullahDemirel wants to merge 3 commits intolaravel:13.xfrom
Open
withSequentialPeriodMetrics() for period-over-period analytics#59766NurullahDemirel wants to merge 3 commits intolaravel:13.xfrom
NurullahDemirel wants to merge 3 commits intolaravel:13.xfrom
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
withSequentialPeriodMetrics()Small, readable API
Screens that used to take 40-50 lines of "a few subqueries plus PHP-side
post-processing" typically collapse down to 5-10 lines:
That payload can be sent straight to the dashboard component and rendered as a
chart — no extra computation layer needed.
TL;DR
It buckets rows by a date column into periods (day / week / month / year),
computes the aggregates you ask for (
sum,avg,count,min,max)per bucket, and on top of that returns the absolute difference (
_change)and percent change (
_change_percent) versus the previous period — all inthe same query.
One call → monthly revenue, order count, and MoM percent change for each.
The result feeds straight into a line / bar chart.
The problem it solves
A seemingly trivial BI question — "how much revenue did we make each month,
and how does it compare to the previous month?" — usually ends up being
solved over and over again like this:
GROUP BY DATE_FORMAT(...).(current - previous) / previous * 100.null, divide-by-zero, missing periods, sort drift./ SQL Server), reimplement the date formatting expression for each.
withSequentialPeriodMetrics()collapses all of that into one builder call.The driver-specific SQL is generated automatically and a window function
(
LAG) returns both the aggregates and the comparison columns in a singleround-trip.
When to use it
It's a good fit if you need any of these:
"this week vs last week", etc.
is an aggregate, and you also want the percent change in the tooltip.
basket, cost…) computed at once.
When it is not the right tool:
different window-function pattern; this method is focused on sequential
period comparisons.
per category"). The method works on a single period axis; this could be
extended later via a
groupByparameter.At a glance
orderstable:Result:
Plugging it into a chart
The returned rows can be passed directly to Chart.js / ApexCharts / ECharts /
Recharts. For instance, the example above can be drawn as
"bars = revenue, line = MoM % change" on the same chart:
xychart-beta title "Monthly Revenue and Month-over-Month % Change" x-axis ["2024-01", "2024-02", "2024-03"] y-axis "Revenue" 0 --> 500 bar [300, 300, 400] line [0, 0, 33]Wiring it up on the frontend stays trivial:
Highlights
SQL Server 2012+. The correct date-formatting function (
DATE_FORMAT,STRFTIME,TO_CHAR,FORMAT) is selected automatically.revenue,cost,order_count… allcomputed together, each one getting its own
LAG(...)previous-periodcolumn and
_change/_change_percentcolumns.difference for another, and skip comparisons entirely for a third.
AggregateAPI: IDE-friendly, readable definitions likeAggregate::sum('revenue')->as('total_revenue')->precision(2).DB::raw('revenue * quantity')or a correlated subquery via aClosure."13,868,830.91"(US/EN),"13.868.830,91"(TR/DE),"13 868 830,91"(FR)… via PHP'snumber_format()— SQL stays purely numeric, formatting only happens atpresentation time.
datetime type via the schema; misuse is rejected with a clear error message.