MySQL memuat nilai NULL dari data CSV


167

Saya memiliki file yang dapat berisi 3 hingga 4 kolom nilai numerik yang dipisahkan oleh koma. Bidang kosong didefinisikan dengan pengecualian ketika mereka berada di akhir baris:

1,2,3,4,5
1,2,3,,5
1,2,3

Tabel berikut dibuat di MySQL:

+ ------- + -------- + ------ + ----- + --------- + ------- +
| Bidang | Ketik | Null | Kunci | Default | Ekstra |
+ ------- + -------- + ------ + ----- + --------- + ------- +
| satu | int (1) | YA | | NULL | |
| dua | int (1) | YA | | NULL | |
| tiga | int (1) | YA | | NULL | |
| empat | int (1) | YA | | NULL | |
| lima | int (1) | YA | | NULL | |
+ ------- + -------- + ------ + ----- + --------- + ------- +

Saya mencoba memuat data menggunakan perintah MySQL LOAD:

LOAD DATA INFILE '/tmp/testdata.txt' INTO TABLE moo FIELDS 
TERMINATED BY "," LINES TERMINATED BY "\n";

Tabel yang dihasilkan:

+ ------ + ------ + ------- + ------ + ------ +
| satu | dua | tiga | empat | lima |
+ ------ + ------ + ------- + ------ + ------ +
| 1 | 2 | 3 | 4 | 5 |
| 1 | 2 | 3 | 0 | 5 |
| 1 | 2 | 3 | NULL | NULL |
+ ------ + ------ + ------- + ------ + ------ +

Masalahnya terletak pada kenyataan bahwa ketika suatu bidang kosong dalam data mentah dan tidak didefinisikan, MySQL untuk beberapa alasan tidak menggunakan nilai default kolom (yang NULL) dan menggunakan nol. NULL digunakan dengan benar ketika bidang tersebut hilang sama sekali.

Sayangnya, saya harus dapat membedakan antara NULL dan 0 pada tahap ini sehingga bantuan apa pun akan dihargai.

Terima kasih S.

sunting

Output dari MENUNJUKKAN PERINGATAN:

+ --------- + ------ + -------------------------------- ------------------------ +
| Level | Kode | Pesan |
+ --------- + ------ + -------------------------------- ------------------------ +
| Peringatan | 1366 | Nilai integer salah: '' untuk kolom 'empat' di baris 2 |
| Peringatan | 1261 | Baris 3 tidak berisi data untuk semua kolom |
| Peringatan | 1261 | Baris 3 tidak berisi data untuk semua kolom |
+ --------- + ------ + -------------------------------- ------------------------ +

Dengan perubahan skema data seperti itu saya akan menggunakan d6tstack yang meluruskan semua kolom sebelum dijalankan LOAD DATA. Lihat bagian contoh SQL d6tstack tentang perubahan skema data.
citynorman

Jawaban:


193

Ini akan melakukan apa yang Anda inginkan. Itu membaca bidang keempat menjadi variabel lokal, dan kemudian menetapkan nilai bidang aktual ke NULL, jika variabel lokal akhirnya berisi string kosong:

LOAD DATA INFILE '/tmp/testdata.txt'
INTO TABLE moo
FIELDS TERMINATED BY ","
LINES TERMINATED BY "\n"
(one, two, three, @vfour, five)
SET four = NULLIF(@vfour,'')
;

Jika semuanya mungkin kosong, maka Anda akan membacanya semuanya menjadi variabel dan memiliki beberapa pernyataan SET, seperti ini:

LOAD DATA INFILE '/tmp/testdata.txt'
INTO TABLE moo
FIELDS TERMINATED BY ","
LINES TERMINATED BY "\n"
(@vone, @vtwo, @vthree, @vfour, @vfive)
SET
one = NULLIF(@vone,''),
two = NULLIF(@vtwo,''),
three = NULLIF(@vthree,''),
four = NULLIF(@vfour,'')
;

Secara teoritis, saya kira - tetapi semuanya ada dalam memori, dan hanya menyimpan sejumlah kecil data per baris, jadi saya akan membayangkannya akan sangat kecil; tetapi Anda harus mengujinya jika Anda berpikir itu mungkin menjadi masalah.
Duncan Lock

4
Saya sangat suka jawaban ini. Pengguna dapat melihat string kosong ''ketika mereka mengunduh csv (menggunakan IFNULL(Col,'')dalam SELECT INTO OUTFILEkueri) untuk excel tetapi kemudian mengunggah menerimanya sebagai null vs harus berurusan dengan \Ndi csv. Terima kasih!
chrisan

9
untuk tanggal saya menggunakan 'NULLIF (STR_TO_DATE (@ date1, "% d /% m /% Y"), "0000-00-00")'
Joaquín L. Robles

1
Saya memiliki file csv yang berisi nol 0yang harus dikonversi NULL(karena tidak mungkin memiliki nilai nol untuk data yang dimaksud) dan juga mengosongkan string. Bagaimana cara memastikan bahwa nol dan string kosong dikonversi ke NULL?
Paul Rougieux

Jika nol nilai-nilai dan string kosong dalam kolom terpisah, kemudian hanya melakukan di atas untuk string kosong, dan sesuatu seperti ini untuk nol: nullif(@vone, 0).
Duncan Lock

136

Manual MySQL mengatakan:

Saat membaca data dengan LOAD DATA INFILE, kolom kosong atau hilang diperbarui dengan ''. Jika Anda menginginkan nilai NULL dalam kolom, Anda harus menggunakan \ N dalam file data. Kata literal "NULL" juga dapat digunakan dalam beberapa keadaan.

Jadi, Anda perlu mengganti yang kosong dengan \ N seperti ini:

1,2,3,4,5
1,2,3,\N,5
1,2,3

3
Terima kasih atas tipnya - Saya ragu untuk mengedit data sumber mentah tetapi jika ini adalah satu-satunya jalan keluar saya akan mencobanya.
Spiros

7
Saya memahami skeptisisme Anda, tidak ada yang suka mengedit data mentah, rasanya tidak benar. Namun, jika Anda memikirkannya sebentar, harus ada cara untuk membedakan antara NULL dan string kosong. Jika entri kosong diterjemahkan ke NULLs, Anda memerlukan urutan khusus untuk string kosong. Akan lebih baik memiliki cara bagaimana memberi tahu MySQL bagaimana cara memperlakukan entri kosong, seperti LOAD DATA INFILE '/tmp/testdata.txt' INTO TABLE moo TREAT BLANKS AS NULL ...
Janci

2
OK, tetapi jika Anda memiliki Fields enclosed by: "adalah bahwa "\N"dari"name",\N,"stuff"
Jonathon

3
Saya dapat memverifikasi bahwa setidaknya untuk "phpMyAdmin 3.5.5" tidak ada gaya \Nditerima yang menunjukkan NULL. Alih-alih gunakan NULL, seperti dalam contoh ini:"name","age",NULL,"other","stuff"
Jonathon

1
Kami memiliki MySQL 5.5.46-0 + deb8u1. Saya mencoba NULL dan \ N, dan hanya \ N yang bekerja untuk kami.
raphael75

6

Perilaku berbeda tergantung pada konfigurasi database. Dalam mode ketat ini akan menimbulkan kesalahan selain peringatan. Permintaan berikut dapat digunakan untuk mengidentifikasi konfigurasi basis data.

mysql> show variables like 'sql_mode';

Terima kasih! Saya menggaruk-garuk kepala mencoba mencari tahu mengapa mengimpor CSV dengan kolom kosong yang saya berhasil impor di server produksi kemarin tidak bekerja pada instalasi lokal baru saya - ini adalah jawaban dalam kasus saya!
Emma Burrows

3

Memproses ulang CSV input Anda untuk mengganti entri kosong dengan \ N.

Coba di regex: s / ,, /, \ n, / g dan s /, $ /, \ N / g

Semoga berhasil.


1
Regex ini sebagian berfungsi, itu tidak memecahkan entri kosong berurutan, misalnya ,,,, akan, \ n ,, \ n, Seharusnya dapat digunakan jika Anda menjalankannya dua kali
ievgen

1
Akan meringkas jawaban dan komentar sebelumnya. Berikut ini berfungsi untuk saya, dalam urutan: sed -i 's / ,, /, \ N / g' $ file, sed -i 's / ,, /, / g' $ file, sed -i 's / \ N, $ / \ N / g '$ file,
Omar Khazamov

Saya ingin melakukan ini, tetapi saya tidak jelas bagaimana Anda menjalankan regex ini. Jika Anda menggunakan MySQL untuk menjalankan ini terhadap file ini akan menjadi solusi terbaik. Tetapi Anda tidak mengatakannya dan saya tidak ingin menghabiskan banyak waktu di Google untuk melakukan sesuatu yang mungkin tidak mungkin dilakukan.
DonkeyKong

1

(variable1, @ variable2, ..) SET variable2 = nullif (@ variable2, '' or '') >> Anda dapat meletakkan kondisi apa pun


0

tampilkan variabel

Show variables like "`secure_file_priv`";

Catatan: simpan file csv Anda di lokasi yang diberikan oleh perintah di atas.

create table assessments (course_code varchar(5),batch_code varchar(7),id_assessment int, assessment_type varchar(10), date int , weight int);

Catatan: di sini kolom ' date' memiliki beberapa nilai kosong di file csv.

LOAD DATA INFILE 'C:/ProgramData/MySQL/MySQL Server 8.0/Uploads/assessments.csv' 
INTO TABLE assessments
FIELDS TERMINATED BY ',' 
OPTIONALLY ENCLOSED BY '' 
LINES TERMINATED BY '\n' 
IGNORE 1 ROWS 
(course_code,batch_code,id_assessment,assessment_type,@date,weight)
SET date = IF(@date = '', NULL, @date);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.