加载数据填充父子表和外键关系

zy1mlcev  于 2021-06-19  发布在  Mysql
关注(0)|答案(2)|浏览(273)

所以我有两张table。路径表的外键“media\u id”与媒体表“id”连接。每个介质可以有多个路径。这一切都很好。
当我尝试用csv导出和导入这些表时,问题就出现了。我可以正常导出它们,但当我要导入它们(第一个媒体表)时,媒体表中的主键“id”被设置为自动递增,并且当媒体表与加载数据填充一起导入时,它将自己生成新的“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";

我的数据库设计有什么问题吗?我怎样才能改进它,或者绕过这个问题?

mspsb9vt

mspsb9vt1#

正如我试图在评论中解释的(可能很糟糕),我认为在这种情况下使用标识符而不是跟踪整数会更好,因为它提供了一个关键的见解,一个简单的数字生成来消除它与它的邻居之间的歧义不会:
它是一种东西,所以它活着。
这个强大的设计模式意味着,当你去导入它时,如果你不使用(希望是已知的)某个旧的导入文件的假设(与未来神奇的导入文件相反),对可能已经在数据集中表示的数据进行整体导入(说真的,可能在我使用重叠的数据集键入时加载了另外两个快照),您只需忽略更新,因为您当前所表示的内容应该比旧数据文件更新,并且其中的内容具有标识:
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'

你不必这样做,请不要把这理解为我在推动重写。然而,如果您在设计时考虑到这一点,请扪心自问,我的数据是否需要放在盒子之外?

hjzp0vay

hjzp0vay2#

我通常不运行这种类型的操作,因此这可能是伪代码,需要调整,但我认为您可以这样做:
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";

现在,对于五个表,事情可能会变得复杂,例如,您必须保持优先顺序(父表在子表之前),除非有方法在导入每个表之前禁用它。
如果可以将它们作为(temp)表放入数据库,那么现在就可以对它们进行处理,例如查询每个父行,对源表执行insert,然后使用 last_insert_id ,可以为以后的子行创建交换索引。如果外键总是遵循相同的模式,例如。 media 以及 media_id ,然后就可以很容易地创建一个函数来处理这个问题,只需使用要复制的五个表名中的表名即可。
另一件事,在 CREATE 呼叫,您可能要删除 TEMPORARY 如果你需要的不仅仅是打个电话,还可以得到一个或一系列的 UNION “d” SELECT s。您可以在查询中结束,但如果使用临时表,它将在下一个查询中消失。最后,运行 DROP TABLE 对于现在的“临时”常规表,只需确保它是实际的临时表。

相关问题