ChatGPT解决这个技术问题 Extra ChatGPT

MySQL 从 CSV 数据加载 NULL 值

我有一个文件,其中可以包含 3 到 4 列用逗号分隔的数值。空字段定义为例外,当它们位于行尾时:

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

下表是在 MySQL 中创建的:

+-------+--------+------+-----+---------+-------+
| Field | Type   | Null | Key | Default | Extra |
+-------+--------+------+-----+---------+-------+
| one   | int(1) | YES  |     | NULL    |       | 
| two   | int(1) | YES  |     | NULL    |       | 
| three | int(1) | YES  |     | NULL    |       | 
| four  | int(1) | YES  |     | NULL    |       | 
| five  | int(1) | YES  |     | NULL    |       | 
+-------+--------+------+-----+---------+-------+

我正在尝试使用 MySQL LOAD 命令加载数据:

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

结果表:

+------+------+-------+------+------+
| one  | two  | three | four | five |
+------+------+-------+------+------+
|    1 |    2 |     3 |    4 |    5 | 
|    1 |    2 |     3 |    0 |    5 | 
|    1 |    2 |     3 | NULL | NULL | 
+------+------+-------+------+------+

问题在于,当原始数据中的字段为空且未定义时,MySQL 出于某种原因不使用列默认值(即 NULL)并使用零。当字段全部丢失时,正确使用 NULL。

不幸的是,在这个阶段我必须能够区分 NULL 和 0,所以任何帮助都将不胜感激。

谢谢S。

编辑

显示警告的输出:

+---------+------+--------------------------------------------------------+
| Level   | Code | Message                                                |
+---------+------+--------------------------------------------------------+
| Warning | 1366 | Incorrect integer value: '' for column 'four' at row 2 | 
| Warning | 1261 | Row 3 doesn't contain data for all columns             | 
| Warning | 1261 | Row 3 doesn't contain data for all columns             | 
+---------+------+--------------------------------------------------------+
对于这样的数据架构更改,我将使用 d6tstack,它在运行 LOAD DATA 之前对齐所有列。请参阅关于数据架构更改的 d6tstack SQL examples 部分。

J
Jacob

这将做你想要的。它将第四个字段读入局部变量,然后将实际字段值设置为 NULL,如果局部变量最终包含一个空字符串:

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

如果它们都可能为空,那么您会将它们全部读入变量并具有多个 SET 语句,如下所示:

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

我真的很喜欢这个答案。用户在为 excel 下载 csv(在 SELECT INTO OUTFILE 查询中使用 IFNULL(Col,''))时可以看到空字符串 '',但随后上传时接受它们为空,而不必处理 csv 中的 \N。谢谢!
对于我使用的日期 'NULLIF(STR_TO_DATE(@date1, "%d/%m/%Y"), "0000-00-00")'
我有一个 csv 文件,其中包含应转换为 NULL 的零 0(因为有问题的数据不可能有零值)以及空字符串。如何确保零和空字符串都转换为 NULL
如何在不提及特定列的情况下执行此操作?只为所有人?
如果你有 50 列呢?设置 50 列似乎有点矫枉过正。有没有一种全局方法来告诉 Load 函数只用 null 替换空值?
J
Janci

MySQL manual 说:

使用 LOAD DATA INFILE 读取数据时,空列或缺失列将使用 '' 进行更新。如果您想在列中使用 NULL 值,则应在数据文件中使用 \N。在某些情况下也可以使用字面意思“NULL”。

所以你需要用 \N 替换空格,如下所示:

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

感谢您的提示 - 我对编辑原始源数据持怀疑态度,但如果这是解决它的唯一方法,我会尝试一下。
我理解你的怀疑,没有人喜欢编辑原始数据,只是感觉不对。但是,如果您考虑一下,必须有一种方法可以区分 NULL 和空字符串。如果将空白条目转换为 NULL,则您需要一个特殊的空字符串序列。很高兴有一种方法告诉 MySQL 如何处理空白条目,例如 LOAD DATA INFILE '/tmp/testdata.txt' INTO TABLE moo TREAT BLANKS AS NULL ...
好的,但是如果您有 Fields enclosed by: ""name",\N,"stuff" 中的 "\N"
我可以验证至少对于“phpMyAdmin 3.5.5”,没有 \N 的样式被接受为表示 NULL。请改用 NULL,如本例所示:"name","age",NULL,"other","stuff"
我们有 MySQL 5.5.46-0+deb8u1。我尝试了 NULL 和 \N,只有 \N 对我们有用。
D
Dobi

行为因数据库配置而异。在严格模式下,这会引发错误,否则会发出警告。以下查询可用于识别数据库配置。

mysql> show variables like 'sql_mode';

谢谢!我正在挠头,试图弄清楚为什么我昨天在生产服务器上成功导入的带有空列的 CSV 在我全新的本地安装上不起作用——这就是我的答案!
S
Sam Goldman

预处理您的输入 CSV 以用 \N 替换空白条目。

尝试正则表达式:s/,,/,\n,/g 和 s/,$/,\N/g

祝你好运。


此正则表达式部分有效,它不能解决连续的空白条目,例如 ,,,, will be ,\n,,\n, 如果您运行两次应该可以使用
将总结答案和先前的评论。以下为我工作,按顺序: sed -i 's/,,/,\N/g' $file, sed -i 's/,,/,/g' $file, sed -i 's/\ N,$/\N/g' $文件,
我想这样做,但我不清楚你是如何运行这个正则表达式的。如果您使用 MySQL 对文件运行它,这将是最好的解决方案。但是你不说,我也不想花很多时间在谷歌上搜索如何做一些不可能的事情。
S
Sunny Sharma

显示变量

Show variables like "`secure_file_priv`";

注意:将您的 csv 文件保存在上述命令给出的位置。

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

注意:这里的 'date' 列在 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);

S
Said

(variable1, @variable2, ..) SET variable2 = nullif(@variable2, '' or ' ') >> 你可以放任何条件


作为对 stackoverflow.com/a/5968530/10376320 的评论,这可能会更好
A
Aimnox

在 UNIX 终端中使用以下 sed 命令将输入文件转换为包含空白列数据的 \N

sed -i 's/,,/,\\N,/g' $file_name

然后使用 LOAD DATA INFILE 命令加载到 mysql