【问题标题】:LOAD DATA INFILE parent child table and foreign keys relationshipLOAD DATA INFILE 父子表和外键关系
【发布时间】:2018-09-08 14:41:46
【问题描述】:

所以我有 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";

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

【问题讨论】:

标签: php mysql foreign-keys


【解决方案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 通话中,您可能希望从通话中删除TEMPORARY,如果您需要的不仅仅是通话并获得一个或一系列UNION'd @987654334 @s。您可以以查询结束,但使用临时表,它会在下一个查询中消失。然后在最后,为现在的“临时”常规表运行 DROP TABLE,只要确保它是实际的临时表即可。

【讨论】:

    【解决方案2】:

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

    它是一个东西,所以它存在。

    这个强大的设计模式意味着,当你去导入它时,如果你正在操作(希望知道)假设正在使用一些旧的导入文件(而不是来自未来的神奇文件) ,要对可能已经在数据集中表示的数据进行整体导入(说真的,在我输入重叠数据集时可能已经加载了另外两个快照),你只需要忽略更新,因为你所代表的目前应该比旧数据文件更新,其中的东西有身份

    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'
    

    您不必这样做,请不要将其解释为我提倡重写。但是,如果您在设计时考虑一下,问问自己,我的数据是否需要开箱即用

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-02
      • 2021-04-19
      • 2019-01-11
      • 1970-01-01
      • 1970-01-01
      • 2012-10-05
      • 2010-11-17
      相关资源
      最近更新 更多