CSV to SQL
Generujte SQL INSERT příkazy z CSV dat
CSV vstup
SQL výstup
Co je převod CSV na SQL?
Převod CSV na SQL transformuje hodnoty oddělené čárkami na příkazy Structured Query Language, které může vykonat relační databáze. Nejběžnějším výstupem je dvojice: příkaz CREATE TABLE, který definuje sloupce, a jeden nebo více příkazů INSERT INTO, které naplní tyto sloupce řádky z CSV souboru.
CSV soubory se řídí specifikací RFC 4180. Každý řádek je záznam, pole jsou oddělena oddělovačem (zpravidla čárkou) a pole obsahující oddělovač nebo konce řádků jsou uzavřena do dvojitých uvozovek. SQL je naproti tomu standardní jazyk pro správu dat v systémech jako PostgreSQL, MySQL, SQLite a SQL Server. Převod mezi těmito dvěma formáty patří k nejčastějším úlohám importu dat při vývoji softwaru.
Správný CSV-to-SQL převodník zvládá uvozování, escapuje jednoduché uvozovky uvnitř hodnot (jejich zdvojením na '' podle standardu SQL), mapuje záhlaví sloupců na platné SQL identifikátory a volitelně dokáže odvodit datové typy. Kromě základního escapování dobrý převodník normalizuje názvy záhlaví (nahrazuje mezery a pomlčky podtržítky) a obaluje výstup do transakčního bloku, takže při selhání importu dojde k čistému vrácení změn místo ponechání neúplných dat v tabulce. Bez převodníku je ruční psaní příkazů INSERT pro i jen několik set řádků náchylné k chybám a zdlouhavé.
Proč používat převodník CSV na SQL?
Ruční psaní SQL INSERT příkazů z dat tabulkového procesoru je únavné a snadno vede k syntaktickým chybám. Převodník automatizuje opakující se části, takže se můžete soustředit na návrh schématu a ověřování dat.
Případy použití CSV na SQL
Přehled datových typů SQL
Při převodu CSV na SQL jsou všechny sloupce ve výchozím nastavení TEXT, protože CSV neobsahuje metadata o typech. Pokud typy sloupců znáte, můžete TEXT ve výstupu CREATE TABLE nahradit. Tato tabulka ukazuje nejběžnější typy SQL a kdy každý z nich použít.
| Typ | Použití | Poznámky |
|---|---|---|
| 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 |
Porovnání SQL dialektů
Syntaxe SQL se liší mezi databázovými stroji. Generované příkazy INSERT používají standardní SQL, které funguje ve většině systémů, ale některé funkce se liší. Tato tabulka shrnuje rozdíly, které jsou při importu CSV dat nejdůležitější.
| Funkce | 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: volba metody importu
Pro malé a střední datové sady (do 10 000 řádků) příkazy INSERT fungují dobře a jsou přenositelné mezi všemi SQL databázemi. Pro velké importy poskytují databáze příkazy pro hromadné načítání, které zcela obcházejí SQL parser.
Ukázky kódu
Tyto ukázky ukazují, jak převést CSV na SQL INSERT příkazy v různých programovacích jazycích. Každá z nich zpracovává escapování jednoduchých uvozovek a sanitizaci názvů sloupců.
// 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;"