Free tutorials & notes in Hindi & English · Clean code examples · Mobile friendly learning
MySQL + SQL · Lesson 106

Import and Export CSV in MySQL

Design the CSV Contract Before Importing

CSV is a delimited text exchange format, not a database backup. Before loading, define the file contract: UTF-8 encoding, column order, header presence, comma delimiter, quote/escape rule, line ending, date format, decimal symbol, NULL representation and duplicate policy.

DecisionExample contract
EncodingUTF-8 without BOM
HeaderOne row, fixed names
DatesYYYY-MM-DD
Blank emailSQL NULL
Duplicate IDReject, do not overwrite silently
Safe pipeline: receive → checksum and scan → load into a staging table → validate → transform in a transaction → reconcile counts/totals → archive or delete according to policy.

Spreadsheet programs can change long IDs, dates and leading zeros. Treat an uploaded CSV as untrusted input and never build SQL from its filename or field values.

Create a Reproducible Import Lab

DROP TABLE IF EXISTS students_csv_lab;
CREATE TABLE students_csv_lab (
  student_id INT PRIMARY KEY,
  student_name VARCHAR(80) NOT NULL,
  email VARCHAR(190) NULL,
  admission_date DATE NOT NULL,
  fee DECIMAL(10,2) NOT NULL,
  CHECK (fee >= 0)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Save this approved sample as students.csv using UTF-8 and LF line endings:

student_id,student_name,email,admission_date,fee
101,"Aman Verma",aman@example.test,2026-04-01,1250.00
102,"Sara, Khan",,2026-04-02,1500.50
103,"Kabir Rao",kabir@example.test,2026-04-03,900.00

The quoted comma in Sara's name tests enclosure handling; her blank email must become SQL NULL. Expected result is three rows and total fee 3650.50.

Import a Trusted Client File with LOAD DATA LOCAL

LOCAL means the client program reads the file and transfers it to MySQL. The server and client must both permit the capability. With the mysql client, enable it only for this trusted operation:

mysql --login-path=importer --local-infile=1 \
  --ssl-mode=VERIFY_IDENTITY --ssl-ca=/approved/ca.pem school
LOAD DATA LOCAL INFILE '/approved/import/students.csv'
INTO TABLE students_csv_lab
CHARACTER SET utf8mb4
FIELDS TERMINATED BY ','
  OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(@id,@name,@email,@date,@fee)
SET student_id=CAST(TRIM(@id) AS UNSIGNED),
    student_name=TRIM(@name),
    email=NULLIF(TRIM(@email),''),
    admission_date=STR_TO_DATE(TRIM(@date),'%Y-%m-%d'),
    fee=CAST(TRIM(BOTH '\r' FROM @fee) AS DECIMAL(10,2));

Use forward slashes or correctly escaped paths. If the file uses CRLF, declare LINES TERMINATED BY '\r\n' instead of compensating in the last field. A format mismatch can shift columns or retain carriage returns.

LOCAL security: connect only to a trusted, identity-verified server. Restrict the client to an approved directory where supported; never let arbitrary web input select a local path.

Use Variables and a Staging Table for Safe Conversion

User variables let the loader receive text before assigning typed columns. For production, an all-text staging table is even safer because every source row can be retained with batch and line metadata:

CREATE TABLE student_import_stage (
  batch_id CHAR(36) NOT NULL,
  source_line INT NOT NULL,
  raw_id VARCHAR(40), raw_name VARCHAR(200),
  raw_email VARCHAR(250), raw_date VARCHAR(40),
  raw_fee VARCHAR(60),
  validation_error VARCHAR(500),
  PRIMARY KEY(batch_id,source_line)
) ENGINE=InnoDB;

Validate in staging, then transform valid rows:

INSERT INTO students_csv_lab
  (student_id,student_name,email,admission_date,fee)
SELECT CAST(raw_id AS UNSIGNED), TRIM(raw_name),
       NULLIF(TRIM(raw_email),''),
       STR_TO_DATE(raw_date,'%Y-%m-%d'),
       CAST(raw_fee AS DECIMAL(10,2))
FROM student_import_stage
WHERE batch_id=@batch AND validation_error IS NULL;

Do not use REPLACE or broad ON DUPLICATE KEY UPDATE until the business owner has approved how duplicates merge. A rejected-row report is safer than silent coercion.

Validate Counts, Warnings and Business Totals

SHOW WARNINGS LIMIT 100;
SELECT COUNT(*) AS imported_rows,
       SUM(fee) AS total_fee,
       SUM(email IS NULL) AS missing_email
FROM students_csv_lab;

SELECT student_id,student_name,email,admission_date,fee
FROM students_csv_lab ORDER BY student_id;
imported_rows=3 | total_fee=3650.50 | missing_email=1 101 Aman Verma | 102 Sara, Khan | 103 Kabir Rao

Check warnings immediately in the same session. Strict SQL mode and table constraints help, but they do not understand business rules. Validate:

  • exact header and column count;
  • file size, row limit and allowed encoding;
  • IDs, dates, decimals, email length and mandatory values;
  • duplicates within the file and against live data;
  • expected counts, sums and sampled records;
  • authorization for the destination school/class/tenant.

Load to a new batch, reconcile it, and commit the final merge as one controlled transaction when possible. Keep sensitive rejected rows out of public logs.

Understand Server-Side INFILE and secure_file_priv

SHOW VARIABLES LIKE 'secure_file_priv';

LOAD DATA INFILE '/var/lib/mysql-files/students.csv'
INTO TABLE students_csv_lab
CHARACTER SET utf8mb4
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n' IGNORE 1 LINES;

Without LOCAL, the MySQL server process reads a server-host file. The account needs the powerful global FILE privilege and the operating-system account must be able to read the file. secure_file_priv behaves as follows:

ValueEffect
DirectoryServer-side import/export restricted there
NULLServer-side file operations disabled
EmptyNo directory restriction; insecure

Avoid granting FILE to normal application accounts. Managed hosting may disable server-side operations; use an approved client/application import instead.

Export Query Results with INTO OUTFILE

SELECT student_id,student_name,email,
       DATE_FORMAT(admission_date,'%Y-%m-%d') AS admission_date,
       fee
FROM students_csv_lab
ORDER BY student_id
INTO OUTFILE '/var/lib/mysql-files/students_export.csv'
CHARACTER SET utf8mb4
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n';

The server writes this file, so FILE privilege, OS permissions and secure_file_priv apply. MySQL refuses to overwrite an existing file. The statement does not add a header row. Use a controlled application/ETL library when headers, RFC-specific quoting, streaming downloads, authorization or cloud storage are required.

Before sharing an export, apply row-level authorization, select only required columns, mask sensitive values, spreadsheet-formula injection controls, encryption and expiry. CSV is not a substitute for backup and recovery.

Production CSV Checklist

  1. Publish a versioned CSV contract and sample.
  2. Use a random server-side storage name outside the web root.
  3. Check extension, size and content; never trust MIME alone.
  4. Use UTF-8, explicit charset, delimiter, enclosure and line ending.
  5. Prefer staging; validate before touching live tables.
  6. Run with least privilege and verified TLS.
  7. Capture batch ID, counts, warnings, checksum and operator.
  8. Reconcile totals and sample records; make retries idempotent.
  9. Encrypt/archive or securely delete source and rejected rows.
  10. Test commas, quotes, Unicode, blank values, CRLF/LF and duplicates.

Review user privileges, transactions and database security before production use.

Official References

File location, LOCAL capability, formatting and export behavior were checked against the official MySQL manual. Confirm the deployed client/server version and hosting policy.

Frequently Asked Questions

What is the difference between LOAD DATA INFILE and LOAD DATA LOCAL INFILE?
Without LOCAL, the MySQL server reads a server-host file and the account needs FILE privilege; secure_file_priv can restrict its directory. With LOCAL, the client reads and sends a client-host file, so both client and server must permit LOCAL loading.
How do I skip a CSV header row in MySQL?
Use IGNORE 1 LINES after the FIELDS and LINES clauses. Inspect the file first because a headerless file would lose its first data row.
How should blank CSV values become SQL NULL?
Load fields into user variables and assign NULLIF(TRIM(variable), empty-string) in the SET clause. Use a staging table when validation or business rules are more complex.
Why does LOAD DATA LOCAL report error 3950?
LOCAL loading is disabled on the server, client, connector, or more than one of them. Enable it only for a trusted workflow, preferably restrict the permitted local directory, and verify the server identity with TLS.
Does SELECT INTO OUTFILE add CSV column headings?
No. It writes selected rows using the specified delimiters. Generate a separately controlled header or use an application/export tool that implements the exact CSV contract.
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

💻 Live Code Editor

This page's programs are ready here — run them, edit them, and learn. No installation needed.
Powered by OneCompiler. The code loads into the editor automatically — press Run to see the output. If the editor does not open, open it in a new tab.