使用MySQL中的LOAD DATA INFILE过滤null或空输入

时间:2011-09-28 18:19:04

标签: mysql bulkinsert

我需要加载到数据库中的一些非常大的文件(数百万条记录)。它们的形式如下:

word1\tblahblahblah
word2\tblahblah
word3\tblahblah
word4
word5\tblahblah
...

我的问题是,我想忽略没有第二条记录的行('blahblah'),如word4。

我目前正在使用以下查询来加载文件:

LOAD DATA LOCAL INFILE 'file' 
IGNORE INTO TABLE tablename 
COLUMNS TERMINATED BY '\t' 
LINES TERMINATED BY '\n'
(col1, col2);

这具有我想要的功能,除了它仍然接受空值。有没有办法跳过word4类型的行,而不是将它们添加到数据库?

直觉上,我认为使用WHEN或WHERE子句是完美的,但通过在线查看文档和其他信息,我找不到任何可行的示例。我是否被迫手动过滤这些记录,或者我可以在此查询中进行过这些记录吗?

任何帮助都非常感谢!

1 个答案:

答案 0 :(得分:1)

我会通过使用grepawk过滤文件,然后将其传输到MySQL(通过/dev/stdin)来完成此操作。像这样的东西:

cat your_file.txt |
  awk '/\t.+/' |
    mysql -u your_username -pyour_password \
      -e "LOAD DATA LOCAL INFILE '/dev/stdin' \
          IGNORE INTO TABLE tablename         \
          COLUMNS TERMINATED BY '\t'          \
          LINES TERMINATED BY '\n'            \
          (col1, col2);" \
      your_database_name

第二行上给awk的正则表达式只匹配任何字符后跟一个或多个字符的字符串。您可能需要调整它以满足您的需求。

编辑:另一种可能性发生在我身上。您可以使用SET在空白的列上设置一些魔术值,并在表格上放置一个BEFORE INSERT触发器,当它看到该值时将在行上保释。我对触发器没有太多经验,但我认为这样的事情应该有效:

CREATE TRIGGER skip_magic_rows
  BEFORE INSERT ON tablename
  FOR EACH ROW
  BEGIN
    IF NEW.col2 = 'IDSPISPOPD4815162342' THEN  # Some unlikely magic string
      # Trigger an error, which will cause the INSERT to fail†

      # If you have MySQL < 5.5 this is kludgy -- see Note 1
      DROP TABLE `Skipped row`

      # OR

      # In MySQL >= 5.5 you can send a signal--'45000' is a generic error
      SIGNAL SQLSTATE '45000' SET message_text = 'Skipped row';  # See Note 2

    END IF
  END
;

†: Per the docs

  

BEFORE或AFTER触发期间的错误导致导致触发器调用的整个语句失败。

则...

LOAD DATA LOCAL INFILE 'file' 
  IGNORE INTO TABLE tablename 
  COLUMNS TERMINATED BY '\t' 
  LINES TERMINATED BY '\n'
  (col1, @var2)
  SET col2 = IF(@var2 IN (NULL, ''), 'IDSPISPOPD4815162342', @var2)
;

希望它有用!

注1: Relevant blog post and comments
注2: Relevant SO thread