LOAD DATA INFILE父子表与外键的关系

时间:2018-09-08 14:41:46

标签: php mysql foreign-keys

所以我有2张桌子。路径表具有与媒体表“ id”连接的外键“ media_id”。每个媒体可以有多个路径。这一切都很好。

当我尝试使用csv导出和导入这些表时出现问题。我可以正常导出它们,但是当我导入它们(第一个媒体表)时,媒体表中的主键'id'设置为自动递增,并且当使用LOAD DATA INFILE导入媒体表时,它将生成新的'id'单独运行,因此我将失去与路径表的任何连接。

$sql = "CREATE TABLE $media_table (
            `id` int(11) NOT NULL AUTO_INCREMENT,
            `title` varchar(255) DEFAULT NULL,
            `description` varchar(2000) DEFAULT NULL,
            PRIMARY KEY (`id`),
         ) $charset_collate;";

        $sql = "CREATE TABLE $path_table (
            `id` int(11) NOT NULL AUTO_INCREMENT,
            `path` varchar(500) DEFAULT NULL,
            `def` varchar(50) DEFAULT NULL,
            `media_id` int(11) NOT NULL,
            PRIMARY KEY (`id`),
            INDEX `media_id` (`media_id`),
            CONSTRAINT `mvp_path_ibfk_1` FOREIGN KEY (`media_id`) REFERENCES {$media_table} (`id`) ON DELETE CASCADE ON UPDATE CASCADE
        ) $charset_collate;";

以下是查询:

$query = "LOAD DATA INFILE '$csv' INTO TABLE {$table}
      FIELDS OPTIONALLY ENCLOSED BY '^'
      TERMINATED BY '|'
      ESCAPED BY ''
      LINES TERMINATED BY '\n'
      IGNORE 1 LINES";

我的数据库设计有问题吗?我该如何改善它或解决这个问题?

2 个答案:

答案 0 :(得分:1)

我通常不运行这种类型的操作,因此这可能是伪代码,需要进行调整,但是我认为您可以这样做:

https://stackoverflow.com/a/2710714

CREATE TEMPORARY TABLE
IF NOT EXISTS temp_{$table_name_with_datetime}
AS (SELECT * FROM {$table_name});

# Not sure if this will work, it would need some way
# for the CREATE to be gotten.
SELECT (SHOW CREATE TABLE temp_{$table_name_with_datetime})
  INTO OUTFILE '{$table_name_with_datetime}_create.sql'
  FIELDS TERMINATED BY ''
  OPTIONALLY ENCLOSED BY ''
  LINES TERMINATED BY '\n'
  FROM temp_{$table_name_with_datetime};

SELECT * INTO OUTFILE '{$table_name_with_datetime}.csv'
  FIELDS TERMINATED BY ','
  OPTIONALLY ENCLOSED BY '"'
  LINES TERMINATED BY '\n'
  FROM temp_{$table_name_with_datetime};

然后使用PHP,例如,拉出这些文件并加载它们:

// This creates the table.
$dbo->query(file_get_contents("{$table_from_filename}_create.sql"));
$dbo->query("
LOAD DATA INFILE '{$table_from_filename}.csv'
  INTO TABLE temp_{$table_from_filename}
  FIELDS OPTIONALLY ENCLOSED BY '"'
  TERMINATED BY '\n'
  ESCAPED BY ''
  LINES TERMINATED BY '\n'
");

如果$table_from_filenamemedia_201809041045,现在您已将其导入为temp_media_201809041045,所以

$tablename = "temp_$table_from_filename";

现在,有了五个表,事情可能会变得复杂,例如,您必须保持优先级顺序(父级先于子级),除非有方法可以禁用它,直到您导入每个表为止。

如果您可以将它们作为(临时)表进入数据库,那么现在您可以通过查询每个父行,在原始表上进行插入,然后使用last_insert_id来处理它们。可以为以后的子行创建交换索引。如果外键始终遵循相同的模式,例如mediamedia_id,那么您可以轻松地创建一个函数来处理该问题,只需使用要复制的五个表名即可。

另一件事,在CREATE呼叫中,如果您需要的不仅仅是呼叫并获得一个或一系列{{1 }}个TEMPORARY。您可以以查询结尾,但是有了一个临时表,下一个查询就消失了。然后最后,为现在的“临时”常规表运行UNION,只需确保它是实际的临时表即可。

答案 1 :(得分:0)

当我试图在评论中解释(可能很差)时,我认为在这种情况下使用标识符而不是跟踪整数会更好,因为它提供了关键的见解,即生成一个简单的数字即可消除歧义它的邻居没有:

这是一件事,所以它活了。

这种强大的设计模式的意思是,当您导入它时,如果您正在(希望知道)假设正在使用某些旧的导入文件(而不是将来使用的神奇文件), ,要对可能已经在数据集中表示的数据进行整体导入 (严重的是,当我使用重叠的数据集键入内容时,可能还加载了另外两个快照),您只需忽略更新,因为您现在代表的 应该比那个旧的数据文件新,所以并且其中的事物具有标识

UUID是uuid是UUID是uuid ...

这是假设域的数据模型是一致的,而加载的表示只是该表示。因此,使用唯一的跨系统标识符序列化先前的外部表示,使其具有从系统中删除然后重新引入时更容易处理的功能。

尤其是在较小的系统中,UUID易于使用(可以在短时间内生成许多数字,并应考虑跨域集成),但是除非您需要这种类型的导出/导入功能并且您需要希望它在导入时保持其身份。

# Note there's `temp_`, $table_from_filename would be "media".
LOAD DATA INFILE '{$table_from_filename}.csv'
  IGNORE INTO TABLE {$table_from_filename}
  FIELDS OPTIONALLY ENCLOSED BY '"'
  TERMINATED BY '\n'
  ESCAPED BY ''
  LINES TERMINATED BY '\n'

您不必这样做,请不要在我提倡重写的同时对它进行解释。但是,如果您在设计时考虑了一下,请问问自己,我的数据是否需要保存在包装盒内?