Software & TechnicalFree
Data Analysis Write-Up From Query Results
Your query result answers a narrower question than the one you were asked. River writes both down, then writes the finding.
River reads the results, the query that produced them and the request that started it, then writes the analysis a stakeholder can act on. The finding first, in their units. The method underneath it. And the section every template asks for and nobody can fill: what these numbers cannot support, derived from the query rather than remembered. The supporting figures land in a sheet, with the population at every step so the denominator is visible to the reader.
Search this and you get seven versions of the same outline: executive summary, background, methodology, findings, limitations, recommendations, appendix. The outline is right. It is also the easy part, and it hands you a heading called Limitations with nothing to put under it. So the section fills with hedging, or it gets cut at five o'clock, and the number goes out attached to a population nobody stated. Most of the time that population was sitting in the query text.
Built for the analyst whose message became a board slide, and for anyone who has watched a finding argued into nothing because the method was three sentences of prose. Reach for it before the number goes anywhere. The pipeline documentation pack says what the tables underneath were actually tested for, and the schema register says what each column holds. The metric definitions pack settles what the word in your headline means before two people compute it differently. When a published number proves wrong, the data quality incident report traces who saw it.
Your query narrowed the question for you
A filter is a population definition. PostgreSQL states that ordinary comparison operators yield null, signifying unknown, not true or false, when either input is null, and offers a not-equals test against null as its worked example. So the clause excluding cancelled orders also excludes every order whose status was never set. Nobody wrote that down, the reader assumes the base is all orders, and the claim now describes a population it never touched.
The denominator moves too. In the same reference set, counting a column returns the number of input rows in which that value is not null, while counting rows returns every input row, and the mean is computed over non-null values only. So an average order value across a column that is empty a twentieth of the time is the average of the other nineteen twentieths. That is a real number, and it answers a slightly different question from the one on the slide.
Then reproducibility. On top ten lists PostgreSQL is unusually direct: without an ordering that constrains the result rows into a unique order you will get an unpredictable subset of the query's rows. It adds that this is not a bug but a consequence of SQL promising no order at all. Ties in the sort key are the ordinary case for a top ten of accounts. Rerun it next week, two rows have swapped, and the analysis has lost its reader.
How it works
Paste the results
The output as it came out, whether that is ten rows or a thousand.
Paste the query
The SQL itself, because every filter and join in it is a claim about the population.
Say what was asked
The original request in the words it arrived in, ticket, message or corridor conversation.
Read the gap
River writes the finding, the method and the population, then shows where request and query diverge.
What you get
- The finding stated as a claim in the reader's units, not in the query's
- The population the query actually measured, read out of its filters and joins
- What the numbers cannot support, derived from the SQL rather than recalled
- The question you were actually asked, beside the question the query really answered
- A supporting figures sheet carrying the row count at every filtering step
- One chart chosen to carry the finding, with the axis and sort choices justified
Common questions
I do not have the query, only the export.
Then the write-up says so, and the population section becomes a list of questions rather than a list of facts. It is still worth having: the export's own shape gives away a lot, including columns empty in a suspicious pattern and totals that do not reconcile to the rows above them. Paste the query when you can and the section fills itself.
Is this just an outline generator?
No, and the outline was never the problem. Every guide on the subject agrees on the sections. What none of them can do is fill the method and the limits, because that requires reading the query that produced the number. That is the work here, and it is why the query is a required field rather than an optional one.
What if the query answers a different question from the one I was asked?
That is the most common outcome and the write-up leads with it. Both questions get stated in one place: what the request asked for, what the result measures, and the distance between them in one sentence. Sometimes the distance is fine and worth naming anyway. Sometimes it is the entire finding, and the answer is a second query.
Does it write the chart too?
One chart, specified: the mark, the axes, what goes on each, the sort, and why that pairing carries the claim rather than a different one. Two charts arguing the same point halves the strength of both. Where the honest picture needs a broken axis or a log scale, it says so on the chart rather than in a footnote.
Our warehouse is not Postgres.
The mechanisms travel. Null comparison yielding unknown, aggregates skipping nulls, an inner join dropping unmatched rows and an unordered limit returning an arbitrary subset are properties of SQL itself rather than of one engine. Snowflake, BigQuery, Redshift and DuckDB inherit all four. Where a dialect differs on something that moves your number, the write-up flags it on the affected figure.
The stakeholder just wants the number.
They get it in the first line. The finding leads, in their units, with the action it supports. Everything else sits below it for the person who challenges it, which on any decision worth making is somebody. A write-up whose method is unreadable and a write-up with no method fail in the same meeting, three weeks apart.
What if the analysis does not support the answer they wanted?
Then it says so plainly, in the first line, with what the data does support beside it. The alternative is a write-up hedged into uselessness, which is worse for everyone: the decision gets made on the same evidence anyway, without the one sentence that would have changed it. A dashboard specification is where a recurring version of the question belongs.
Data Analysis Write-Up From Query Results
Fill in the form and your workspace opens with the work already underway.