Survey Data Stuck in a .sav File? Read It Without SPSS
.sav is how survey data travels — from panel providers and research agencies, university data archives and national statistics offices. Without an SPSS licence the file is a locked box, and the fieldwork you paid for is inside it. Here is how to open it, tabulate it and hand it on, in a browser tab.
The Usual Routes
| Approach | What it costs |
|---|---|
| IBM SPSS Statistics | A licence or subscription, for what may be one look at one file. |
| PSPP | A free program that reads .sav files. An install, which on a managed laptop means a ticket. |
| R (haven) or Python (pyreadstat) | Excellent, for people who write code. |
| Excel | Cannot open a .sav file at all. |
| An online converter | Respondent-level data sent to an unknown server — personal data you would have to account for. |
Doing It in the Browser
OmniSelect FileSQL reads SPSS files with ReadStat, the open-source library behind R’s haven and Python’s pyreadstat, compiled to WebAssembly and run inside your browser tab. The file is never uploaded.
- Open the app.
- Drop the
.savfile onto the File Select panel. It gets a row with the type SAV and a one-letter table name in the Alias column:survey.savbecomesS. - Look at it.
SELECT * FROM S LIMIT 100
| resp_id | region | region_label | q1_satis | q1_satis_label | recommend | recommend_label | age | int_date | weight |
|---|---|---|---|---|---|---|---|---|---|
| 101 | 1 | North | 5 | Very satisfied | 1 | Yes | 34 | 2026-03-02 | 1.2 |
| 102 | 2 | South | 4 | Satisfied | 1 | Yes | 51 | 2026-03-02 | 0.8 |
| 103 | 1 | North | 2 | Dissatisfied | 0 | No | 29 | 2026-03-03 | 1 |
| 105 | 4 | West | 3 | Neutral | 0 | No | 62 | 2026-03-04 | 0.9 |
| 106 | 2 | South | 1 | Yes | 38 | 2026-03-05 | 1.3 |
Every variable with value labels comes in twice: the code as stored, and a _label column beside it with what the code means — q1_satis 5 is Very satisfied. The interview date, held by SPSS as seconds since 1582, is a real date.
Respondent 106 answered 9, Refused, which the file defines as a user-missing value. As in SPSS, it is treated as missing: both cells are empty, and statistics leave it out. Compare a count of rows with a count of scores:
SELECT region_label, COUNT(*) AS answers, COUNT(q1_satis) AS scored,
ROUND(AVG(q1_satis), 2) AS avg_score
FROM S
GROUP BY region_label
ORDER BY avg_score DESC
| region_label | answers | scored | avg_score |
|---|---|---|---|
| West | 3 | 3 | 4.33 |
| South | 3 | 2 | 4 |
| East | 3 | 3 | 3.67 |
| North | 3 | 3 | 2.67 |
South has three respondents but two scores: the refusal did not drag its average towards 9.
Your SPSS Habits, in SQL
| In SPSS | Here |
|---|---|
FREQUENCIES | GROUP BY with COUNT(*), and a percentage |
CROSSTABS | GROUP BY two columns |
MEANS | AVG by group, as above |
SELECT IF | WHERE |
WEIGHT BY | SUM(x * weight) / SUM(weight) |
A frequency table, in code order, with percentages:
SELECT q1_satis_label, COUNT(*) AS n,
ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 1) AS pct
FROM S
GROUP BY q1_satis, q1_satis_label
ORDER BY q1_satis
| q1_satis_label | n | pct |
|---|---|---|
| Very dissatisfied | 1 | 8.3 |
| Dissatisfied | 2 | 16.7 |
| Neutral | 1 | 8.3 |
| Satisfied | 3 | 25 |
| Very satisfied | 4 | 33.3 |
| 1 | 8.3 |
The empty row is the missing answer, listed last as SPSS lists missing values.
A crosstab of region by whether they would recommend:
SELECT region_label, recommend_label, COUNT(*) AS n FROM S GROUP BY region_label, recommend_label ORDER BY region_label, recommend_label
A weighted mean. The weight is just a column, so a weighted average is written out — dividing only by the weights of respondents who have a score:
SELECT region_label,
ROUND(SUM(q1_satis * weight) / SUM(CASE WHEN q1_satis IS NOT NULL THEN weight END), 2) AS weighted_score
FROM S
GROUP BY region_label
ORDER BY weighted_score DESC
| region_label | weighted_score |
|---|---|
| West | 4.38 |
| South | 4 |
| East | 3.62 |
| North | 2.81 |
SELECT IF: respondents aged 40 or over who would not recommend:
SELECT resp_id, region_label, age FROM S WHERE recommend_label = 'No' AND age >= 40
Drop a .sav file in and see inside it.
Open the app →Or Just Ask
The plain-English box writes the SQL for you, inside your browser, with no AI service. It works from the column names: count by q1_satis_label becomes SELECT q1_satis_label, COUNT(*) AS count_rows FROM S GROUP BY q1_satis_label, and average age by region_label becomes SELECT region_label, AVG(age) AS avg_age FROM S GROUP BY region_label. The SQL is shown beside the question, ready to edit before you run it.
Handing It On
For a colleague without SPSS, run SELECT * FROM S and choose Export › CSV (or Excel). Codes and labels travel side by side:
resp_id,region,region_label,q1_satis,q1_satis_label,recommend,recommend_label,age,int_date,weight 101,1,North,5,Very satisfied,1,Yes,34,2026-03-02,1.2 102,2,South,4,Satisfied,1,Yes,51,2026-03-02,0.8 … 106,2,South,,,1,Yes,38,2026-03-05,1.3
The export holds every row of the result, not only the rows on screen.
What Comes Across
| In the SPSS file | In the table |
|---|---|
| Numeric and string variables | Numbers and text |
| Value labels | The code, plus a <name>_label column holding its label |
Date formats: DATE, ADATE, EDATE, SDATE … | Dates, such as 2026-03-02 |
DATETIME | Date and time |
TIME | A time, such as 14:30:00 |
| System-missing and user-missing values | Empty — NULL in SQL |
| Variable labels (the question wording) | Not shown: columns are named by the variable names, so keep the questionnaire to hand |
.zsav (compressed) and .por (portable) files | Read the same way |
Reasonable Questions
Is it reading the file correctly?
It uses ReadStat, the library R and Python users rely on for SPSS files. Codes, labels, dates and missing values come through as shown above.
How large a file can it open?
Up to 50 MB and 1,000,000 rows per file. For larger files, keep only the variables you need in PSPP, R or Python first.
Can I save a .sav file?
No. Exports are CSV, JSON, Excel or Parquet.
Is respondent data uploaded?
No. The file is read inside your browser, and after the page has loaded it makes no network requests — check it in about a minute. For work under a data-sharing agreement, see working with client data under an NDA.