每天下午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与表中的当前记录进行比较的当前方法是最好的方法吗?如前所述,我对数据库有一定的经验,但从未尝试过做类似的事情。我应该朝哪个方向看?我缺少明显的东西吗?
答案 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)