MySQL tải các giá trị NULL từ dữ liệu CSV


167

Tôi có một tệp có thể chứa từ 3 đến 4 cột giá trị số được phân tách bằng dấu phẩy. Các trường trống được xác định với ngoại lệ khi chúng ở cuối hàng:

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

Bảng sau đây đã được tạo trong MySQL:

+ ------- + -------- + ------ + ----- + --------- + ------- +
| Lĩnh vực | Loại | Không | Chìa khóa | Mặc định | Thêm |
+ ------- + -------- + ------ + ----- + --------- + ------- +
| một | int (1) | CÓ | | NULL | |
| hai | int (1) | CÓ | | NULL | |
| ba | int (1) | CÓ | | NULL | |
| bốn | int (1) | CÓ | | NULL | |
| năm | int (1) | CÓ | | NULL | |
+ ------- + -------- + ------ + ----- + --------- + ------- +

Tôi đang cố tải dữ liệu bằng lệnh MySQL LOAD:

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

Bảng kết quả:

+ ------ + ------ + ------- + ------ + ------ +
| một | hai | ba | bốn | năm |
+ ------ + ------ + ------- + ------ + ------ +
| 1 | 2 | 3 | 4 | 5 |
| 1 | 2 | 3 | 0 | 5 |
| 1 | 2 | 3 | NULL | NULL |
+ ------ + ------ + ------- + ------ + ------ +

Vấn đề nằm ở chỗ, khi một trường trống trong dữ liệu thô và không được xác định, MySQL vì một số lý do không sử dụng giá trị mặc định của cột (là NULL) và sử dụng 0. NULL được sử dụng chính xác khi trường bị thiếu hoàn toàn.

Thật không may, tôi phải phân biệt được NULL và 0 ở giai đoạn này để mọi sự giúp đỡ đều được đánh giá cao.

Cảm ơn S.

biên tập

Đầu ra của SHOW WARNING:

+ --------- + ------ + -------------------------------- ------------------------ +
| Cấp độ | Mã | Tin nhắn |
+ --------- + ------ + -------------------------------- ------------------------ +
| Cảnh báo | 1366 | Giá trị nguyên không chính xác: '' cho cột 'bốn' ở hàng 2 |
| Cảnh báo | 1261 | Hàng 3 không chứa dữ liệu cho tất cả các cột |
| Cảnh báo | 1261 | Hàng 3 không chứa dữ liệu cho tất cả các cột |
+ --------- + ------ + -------------------------------- ------------------------ +

Với các thay đổi lược đồ dữ liệu như vậy, tôi sẽ sử dụng d6tstack để căn chỉnh tất cả các cột trước khi chạy LOAD DATA. Xem phần ví dụ SQL d6tstack về thay đổi lược đồ dữ liệu.
citynorman

Câu trả lời:


193

Điều này sẽ làm những gì bạn muốn. Nó đọc trường thứ tư thành một biến cục bộ, sau đó đặt giá trị trường thực tế thành NULL, nếu biến cục bộ kết thúc có chứa một chuỗi rỗng:

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,'')
;

Nếu tất cả đều có thể trống, thì bạn sẽ đọc tất cả chúng thành các biến và có nhiều câu lệnh SET, như thế này:

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,'')
;

Về mặt lý thuyết, tôi cho rằng - nhưng tất cả chỉ là trong bộ nhớ và chỉ chứa một lượng nhỏ dữ liệu trên mỗi hàng, vì vậy tôi sẽ hình dung nó sẽ là vô hạn; nhưng bạn nên kiểm tra nó nếu bạn nghĩ nó có thể là một vấn đề.
Khóa Duncan

4
Tôi thực sự thích câu trả lời này. Người dùng có thể thấy các chuỗi trống ''khi họ tải xuống một csv (sử dụng IFNULL(Col,'')trong SELECT INTO OUTFILEtruy vấn) cho excel nhưng sau đó tải lên chấp nhận chúng là null so với việc phải xử lý \Ntrong csv. Cảm ơn!
chrisan

9
cho những ngày tôi đã sử dụng 'NULLIF (STR_TO_DATE (@ date1, "% d /% m /% Y"), "0000-00-00")'
Joaquín L. Robles

1
Tôi có một tệp csv chứa các số 0 0nên được chuyển đổi thành NULL(vì không thể có giá trị 0 cho dữ liệu được đề cập) và cả các chuỗi trống. Làm thế nào để đảm bảo rằng cả số không và chuỗi rỗng được chuyển đổi thành NULL?
Paul Rougieux

Nếu các giá trị 0 và các chuỗi trống nằm trong các cột riêng biệt, thì chỉ cần thực hiện ở trên cho các chuỗi trống và một cái gì đó như thế này cho các số không : nullif(@vone, 0).
Khóa Duncan

136

Hướng dẫn sử dụng MySQL nói:

Khi đọc dữ liệu với LOAD DATA INFILE, các cột trống hoặc thiếu được cập nhật với ''. Nếu bạn muốn giá trị NULL trong một cột, bạn nên sử dụng \ N trong tệp dữ liệu. Từ này có thể được sử dụng trong một số trường hợp.

Vì vậy, bạn cần thay thế khoảng trống bằng \ N như thế này:

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

3
Cảm ơn về mẹo - Tôi nghi ngờ khi chỉnh sửa dữ liệu nguồn thô nhưng nếu đây là cách duy nhất xung quanh nó, tôi sẽ thử.
Spiros

7
Tôi hiểu sự hoài nghi của bạn, không ai thích chỉnh sửa dữ liệu thô, điều đó không đúng. Tuy nhiên, nếu bạn nghĩ về nó trong một phút, phải có một cách để phân biệt giữa NULL và chuỗi rỗng. Nếu các mục trống được dịch sang NULL, bạn cần một chuỗi đặc biệt cho chuỗi trống. Thật tuyệt khi có một cách để nói với MySQL cách xử lý các mục trống, một cái gì đó như LOAD DATA INFILE '/tmp/testdata.txt' INTO TABLE moo TREAT BLANKS AS NULL ...
Janci

2
OK, nhưng nếu bạn có Fields enclosed by: ""\N"của"name",\N,"stuff"
Jonathon

3
Tôi có thể xác minh rằng ít nhất là đối với "phpMyAdmin 3.5.5", không có kiểu nào \Nđược chấp nhận là biểu thị NULL. Thay vì sử dụng NULL, như trong ví dụ này:"name","age",NULL,"other","stuff"
Jonathon

1
Chúng tôi có MySQL 5.5.46-0 + deb8u1. Tôi đã thử cả NULL và \ N và chỉ \ N làm việc cho chúng tôi.
raphael75

6

Hành vi là khác nhau tùy thuộc vào cấu hình cơ sở dữ liệu. Trong chế độ nghiêm ngặt, điều này sẽ đưa ra một cảnh báo khác. Truy vấn sau đây có thể được sử dụng để xác định cấu hình cơ sở dữ liệu.

mysql> show variables like 'sql_mode';

Cảm ơn! Tôi đã gãi đầu cố gắng tìm ra lý do tại sao việc nhập CSV với các cột trống tôi đã nhập thành công trên máy chủ sản xuất ngày hôm qua không hoạt động với cài đặt cục bộ hoàn toàn mới của tôi - đây là câu trả lời trong trường hợp của tôi!
Emma Burrows

3

Tiền xử lý CSV đầu vào của bạn để thay thế các mục trống bằng \ N.

Cố gắng ở một regex: s / ,, /, \ n, / g và s /, $ /, \ N / g

Chúc may mắn.


1
Regex này hoạt động một phần, nó không giải quyết các mục trống liên tiếp, ví dụ ,,,, sẽ, \ n ,, \ n, Có thể sử dụng được nếu bạn chạy nó hai lần
ievgen

1
Sẽ tóm tắt câu trả lời và nhận xét trước đó. Theo sau làm việc cho tôi, theo thứ tự: tập tin sed -i '/ / / / \ \ / $, tập tin sed -i / ,, /, / g' $, tập tin sed -i / s / \ Tệp N, $ / \ N / g '$,
Omar Khazamov

Tôi muốn làm điều này, nhưng tôi không rõ bạn đang chạy regex này như thế nào. Nếu bạn đang sử dụng MySQL để chạy tệp này thì đây sẽ là giải pháp tốt nhất. Nhưng bạn không nói và tôi không muốn mất nhiều thời gian để làm thế nào để làm điều gì đó có thể không thể.
DonkeyKong

1

(biến1, @ biến2, ..) SET biến2 = nullif (@ biến2, '' hoặc '') >> bạn có thể đặt bất kỳ điều kiện nào


0

hiển thị các biến

Show variables like "`secure_file_priv`";

Lưu ý: giữ tệp csv của bạn ở vị trí được cung cấp bởi lệnh trên.

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

Lưu ý: ở đây datecột '' có một số giá trị trống trong tệp 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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.