PrestaShop has a SQL manager built in, so this looks solved. It mostly is — until the query you need is slow, the export is capped, or the multi-language joins quietly double your revenue.
PrestaShop's back office has an SQL manager: write a SELECT, get a CSV. For a small shop that genuinely is the answer, and you can stop reading. The catch is where that query runs — on your production database, from the same PHP process serving the shop, with whatever execution limits your host imposes. A query across a year of orders can take long enough to hit them.
Then there's the join problem. Product and category names live in _lang tables, and multi-shop installs split rows again across _shop variants. Miss a language filter and every product appears once per language: your top-seller list looks plausible and your totals are quietly multiplied. It's the most common way a PrestaShop export is wrong without looking wrong.
Finally, volume in the wrong places. A typical install carries several hundred tables, and the biggest are ps_connections, ps_guest and ps_pagenotfound — visitor tracking that on one production store we sync accounts for roughly 97% of all rows. None of it belongs in a spreadsheet, but it's in every naive export of "the database".
All three end in a spreadsheet. The difference is where the query runs and how much you trust the number when it arrives.
Advanced Parameters → SQL Manager: write a SELECT in the back office and download the CSV.
A paid module that exports orders and products on a schedule, sometimes straight into a Google Sheet.
BeQuery clones the shop into an isolated PostgreSQL copy, tracking tables excluded. You query the copy and export a result that's already aggregated.
Read-only MySQL credentials, host and port. BeQuery clones the database into an isolated PostgreSQL copy that only your team can reach — the shop itself is only ever read.
This is the step that decides whether the spreadsheet survives. In the SQL editor, aggregate first: revenue by month, margin by product, customers by cohort. You want the answer, which is hundreds of rows, not the raw orders table, which is hundreds of thousands.
Save the query, then either export CSV or XLSX from the editor for a one-off, or publish the query as a CSV link. XLSX exports are capped at 500,000 rows; CSV will happily hand you more than a spreadsheet can hold, which is another reason to aggregate first.
Drop =IMPORTDATA("…your link…") into a cell. Sheets fetches it on its own — roughly once an hour — so the tab stays current without anyone exporting anything again. Build your charts and pivots on top of that range. The link is a password in URL form: anyone who can see the formula can read the results, and you can revoke it from BeQuery at any time.
For a lot of PrestaShop analysis, yes. There's a fairly clear line where it stops being true.
Nine times out of ten it's a _lang or _shop join multiplying rows: join ps_product to ps_product_lang without filtering id_lang and every product appears once per installed language. The other common cause is counting order states that shouldn't count — carts, cancelled and refunded orders sitting alongside valid ones.
Not natively — it's a manual download each time. Modules add scheduling, at the cost of running the query against production on a timer. Querying a copy sidesteps the trade-off entirely: the query can be as heavy as it likes because nothing depends on the database it runs against.
It can refresh itself. Publish a saved query as a CSV link, paste =IMPORTDATA("…") into a cell, and Sheets refetches it on its own — about once an hour. Worth being precise about the direction: BeQuery doesn't write into your spreadsheet, the spreadsheet pulls from BeQuery. Nothing is pushed, nothing is stored in Google on our side, and revoking the link stops it immediately.
Treat it as a password. It's fetched anonymously by Google, so the URL itself is the credential — anyone holding it, including anyone who can open your spreadsheet and read the formula, can see that query's results. It's deliberately narrow: one saved query, read-only, row-capped, and revocable. We store only a hash of it, which is why it's shown once when you create it and can't be retrieved afterwards. For anything sensitive shared widely, use Looker Studio on a read-only connection instead.
Google Apps Script can open a JDBC connection to MySQL, so it is technically possible. It means exposing your production database to Google's IP ranges, writing and maintaining the script, and having every refresh query the same server that serves your customers. It's a lot of moving parts to end up with a spreadsheet that occasionally times out.
Google Sheets caps a spreadsheet at 10 million cells across all its tabs. That sounds enormous until you divide by columns: a 20-column export runs out at around 500,000 rows, and performance gets unpleasant well before the hard limit. Aggregated results are never a problem; raw order lines from a busy store are.
Free tier, no credit card, read-only access. Production is never written to — and you can explore the demo store before connecting anything.