From a Stata .dta File to Excel, Value Labels and All
A .dta file from a replication package, a survey archive or a colleague’s project, and what you need is a spreadsheet. Excel cannot open it, and a Stata licence is a lot to buy for one look. Here is how to get from .dta to .xlsx in a browser tab — with the value labels still attached.
What Makes a .dta File Awkward Without Stata
It is not only that the format is binary. Three things go wrong when a .dta file is converted carelessly:
| In Stata | After a careless conversion |
|---|---|
Value labels: sex shows Male and Female | A column of 1s and 2s, and nobody left who remembers which is which |
Dates: hired shows 01apr2019 | 21640 — the number of days since 1 January 1960 |
| Versions: a file saved by a current Stata | Refused by an older copy of Stata — the reason saveold exists |
Doing It in the Browser
OmniSelect FileSQL reads Stata files with ReadStat, the open-source library behind R’s haven and Python’s pyreadstat, compiled to WebAssembly and run inside your tab. Nothing is uploaded.
- Open the app.
- Drop the
.dtafile onto the File Select panel. It gets a row with the type DTA and a one-letter table name in the Alias column:labour.dtabecomesL. - Look at it.
SELECT * FROM L LIMIT 100
| pid | sex | sex_label | educ | educ_label | hrwage | hired |
|---|---|---|---|---|---|---|
| 1001 | 1 | Male | 3 | Bachelor’s | 22.5 | 2019-04-01 |
| 1002 | 2 | Female | 4 | Postgraduate | 31 | 2021-09-13 |
| 1003 | 2 | Female | 2 | High school | 17.25 | 2023-01-09 |
| 1004 | 1 | Male | 3 | Bachelor’s | 24 | 2018-06-25 |
| 1006 | 1 | Male | 1 | No diploma | 14 | 2024-07-01 |
Every variable with value labels comes in twice: the code as stored (sex) and, beside it, what the code means (sex_label). Keep both — ORDER BY educ puts qualifications in their coded order, ORDER BY educ_label alphabetically. The %td date hired is a real date.
Ask It Questions
The plain-English box writes the SQL for you, inside your browser. average hrwage by educ_label becomes:
SELECT educ_label, AVG(hrwage) AS avg_hrwage FROM L GROUP BY educ_label
| educ_label | avg_hrwage |
|---|---|
| Bachelor’s | 24.166666666666668 |
| Postgraduate | 32 |
| High school | 17.5 |
| No diploma | 14 |
It works from the column names in your file. Ask for average hourly wage by sex and it says that wage is not a column and lists the words it did not recognise, rather than guessing. Name the columns — hrwage, sex_label — and it follows. Or write the SQL yourself, rounded and sorted:
SELECT sex_label, COUNT(*) AS people, ROUND(AVG(hrwage), 2) AS avg_wage FROM L GROUP BY sex_label ORDER BY avg_wage DESC
| sex_label | people | avg_wage |
|---|---|---|
| Female | 5 | 27.85 |
| Male | 5 | 19.15 |
Dates compare as dates. Everyone hired since the start of 2022:
SELECT * FROM L WHERE hired >= '2022-01-01' ORDER BY hired
Drop a .dta file in and see inside it.
Open the app →From .dta to Excel
- Run the query whose result you want in the spreadsheet —
SELECT * FROM Lfor everything. - Open the Export menu above the results and choose Excel.
You get an .xlsx file with one sheet, Query Results, and a header row of column names. Codes and wages are real numbers, so they sum and chart; labels are text; dates are written as text in YYYY-MM-DD form, which sorts and filters correctly as it is. If you need them as Excel dates, Data › Text to Columns with the column format Date: YMD converts them in one step. The export holds every row of the result, however many the Row limit box shows on screen.
For a sheet that reads like Stata’s Data Editor with labels on, choose and rename the columns before exporting:
SELECT pid, sex_label AS sex, educ_label AS education, hrwage, hired FROM L
| pid | sex | education | hrwage | hired |
|---|---|---|---|---|
| 1001 | Male | Bachelor’s | 22.5 | 2019-04-01 |
| 1002 | Female | Postgraduate | 31 | 2021-09-13 |
| 1003 | Female | High school | 17.25 | 2023-01-09 |
Excel holds up to 1,048,576 rows on a sheet, and the app reads up to 1,000,000 rows from one file, so a whole file always fits. CSV, JSON and Parquet are on the same menu.
What Comes Across
| In the .dta file | In the table |
|---|---|
| Numeric variables (byte, int, long, float, double) | Numbers |
| String variables | Text |
| Value labels | The code, plus a <name>_label column holding its label |
%td dates | Dates, such as 2019-04-01 |
%tc date-times | Date and time, such as 2019-04-01 14:30:00 |
%tw, %tm, %tq, %th | The first day of the period: March 2024 in %tm is 2024-03-01 |
Missing values (.) | Empty — NULL in SQL |
| Variable labels | Not shown: columns are named by the variable names |
| Files from Stata 13 and later, and from before | Both open — the format changed at Stata 13, and the reader knows both |
Reasonable Questions
Does it matter which version of Stata saved the file?
No. Files saved by current versions of Stata and by versions from before the format changed at Stata 13 both open, so there is no saveold round trip.
What if a code has no label?
Then its _label cell is empty and the code is still there in the column beside it, so nothing is lost.
Can I save a .dta file?
No. Exports are Excel, CSV, JSON or Parquet. Stata reads the Excel file back with import excel.
How big a file can it take?
Up to 50 MB and 1,000,000 rows. For a larger file, keep only the variables you need in Stata, R or Python first.
Is my data sent anywhere?
No. The file is read in your browser and stays on your machine — a one-minute check shows it.