我已将 mysql 表转储为 CSV。在此 CSV 文件中,NULL 值写为
\N
\N
是空值。它将其视为字符串,并且该列值存储为“\N”而不是 NULL。
任何人都可以指导如何使用 sqlite 中的
.nullvalue
点命令。我无法将 \N
设置为空值。sqlite> .show
nullvalue: ""
sqlite> .nullvalue \N
sqlite> .show
nullvalue: "N"
sqlite> .nullvalue '\N'
sqlite> .show
nullvalue: "\\N"
sqlite> .nullvalue "\N"
sqlite> .show
nullvalue: "N"
sqlite> .nullvalue \\N
sqlite> .show
nullvalue: "\\N"
sqlite> .nullvalue '\'N
Usage: .nullvalue STRING
sqlite> .nullvalue '\\'N
Usage: .nullvalue STRING
sqlite> .nullvalue \\N
sqlite> .show
nullvalue: "\\N"
sqlite>
这是每个
nullvalue
值之后的输出
sqlite> .import /tmp/mysqlDump.csv employee
sqlite> select count(*) from employee where updatedon='\N';
94143
sqlite> select count(*) from employee where updatedon is null;
0
如何告诉 sqlite 将
\N
视为 NULL 值? 我不能使用空字符串作为 NULL 值,因为我的数据包含空字符串。
CSV 文件仅包含文本值。无法从 CSV 文件导入 NULL 值。
要将
\N
值转换为 NULL,只需随后使用 UPDATE:
UPDATE employee SET updatedon = NULL WHERE updatedon = '\N';
当 sqlite 配置为检查外键引用时,依赖于在导入后进行更新的方法是不可能的,因为导入将失败(外键约束将失败)并且不会有要更新的行。
为此,在导入后进行更新是不可接受的情况下,您必须修改合并中的 shell.c 文件(如下所示),并编译一个新的 sqlite(.exe) 二进制文件。
要做的更改是当字段为空时(使用
sqlite3_bind_null
)将字段的参数绑定为 NULL,而不是像目前所做的那样使用 sqlite3_bind_text
无条件地将其绑定为文本字段。
下面是对 sqlite 版本 v 3.33.0 2020-08-14 进行更改的示例(作为补丁差异)。
该示例在新的编译时选项
SQLITE_IMPORT_NULL_IF_EMPTY
背后进行了更改,因此要启用它,您需要在编译时定义它,如下所示:
cc -DSQLITE_IMPORT_NULL_IF_EMPTY <other options> shell.c sqlite3.c -o sqlite3
带有推荐选项(以及其他一些设置)的完整编译命令示例:
cc -Os -DSQLITE_IMPORT_NULL_IF_EMPTY -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_USE_ALLOCA -DSQLITE_OMIT_AUTOINIT -DSQLITE_DEFAULT_FOREIGN_KEYS=1 -DSQLITE_ENABLE_NULL_TRIM -DSQLITE_ENABLE_RBU -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DHAVE_USLEEP -DHAVE_READLINE shell.c sqlite3.c -lreadline -lncurses -o sqlite3
补丁文件内容:
--- sqlite-amalgamation-3330000/shell.c 2020-08-14 13:42:48.000000000 +0000
+++ shell.c 2020-10-07 13:23:39.000000000 +0000
@@ -17845,7 +17845,12 @@
** the remaining columns.
*/
if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
+#ifdef SQLITE_IMPORT_NULL_IF_EMPTY
+ if (z==0 || z[0]=='\0') sqlite3_bind_null(pStmt, i+1);
+ else sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
+#else
sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
+#endif
if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
utf8_printf(stderr, "%s:%d: expected %d columns but found %d - "
"filling the rest with NULL\n",
更好一点的补丁:
+ if (p->nullValue[0] != '\0' && cli_strcmp(z, p->nullValue)==0) sqlite3_bind_null(pStmt, i+1);
+ else sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
现在,当设置 .nullvalue 时,导入 CSV/TSV 文件时其值将替换为 NULL。