CSV to SQL
Генерация SQL INSERT-запросов из CSV-данных
Входные данные CSV
SQL-вывод
Что такое конвертация CSV в SQL?
Конвертация CSV в SQL преобразует значения, разделённые запятыми, в инструкции Structured Query Language, которые может выполнить реляционная база данных. Наиболее распространённый результат — пара команд: инструкция CREATE TABLE, определяющая столбцы, и одна или несколько инструкций INSERT INTO, заполняющих эти столбцы строками из CSV-файла.
CSV-файлы соответствуют спецификации RFC 4180. Каждая строка является записью, поля разделяются разделителем (обычно запятой), а поля, содержащие разделитель или переносы строк, заключаются в двойные кавычки. SQL, в свою очередь, является стандартным языком для управления данными в таких системах, как PostgreSQL, MySQL, SQLite и SQL Server. Преобразование между этими двумя форматами — одна из наиболее частых задач импорта данных в разработке программного обеспечения.
Полноценный конвертер CSV-в-SQL обрабатывает кавычки, экранирует одинарные кавычки внутри значений (удваивая их до '' согласно стандарту SQL), сопоставляет заголовки столбцов с допустимыми SQL-идентификаторами и при необходимости определяет типы данных. Помимо базового экранирования, хороший конвертер нормализует имена заголовков (заменяя пробелы и дефисы на знаки подчёркивания) и оборачивает вывод в блок транзакции, чтобы при сбое импорта выполнялся откат без сохранения частичных данных в таблице. Без конвертера ручное написание INSERT-инструкций даже для нескольких сотен строк — трудоёмкий и ненадёжный процесс.
Зачем использовать конвертер CSV в SQL?
Писать SQL INSERT-инструкции вручную из данных электронных таблиц утомительно и чревато синтаксическими ошибками. Конвертер автоматизирует рутинную работу, позволяя сосредоточиться на проектировании схемы и проверке данных.
Сценарии использования CSV to SQL
Справочник по типам данных SQL
При конвертации CSV в SQL каждый столбец по умолчанию получает тип TEXT, поскольку в CSV нет метаданных о типах. Если вы знаете типы столбцов, замените TEXT в выводе CREATE TABLE. В таблице ниже приведены наиболее распространённые типы SQL и когда их применять.
| Тип | Применяется для | Примечания |
|---|---|---|
| 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 |
Сравнение диалектов SQL
Синтаксис SQL различается между движками баз данных. Сгенерированные INSERT-инструкции используют стандартный SQL, работающий в большинстве систем, однако некоторые возможности различаются. В таблице описаны ключевые отличия, важные при импорте CSV-данных.
| Возможность | 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: выбор метода импорта
Для небольших и средних наборов данных (до 10 000 строк) INSERT-инструкции работают хорошо и совместимы с любой SQL-базой данных. Для больших импортов базы данных предоставляют команды массовой загрузки, минующие SQL-парсер.
Примеры кода
Примеры ниже показывают, как конвертировать CSV в SQL INSERT-инструкции на разных языках программирования. Каждый из них обрабатывает экранирование одинарных кавычек и нормализацию имён столбцов.
// 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;"