CSV sang SQL
Tạo câu lệnh SQL INSERT từ dữ liệu CSV
Đầu vào CSV
Đầu ra SQL
Chuyển đổi CSV sang SQL là gì?
Chuyển đổi CSV sang SQL biến các giá trị phân tách bằng dấu phẩy thành các câu lệnh Ngôn ngữ Truy vấn Có cấu trúc mà cơ sở dữ liệu quan hệ có thể thực thi. Đầu ra phổ biến nhất là một cặp: câu lệnh CREATE TABLE định nghĩa các cột, và một hoặc nhiều câu lệnh INSERT INTO điền dữ liệu từ các hàng trong tệp CSV vào các cột đó.
Tệp CSV tuân theo đặc tả RFC 4180. Mỗi dòng là một bản ghi, các trường được phân tách bằng dấu phân cách (thường là dấu phẩy), và các trường chứa dấu phân cách hoặc ký tự xuống dòng được bao trong dấu ngoặc kép. SQL, mặt khác, là ngôn ngữ chuẩn để quản lý dữ liệu trong các hệ thống như PostgreSQL, MySQL, SQLite và SQL Server. Chuyển đổi giữa hai định dạng này là một trong những tác vụ nhập dữ liệu phổ biến nhất trong phát triển phần mềm.
Một công cụ chuyển đổi CSV sang SQL đúng chuẩn xử lý việc đặt dấu ngoặc kép, thoát dấu nháy đơn bên trong các giá trị (nhân đôi chúng thành '' theo tiêu chuẩn SQL), ánh xạ tiêu đề cột thành các định danh SQL hợp lệ, và có thể tùy chọn suy luận kiểu dữ liệu. Ngoài việc thoát ký tự cơ bản, một công cụ tốt còn chuẩn hóa tên tiêu đề (thay thế dấu cách và dấu gạch ngang bằng dấu gạch dưới) và bao đầu ra trong một khối giao dịch, để khi nhập thất bại sẽ khôi phục hoàn toàn thay vì để lại dữ liệu không đầy đủ trong bảng. Nếu không có công cụ chuyển đổi, việc viết tay các câu lệnh INSERT cho vài trăm hàng là rất dễ mắc lỗi và tốn thời gian.
Tại sao nên dùng công cụ chuyển CSV sang SQL?
Viết tay các câu lệnh SQL INSERT từ dữ liệu bảng tính rất tẻ nhạt và dễ gây lỗi cú pháp. Công cụ chuyển đổi tự động hóa các phần lặp lại để bạn có thể tập trung vào thiết kế lược đồ và kiểm tra dữ liệu.
Các trường hợp sử dụng CSV sang SQL
Tài liệu tham khảo kiểu dữ liệu SQL
Khi chuyển đổi CSV sang SQL, mọi cột mặc định là TEXT vì CSV không có siêu dữ liệu kiểu. Nếu bạn biết kiểu của các cột, bạn có thể thay thế TEXT trong đầu ra CREATE TABLE. Bảng này liệt kê các kiểu SQL phổ biến nhất và khi nào nên dùng mỗi kiểu.
| Kiểu | Dùng cho | Ghi chú |
|---|---|---|
| TEXT / VARCHAR | Strings, mixed content | Default safe choice; works in every SQL dialect |
| INTEGER / INT | Whole numbers (age, count, ID) | Use when column contains only digits with no decimals |
| REAL / FLOAT | Decimal numbers (price, rate) | Needed for columns with dots like 19.99 or 3.14 |
| DATE | ISO 8601 dates (2024-01-15) | Requires consistent formatting; varies by database |
| BOOLEAN | true/false, 1/0, yes/no | MySQL uses TINYINT(1); PostgreSQL has native BOOL |
| NUMERIC / DECIMAL | Exact precision (currency) | Specify scale: DECIMAL(10,2) for money columns |
| BLOB / BYTEA | Binary data | Rarely needed in CSV imports; use for hex-encoded fields |
So sánh các phương ngữ SQL
Cú pháp SQL khác nhau giữa các công cụ cơ sở dữ liệu. Các câu lệnh INSERT được tạo ra sử dụng SQL chuẩn hoạt động trong hầu hết các hệ thống, nhưng một số tính năng nhất định có sự khác biệt. Bảng này tóm tắt các khác biệt quan trọng nhất khi nhập dữ liệu CSV.
| Tính năng | PostgreSQL | MySQL | SQLite | SQL Server |
|---|---|---|---|---|
| Identifier quoting | "col" | `col` | "col" | [col] |
| String escape | '' | '' or \' | '' | '' |
| INSERT syntax | INSERT INTO | INSERT INTO | INSERT INTO | INSERT INTO |
| Batch INSERT | VALUES (),()… | VALUES (),()… | VALUES (),()… | max 1000 rows |
| Auto-increment | SERIAL | AUTO_INCREMENT | AUTOINCREMENT | IDENTITY(1,1) |
| Upsert / merge | ON CONFLICT | ON DUPLICATE KEY | ON CONFLICT | MERGE |
| NULL handling | IS NULL | IS NULL / <=> | IS NULL | IS NULL |
| COPY from CSV | COPY … FROM | LOAD DATA INFILE | .import | BULK INSERT |
INSERT vs COPY: Chọn phương thức nhập dữ liệu
Đối với các tập dữ liệu nhỏ đến trung bình (dưới 10.000 hàng), các câu lệnh INSERT hoạt động tốt và có thể dùng trên mọi cơ sở dữ liệu SQL. Đối với các lần nhập lớn, cơ sở dữ liệu cung cấp các lệnh tải hàng loạt bỏ qua hoàn toàn trình phân tích cú pháp SQL.
Ví dụ mã nguồn
Các ví dụ này minh họa cách chuyển đổi CSV sang câu lệnh SQL INSERT trong các ngôn ngữ khác nhau. Mỗi ví dụ xử lý việc thoát dấu nháy đơn và làm sạch tên cột.
// CSV → SQL INSERT statements
const csv = `name,age,city
Alice,30,Berlin
Bob,25,Tokyo`
function csvToSql(csv, table = 'data') {
const rows = csv.trim().split('\n').map(r => r.split(','))
const [headers, ...data] = rows
const cols = headers.map(h => h.trim().toLowerCase().replace(/\s+/g, '_'))
const values = data.map(row =>
' (' + row.map(v => `'${v.replace(/'/g, "''").trim()}'`).join(', ') + ')'
)
return `INSERT INTO ${table} (${cols.join(', ')}) VALUES
${values.join(',\n')};`
}
console.log(csvToSql(csv, 'users'))
// → INSERT INTO users (name, age, city) VALUES
// ('Alice', '30', 'Berlin'),
// ('Bob', '25', 'Tokyo');import csv
import io
csv_string = """name,age,city
Alice,30,Berlin
Bob,25,Tokyo"""
reader = csv.reader(io.StringIO(csv_string))
headers = [h.strip().lower().replace(' ', '_') for h in next(reader)]
table = 'users'
rows = list(reader)
# CREATE TABLE
col_defs = ', '.join(f'{h} TEXT' for h in headers)
print(f'CREATE TABLE {table} ({col_defs});')
# → CREATE TABLE users (name TEXT, age TEXT, city TEXT);
# INSERT statements
for row in rows:
vals = ', '.join(f"'{v.replace(chr(39), chr(39)*2)}'" for v in row)
print(f"INSERT INTO {table} ({', '.join(headers)}) VALUES ({vals});")
# → INSERT INTO users (name, age, city) VALUES ('Alice', '30', 'Berlin');
# → INSERT INTO users (name, age, city) VALUES ('Bob', '25', 'Tokyo');package main
import (
"encoding/csv"
"fmt"
"strings"
)
func csvToSQL(data, table string) string {
r := csv.NewReader(strings.NewReader(data))
records, _ := r.ReadAll()
if len(records) < 2 {
return ""
}
headers := records[0]
var vals []string
for _, row := range records[1:] {
escaped := make([]string, len(row))
for i, v := range row {
escaped[i] = "'" + strings.ReplaceAll(v, "'", "''") + "'"
}
vals = append(vals, " ("+strings.Join(escaped, ", ")+")")
}
return fmt.Sprintf("INSERT INTO %s (%s) VALUES\n%s;",
table, strings.Join(headers, ", "), strings.Join(vals, ",\n"))
}
func main() {
csv := "name,age,city\nAlice,30,Berlin\nBob,25,Tokyo"
fmt.Println(csvToSQL(csv, "users"))
// → INSERT INTO users (name, age, city) VALUES
// ('Alice', '30', 'Berlin'),
// ('Bob', '25', 'Tokyo');
}# SQLite: import CSV directly into a table sqlite3 mydb.db <<EOF .mode csv .import data.csv users SELECT * FROM users LIMIT 5; EOF # PostgreSQL: COPY from CSV file (server-side) psql -c "COPY users FROM '/path/to/data.csv' WITH (FORMAT csv, HEADER true);" # PostgreSQL: \copy from CSV (client-side, no superuser needed) psql -c "\copy users FROM 'data.csv' WITH (FORMAT csv, HEADER true);" # MySQL: LOAD DATA from CSV mysql -e "LOAD DATA INFILE '/path/to/data.csv' INTO TABLE users FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 ROWS;"