OmniSelect FileSQL

Guides
← Back to App
HomeGuides › Joining two CSV files

How to Join Two CSV Files Using SQL

You have two CSV files that share a column — orders and customers, transactions and accounts, employees and departments — and you need them side by side. This is a database join, and you can do it without a database.

The Usual Options, and Why They Grate

ApproachThe problem with it
Excel VLOOKUP / XLOOKUPWorks, but you are writing one formula per column you want to pull across, then copying it down thousands of rows. It breaks silently when the lookup column is not the leftmost, when types do not match, or when someone sorts the sheet. Fine for one column; miserable for eight.
Python and pandasThe right tool if you already have it. Installing Python, pip and pandas to combine two files once is a lot of ceremony for a ten-minute job.
Load into a real databaseCorrect and robust. Also means a server, a schema, CREATE TABLE statements, an import step, and usually somebody else's permission.
An online CSV merge toolQuick — but you are uploading both files to a stranger's server, which is often not allowed and rarely checked.

There is a fourth option: write the SQL you already know, and have it run in your browser against the files directly.

The Example

Two files. orders.csv:

order_id,customer_id,amount,status
1001,C001,250.00,paid
1002,C003,89.50,pending
1003,C001,410.00,paid
1004,C002,15.75,refunded
1005,C004,120.00,paid

And customers.csv:

customer_id,name,city
C001,Acme Ltd,Austin
C002,Borden Group,Denver
C003,Castle Co,Austin
C005,Delta Partners,Boston

They share customer_id. Note that order 1005 refers to C004, who is not in the customer list, and that customer C005 has no orders. Real data always looks like this, and which join you pick decides what happens to those two.

Step by Step

  1. Open the tool. Go to the main page. Nothing to install.
  2. Drop both files in at once. Drag them together onto the File Select panel.
  3. Check the aliases. Each file becomes a SQL table named by a single letter, shown in the Alias column. The letter comes from the start of the filename — orders.csv becomes O, customers.csv becomes C. If two files would claim the same letter, the second is given another free one. Glance at that column before writing anything, and type a different letter if you would rather have one.
  4. Write the join.
    SELECT O.order_id, C.name, C.city, O.amount, O.status
    FROM O
    JOIN C ON O.customer_id = C.customer_id
  5. Run it with the Run Query button or Ctrl+Enter.

Four rows come back — every order whose customer exists in the second file:

order_idnamecityamountstatus
1001Acme LtdAustin250paid
1002Castle CoAustin89.5pending
1003Acme LtdAustin410paid
1004Borden GroupDenver15.75refunded

Order 1005 is gone, because customer C004 does not exist in customers.csv. That is a plain JOIN — also written INNER JOIN — doing exactly what it is supposed to: keep only rows that match on both sides.

💡 Notice that 250.00 came back as 250. Columns that look numeric are treated as numbers, so trailing zeros in the source text are not preserved — which is what lets you write WHERE amount > 100 without quoting. Values that would be damaged by that, like a reference such as 00042, are deliberately left as text instead.

Try it with your own two files.

Open the tool →

Keeping the Unmatched Rows

Dropping order 1005 is usually not what you want — an order with a missing customer record is precisely the thing worth finding. Use a LEFT JOIN to keep every row from the left-hand file regardless:

SELECT O.order_id, C.name, O.amount
FROM O
LEFT JOIN C ON O.customer_id = C.customer_id

Now all five orders come back, and order 1005 has an empty name. To list only the broken ones:

SELECT O.order_id, O.customer_id, O.amount
FROM O
LEFT JOIN C ON O.customer_id = C.customer_id
WHERE C.customer_id IS NULL

That is a data-quality report, written in three lines, that VLOOKUP makes genuinely awkward.

Which Join to Use

JoinKeepsUse it when
JOIN (inner)Only rows matching on both sidesYou want complete records and nothing else
LEFT JOINEverything from the table named before LEFT JOIN; blanks where the other has no matchThat file is your source of truth and you are enriching it
💡 A good habit: start with LEFT JOIN, count the blanks, then decide. If you begin with an inner join you will never see what you quietly threw away.

Going Further Than a Lookup

Once the files are joined, everything else in SQL is available. Total paid revenue per city, for example:

SELECT C.city, COUNT(*) AS order_count, SUM(O.amount) AS revenue
FROM O
JOIN C ON O.customer_id = C.customer_id
WHERE O.status = 'paid'
GROUP BY C.city
ORDER BY revenue DESC

Doing that with lookup formulas means a helper column, a pivot table, and a filter that somebody will forget to update. Here it is one query.

When a Join Returns Nothing

An empty result is the classic frustration. It is almost always one of these four, and all are quick to check.

1. The values do not actually match

Trailing spaces and differing case are the usual culprits — "C001 " and "C001" are different strings. Look first:

SELECT customer_id FROM O LIMIT 10

Then force both sides into the same shape:

SELECT O.order_id, C.name
FROM O
JOIN C ON UPPER(TRIM(O.customer_id)) = UPPER(TRIM(C.customer_id))

2. One side is a number and the other is text

Numeric-looking values are detected as numbers automatically, so WHERE id = 42 works without quotes. But if one file has 00042 — which is kept as text, because stripping the leading zeros would corrupt it — and the other has 42, they will not match. Line them up explicitly:

SELECT O.order_id, C.name
FROM O
JOIN C ON CAST(O.customer_id AS STRING) = CAST(C.customer_id AS STRING)

3. You guessed the alias letters

This catches people out more than anything else on this list. The alias is not simply A for the first file you added — it is derived from the filename, so orders.csv is O. Write a query against A and B out of habit and you get an error about an unknown table, or worse, you join the wrong pair. The Alias column in the File Select panel is the authority, and the letter is editable.

4. The column name is ambiguous

When both files have a column called customer_id, always qualify it — O.customer_id, not bare customer_id. Unqualified, it is genuinely unclear which file you mean.

A Note on Duplicates

If the right-hand file has more than one row per key, a join multiplies rows: two matching customer rows for one order produces two output rows, and your totals silently double. Check before you trust the numbers:

SELECT customer_id, COUNT(*) AS n
FROM C
GROUP BY customer_id
HAVING COUNT(*) > 1

If that returns anything, deduplicate or tighten the join condition before reporting any sums.

Exporting the Result

Click Export in the Query Results panel and choose CSV, JSON, Excel or Parquet. The file is generated in your browser and saved straight to your downloads folder.

Where the Files Go

Nowhere. Both CSVs are read and joined inside your browser tab; neither is transmitted to any server. You can confirm this by loading the page, disconnecting from the network entirely, and then doing the whole join offline — it works. See querying without uploading for the full explanation.

Two files, one query, nothing uploaded.

Open the tool →

Related Guides