All posts
    Guideshow to remove duplicate rows from a csv file

    How to Remove Duplicate Rows From a CSV File: 6 Methods Ranked by File Size (2026)

    Remove duplicate rows from any CSV file: Excel, Google Sheets, Python pandas, command line, and SQL. Pick the right method by file size and keep the row you want.

    November 2, 202613 min readCarbonApps Team

    Most guides send you straight to Excel's Remove Duplicates button. That button works fine on a 500 row list and quietly damages a 500,000 row export, mangling leading zeros, rewriting dates, and chopping off rows past Excel's limit without telling you. Before you pick a tool, answer two questions: how big is the file, and what actually counts as a duplicate.

    First decide what "duplicate" actually means

    Every method below does the same basic thing: it compares rows and keeps one copy. What changes is how you define "same," and getting that definition wrong is the single most common way people delete the wrong data.

    Whole-row duplicates vs. duplicates on one key column

    A whole-row duplicate means every single field matches, name, date, amount, everything. That's rare in real exports. Far more common is a duplicate on one key column, like the same order ID or email address appearing twice with slightly different timestamps or totals. If you dedupe on the whole row when you really needed to dedupe on just the order ID, you'll keep every near-miss row and the duplicates will survive.

    Exact match vs. case/whitespace/trailing-space differences

    "[email protected]" and "[email protected] " (with a trailing space) are the same email address to a human and two different strings to most deduplication tools. Decide upfront whether you need case-insensitive, whitespace-trimmed matching, because the default in Excel, Google Sheets, and SQL is a strict character-for-character comparison.

    Which copy do you keep: first, last, or most complete?

    When two rows represent the same record, one of them is usually better, a more recent timestamp, a filled-in phone number, a corrected spelling. Decide which copy wins before you run anything. "First" and "last" are easy to automate; "most complete" usually needs a manual pass or a custom rule (keep the row with fewer blank fields).

    Method 1: Excel (for files under about 100,000 rows)

    Excel is fine for small, one-off cleanups. It becomes risky the moment your file approaches its row ceiling or contains data types Excel likes to "fix" for you.

    Using Data > Remove Duplicates and choosing the right columns

    Select your data, open the Data tab, and choose Remove Duplicates. Excel lets you check or uncheck individual columns, which is exactly the whole-row-vs-key-column decision from above: check only the columns that define a duplicate for your use case, not every column in the sheet.

    The leading-zero, long-number, and date-format traps before you save back to CSV

    Excel auto-formats cells the moment it opens a CSV, and that formatting can change the underlying value when you save back out.

    What's in the CSVWhat Excel shows after openingWhat gets saved back to CSV
    ZIP code "00501"501501 (leading zeros gone)
    Account number "1234567890123"1.23457E+12Scientific notation, precision lost
    Date "2026-03-01"3/1/2026 (locale-dependent)Reformatted date string

    If your file has any of these, format the affected columns as Text before you open the CSV, or avoid Excel for that file entirely. Microsoft's own guidance on importing and exporting CSV files covers these conversions in more depth.

    Why Excel's row cap and silent truncation make it risky for big exports

    Excel has a hard row limit per sheet. A CSV export larger than that limit gets truncated on open, with no dialog telling you rows were dropped, so you could "successfully" dedupe a file that was already missing a chunk of its data before you started. Treat Excel as a small-file tool, not a safety net for anything you haven't already verified is under that limit.

    Method 2: Google Sheets with UNIQUE() (shareable, no install)

    Google Sheets avoids the row cap problem of Excel for midsize files and keeps a formula-based audit trail instead of a one-click destructive action.

    The =UNIQUE() formula and when it beats Remove Duplicates

    The UNIQUE function returns a new range of only the distinct rows from a source range, leaving your original data untouched. That matters: if the formula result looks wrong, your source data is still there to fix and retry, unlike an in-place Remove Duplicates click.

    Deduplicating on specific columns with QUERY or UNIQUE ranges

    To dedupe on one key column instead of the whole row, wrap UNIQUE around just that column, or pair it with QUERY to pull back the full row for each distinct key. This is the Sheets equivalent of Excel's column checkboxes, just formula-driven and easier to audit.

    Re-exporting cleanly to .csv without re-introducing dupes

    Once UNIQUE() has produced your clean range, copy it, paste as values into a new sheet, and export that sheet as CSV. Exporting the tab that still contains the original formula and source data will just re-export the duplicates alongside the UNIQUE() output.

    Method 3: Python pandas drop_duplicates() (the workhorse)

    For anything repeatable, or any file where you don't trust a spreadsheet to preserve your data types, pandas is the most reliable general-purpose tool.

    A copy-paste script: read_csv, drop_duplicates, to_csv

    import pandas as pd
    
    df = pd.read_csv("input.csv", dtype=str)
    df = df.drop_duplicates()
    df.to_csv("output.csv", index=False)
    

    Reading every column as a string (dtype=str) with read_csv is what stops pandas from doing the same leading-zero and scientific-notation damage Excel does, since nothing gets silently reinterpreted as a number.

    subset= to dedupe on key columns and keep='first'/'last'

    df = df.drop_duplicates(subset=["order_id"], keep="last")
    

    subset targets specific key columns instead of the whole row, and keep controls which copy survives, "first", "last", or False to drop every duplicate including the original.

    Handling whitespace and case before you drop (str.strip, str.lower)

    df["email"] = df["email"].str.strip().str.lower()
    df = df.drop_duplicates(subset=["email"])
    

    Normalize with str.strip() and str.lower() before deduping on a text column, otherwise " [email protected]" and "[email protected]" will both survive as separate rows.

    Method 4: Command line with sort and awk (for files too big to open)

    When a file is too large for Excel, Sheets, or even pandas to load comfortably into memory, standard Unix tools can stream through it line by line.

    sort -u and when it's safe (and when it reorders your rows)

    sort -u data.csv > deduped.csv
    

    sort -u is fast and memory-efficient, but it alphabetizes your rows as a side effect, which also risks moving your header row out of position. It's a good fit when row order genuinely doesn't matter and you re-add the header afterward.

    awk '!seen[$0]++' to dedupe while preserving original order

    awk '!seen[$0]++' data.csv > deduped.csv
    

    This one-liner, documented in the broader GNU awk manual, keeps the first occurrence of each line and preserves the original row order, which makes it the better default over sort -u for most CSV cleanup jobs.

    Method 5: csvkit for header-aware CSV cleanup

    Plain sort and awk treat every line as an undifferentiated string, including the header row. csvkit is a set of command line tools built specifically for CSV, so it understands columns and headers instead of raw text lines.

    Installing csvkit and why header-awareness matters

    csvkit installs as a Python package (pip install csvkit) and gives you commands like csvsort and csvformat that operate on named columns, which means you can sort or dedupe by a specific field without the header row getting treated as just another line of data.

    csvsort and csvformat for normalizing before dedupe

    Run csvformat first to normalize delimiters and encodings, then csvsort on your key column to group matching values together, which makes it far easier to spot or script around the surviving duplicates in a file too large to open in a spreadsheet.

    Method 6: SQL (when the data already lives in a database)

    If the CSV is really just an export of a database table, dedupe at the source instead of round-tripping through a spreadsheet or script.

    SELECT DISTINCT vs. GROUP BY for row- and column-level dedupe

    ApproachDeduplicates onKeeps which rowBest for
    SELECT DISTINCTWhole rowN/A, rows are identicalExact whole-row duplicates
    GROUP BYChosen key columnsOne row per group (needs an aggregate)Dedupe on a subset of columns
    ROW_NUMBER() OVER (PARTITION BY ...)Chosen key columnsWhichever row you rank firstKeeping the newest or "best" record

    SELECT DISTINCT only removes rows that are identical across every selected column. GROUP BY collapses rows that share the same key columns but needs an aggregate function (MIN, MAX, COUNT) to decide what happens to the other columns.

    ROW_NUMBER() OVER (PARTITION BY ...) to keep the newest record

    WITH ranked AS (
      SELECT *,
        ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY updated_at DESC) AS rn
      FROM orders_raw
    )
    SELECT * FROM ranked WHERE rn = 1;
    

    This pattern, built on the window functions available in PostgreSQL and most modern databases, is the closest SQL equivalent to pandas' keep="last": it lets you explicitly choose which duplicate survives instead of relying on whatever order the database happens to store rows in.

    Exporting the deduped result back out to CSV

    Most database clients have a COPY or \copy command, or a GUI export button, that writes a query result straight to CSV. Export the final deduped query, not the raw table, so the duplicates never make it back into the file.

    Pick your method in 30 seconds

    If you only read one section, read this one and go fix your file.

    The decision cheat sheet: file size x dedupe type to tool

    File sizeWhole-row duplicatesDedupe on one key column
    Under ~100k rowsExcel Remove DuplicatesExcel, checking only the key column
    Shareable, team-editedGoogle Sheets UNIQUE()Sheets UNIQUE() + QUERY
    Any size, repeatable jobPython pandas drop_duplicates()pandas with subset=
    Too large to open anywhereawk '!seen[$0]++'csvkit (csvsort + custom script)
    Already in a databaseSQL SELECT DISTINCTSQL ROW_NUMBER() OVER (PARTITION BY)
    MethodHandles huge filesPreserves data types (zeros, long numbers)Needs install
    ExcelNoNoNo
    Google SheetsNoPartialNo
    Python pandasYesYesYes
    Command line (sort/awk)YesYesNo (built in on Mac/Linux)
    csvkitYesYesYes
    SQLYesYesDepends on existing database

    Clean your messy export now

    If you're staring at a messy export right now, match your file size and dedupe type to the table above, run the matching command or formula from the method section, then verify the result before you trust it anywhere downstream.

    Verify the result and avoid re-introducing duplicates

    Deduplication isn't done the moment a tool finishes running. Confirm it actually did what you intended.

    Count rows before and after so you know what was removed

    Run a row count on the original file and the output file (wc -l on the command line, COUNTA in a spreadsheet, len(df) in pandas). If the difference is zero, your match criteria were too strict; if it's suspiciously large, you may have deduped on the wrong column.

    Spot-check near-duplicates the tools missed (encoding, hidden characters)

    Two rows can look identical and still fail an exact match because of invisible differences: a non-breaking space instead of a regular space, mismatched line endings, or different text encodings. Open a handful of suspicious rows in a plain text editor rather than a spreadsheet, which tends to hide these characters.

    Trailing spaces, case, and the wrong key column deleting valid records

    This is where most bad dedupes come from: trimming and lowercasing too aggressively and merging two genuinely different records (two different people with similar emails), or deduping on a key column that isn't actually unique to a single real-world entity (like deduping customers by name alone). Re-check your key column choice against a few rows you know should stay separate.

    Fix the upstream source so the dupes don't come back

    If the same CSV export keeps arriving with duplicates, the fix belongs upstream: a missing unique constraint in the source database, a form that allows resubmission, or an export job that runs twice. Cleaning the CSV every time is a workaround, not a fix.

    Frequently asked questions

    What's the difference between removing fully duplicate rows and removing duplicates based on one column? A fully duplicate row matches on every column; deduping on one column (like an email or order ID) treats two rows as duplicates even if other fields differ, and you have to decide which of those differing rows to keep.

    How do I remove duplicate rows from a CSV that's too large to open in Excel? Use a command line tool like awk '!seen[$0]++' for order-preserving dedupe, sort -u when order doesn't matter, or load it with Python pandas, none of which need to hold the whole file in a spreadsheet grid.

    Will removing duplicates in Excel change my dates, leading zeros, or long ID numbers? It can. Excel reformats numbers and dates on import and export, so account numbers can turn into scientific notation and ZIP codes can lose leading zeros unless you format those columns as text first.

    How can I keep the most recent (or most complete) row when removing duplicates? In pandas, sort by your date column first, then use drop_duplicates(keep="last"). In SQL, use ROW_NUMBER() OVER (PARTITION BY key ORDER BY date DESC) and keep only rn = 1.

    How do I remove duplicates that only differ by capitalization or extra spaces? Normalize first: str.strip() and str.lower() in pandas, TRIM() and LOWER() in SQL, or a helper column in a spreadsheet, then dedupe on the normalized version.

    Does sort -u or SELECT DISTINCT change the order of my rows? sort -u always reorders rows alphabetically. SELECT DISTINCT doesn't guarantee any particular order unless you add an explicit ORDER BY. If order matters, use awk '!seen[$0]++' or add an explicit sort afterward.

    How do I check how many duplicate rows were actually removed? Compare row counts before and after with wc -l, COUNTA, or len(df). If the number removed doesn't match your expectation, re-check whether you deduped on the right column with the right matching rules.

    There's no single best way to remove duplicate rows from a CSV, there's only the method that matches your file size and your actual definition of a duplicate. Get those two answers right first, and whichever tool from Excel to SQL you reach for next will do the job correctly the first time.

    Work with the studio

    CarbonApps is an independent venture studio in Los Angeles.

    Get in touch