繁体   English   中英

r-dbWriteTable还是MySQL Delete查询?

[英]r - dbWriteTable or a MySQL Delete query?

我似乎在任何地方都找不到答案。 我正在使用read.csv函数将csv读取到数据帧中。 然后,我使用dbWriteTable将数据帧内容写入mysql表。 这对于创建表的初始运行非常有用,但是此后的每次运行都需要根据表中是否已存在记录进行插入或更新。

数据框中的第一列是主键,其他记录包含的数据可能会在我每次提取csv的新副本时发生变化。 每次我拉CSV时,如果主键已经存在,我希望它用新数据更新该记录,并且如果主键不存在(例如:自上次运行以来的新键),我希望它只需将记录插入表中即可。

这是我当前的dbWriteTable。 这将在第一次运行时创建该表,并且还将一个“ Timestamp”列插入设置为“ on update CURRENT_TIMESTAMP”的表中,以便我知道每条记录的最后更新时间。

dbWriteTable(mydb, value=csvData, name=Table, row.names=FALSE, field.types=list(PrimaryKey="VARCHAR(10)",Column2="VARCHAR(255)",Column3="VARCHAR(255)",Timestamp="TIMESTAMP"), append=TRUE)

现在,下次运行此代码时,我只希望它更新表中已存在的任何PrimaryKey,并添加任何新的PrimaryKey。 我也不想丢失任何记录,以防PrimaryKey从CSV源消失。

是否可以使用dbWriteTable或其他R函数进行这种更新?

如果那是不可能的,是否可以只运行一个mysql查询,该查询将删除任何重复的PrimaryKey记录,并仅保留具有最新时间戳的1条记录? 因此,我将运行dbWriteTable追加新数据,然后运行MySQL查询以删减旧记录。

显然,我无法将第1列定义为数据库中的实际PrimaryKey,因为附加键会导致我的附加/删除解决方案无法正常工作,这很好,我可以随时向表中添加“真正的”主键(如果需要)。

有什么想法吗?

考虑使用临时表(最终表的精确副本,但记录更少),然后在最终表中运行INSERTUPDATE查询,这将处理两种情况而不会出现重叠(加上主键是约束,并且如果进行尝试,查询将出错)复制任何):

  1. 如果不存在,则追加记录-使用LEFT JOIN NULL查询
  2. 记录是否存在更新。 -使用UPDATE INNER JOIN查询

关于前者,是否使用LEFT JOIN NULL或NOT IN或NOT EXISTS是最佳的解决方案,当然这是“依赖”的,这在SQL编码人员中经常引起争论。 此处使用的“左联接”确实避免了子查询。 但是,如果需要,请考虑这些途径。

# DELETE LAST SET OF TEMP DATA
dbSendQuery(mydb, "DELETE FROM tempTable")

# APPEND R DATA FRAME TO TEMP DATA
dbWriteTable(mydb, value=csvData, name=tempTable, row.names=FALSE,
             field.types=list(PrimaryKey="VARCHAR(10)", Column2="VARCHAR(255)", 
                              Column3="VARCHAR(255)", Timestamp="TIMESTAMP"), 
                              append=TRUE, overwrite=FALSE)

# LEFT JOIN ... NULL QUERY TO APPEND NEW RECORDS NOT IN TABLE
dbSendQuery(mydb, "INSERT INTO finalTable (Column1, Column2, Column3, Timestamp)
             SELECT Column1, Column2, Column3, Timestamp 
             FROM tempTable f
             LEFT JOIN finalTable t  
             ON f.PrimaryKey = t.PrimaryKey
             WHERE f.PrimaryKey IS NULL;")

# UPDATE INNER JOIN QUERY TO UPDATE MATCHING RECORDS
dbSendQuery(mydb, "UPDATE finalTable f
             INNER JOIN tempTable t  
             ON f.PrimaryKey = t.PrimaryKey
             SET f.Column1 = t.Column1,
                 f.Column2 = t.Column2,
                 f.Column3 = t.Column3,
                 f.Timestamp = t.Timestamp;")

在大多数情况下,如果您需要更改数据库,上述查询将在大多数SQL后端中符合要求。 一些RDMS不支持UPDATE INNER JOIN但是可以使用等效的替代方法。 最后,此路由的优点在于所有处理都在SQL引擎而不是R中处理。

听起来您正在尝试进行升级。

我对MySQL有点生锈,但是一般的想法是您需要一个临时表来上载新的CSV,然后在数据库本身中执行插入/更新。

为此,您需要将dbSendQuery与INSERT ON DUPLICATE UPDATE一起使用。

http://dev.mysql.com/doc/refman/5.7/zh-CN/insert-on-duplicate.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM