保持MySQL数据库与外部源(.csv)同步,同时维护先前的数据

时间:2019-01-18 17:07:11

标签: php mysql database

每天下午3点,我都会将一个.csv文件上传到我的FTP服务器。

例如,让我们以此为例

  

population.csv

city,population
New York,8008278
Los Angeles,3694825
San Diego,1223405

我已将CSV文件转换为数组,并使用INSERT INTO将行插入表Populations

╔════╦═════════════╦════════════╦════════╗
║ id ║    city     ║ population ║ status ║
╠════╬═════════════╬════════════╬════════╣
║  1 ║ New York    ║    8008278 ║      1 ║
║  2 ║ Los Angeles ║    3694825 ║      1 ║
║  3 ║ San Diego   ║    1223405 ║      1 ║
╚════╩═════════════╩════════════╩════════╝

id是一个AUTO INCREMENT索引,状态是一个TINYINT(1),如果它是当天上传的CSV文件,则我将其值设置为1

让我们说明天下午3点将此CSV文件上传到我的服务器:

city,population
Los Angeles,3694825
San Diego,1229502

如您所见,New York行未包括在内,population中的San Diego已更改。

我想要实现的结果是每天使用CSV文件中的值更新行。如果不包含以前的行(例如New York),我想将状态设置为0

因此,第二天,基于CSV文件的内容,我希望数据库解决以下问题:

╔════╦═════════════╦════════════╦════════╗
║ id ║    city     ║ population ║ status ║
╠════╬═════════════╬════════════╬════════╣
║  1 ║ New York    ║    8008278 ║      0 ║
║  2 ║ Los Angeles ║    3694825 ║      1 ║
║  3 ║ San Diego   ║    1229502 ║      1 ║
╚════╩═════════════╩════════════╩════════╝

截至目前,我正在使用PHP将上传的CSV文件解析为一个数组,另外还使用了一个SELECT查询来将数据库解析为一个数组。

在PHP中使用条件语句,我正在比较两个数组的任何差异(行值更改,新行,已删除行)。

这是我第一次尝试使外部源与状态为1的数据库内容完全同步。

在MySQL本身中是否有更有效的方法来执行此操作,而不依靠其他编程语言来构造我的语句?

有些想法让我望而却步:

  • 为每行添加一个LastUpdated时间戳记,如果该时间戳记超过24小时,则创建一个TRIGGER来将状态设置为0

  • 创建审核表以引用前一天的更改。 (已删除的行,已插入的行等)。引用后,重新插入所有唯一/索引值(id),并将状态0表示为今天的CSV文件中未包含的行

或者我目前使用PHP将CSV与表中的当前记录进行比较的当前方法是最好的方法吗?如前所述,我对数据库有一定的经验,但从未尝试过做类似的事情。我应该朝哪个方向看?我缺少明显的东西吗?

1 个答案:

答案 0 :(得分:1)

我建议首先使用LOAD DATA INFILE语法将新文件插入到临时表中。以下是一个示例,您可能需要根据用例(de {this tutorial for example)对其进行修改;

LOAD DATA INFILE 'c:/tmp/populations.csv' 
INTO TABLE Temp 
FIELDS TERMINATED BY ',' 
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;

然后,以下查询可用于更新主表中的现有行:

UPDATE Populations p
LEFT JOIN Temp t ON p.city = t.city
SET 
    p.population = COALESCE(t.population, p.population),
    p.status = CASE WHEN p.city IS NULL THEN 1 ELSE 0 END

此查询将插入尚不存在的行:

INSERT INTO Populations
SELECT p.name, p.population, 1
FROM Temp t
WHERE NOT EXISTS (
    SELECT 1 FROM Populations WHERE name = t.name)