将 MySQL 转储导入 R(不需要 MySQL 服务器)

Import MySQL dump into R (without requiring MySQL server)

RMySQLsqldf 等软件包允许与本地或远程数据库服务器进行交互。我正在创建一个 portable 项目,该项目涉及在并不总是可以访问 运行 服务器但 的情况下(或在设备上)导入 sql 数据do 始终可以访问最新的 .sql 数据库转储。

目标似乎很简单:将 .sql 转储导入 R 而无需 MySQL 服务器的参与。 更具体地说,我会喜欢创建一个列表列表,其中的元素对应于 .sql 转储中定义的任何数据库(可能有多个),而这些元素又由这些数据库中的 table 组成。

为了使其可重现,让我们以样本 sportsdb SQL 文件 here 为例——如果你解压它,它被称为 sportsdb_sample_mysql_20080303.sql.

有人会认为 sqldf 可以做到:

read.csv.sql('sportsdb_sample_mysql_20080303.sql', sql="SELECT * FROM addresses") Error in sqliteSendQuery(con, statement, bind.data) : error in statement: no such table: addresses

尽管转储中确实有一个 table 地址。 sqldf 列表中的 This post 提到了同样的错误,但没有解决方案。

然后ProjectTemplate包里有一个sql.reader函数,看起来很有前途。四处寻找,可以找到该函数的源代码 here,它假设有一个 运行 数据库服务器并依赖于 RMySQL——这不是我需要的。

所以...我们似乎 运行 别无选择。来自 hivemind 的任何帮助表示赞赏!

(重申一下,我 不是 寻找依赖于访问 SQL 服务器的解决方案;使用 dbReadTable 来自 RMySQL 包。我非常想绕过服务器并直接从 .sql 转储文件中获取数据。)

根据您想从 table 中提取的内容,以下是您如何处理数据

numLines <- R.utils::countLines("sportsdb_sample_mysql_20080303.sql")
# [1] 81266

linesInDB <- readLines("sportsdb_sample_mysql_20080303.sql",n=60)

然后你可以做一些正则表达式来获取 table 的名称(在 CREATE TABLE 之后)、列名(在第一个括号之间)和值(在 CREATE TABLE 之后和之间的行第二个括号)

参考: Reverse engineering a mysqldump output with MySQL Workbench gives "statement starting from pointed line contains non UTF8 characters" error


编辑:针对 OP 的回答,如果我正确解释 python 脚本,它也会逐行读取它,过滤 INSERT INTO 行,解析为 csv,然后写入文件。这与我最初的建议非常相似。我在 R 中的版本如下。如果文件太大,最好使用其他 R 包

分块读取文件
options(stringsAsFactors=F)
library(utils)
library(stringi)
library(plyr)

mysqldumpfile <- "sportsdb_sample_mysql_20080303.sql"

allLines <- readLines(mysqldumpfile)
insertLines <- allLines[which(stri_detect_fixed(allLines, "INSERT INTO"))]
allwords <- data.frame(stri_extract_all_words(insertLines, " "))
d_ply(allwords, .(X3), function(x) {
    #x <- split(allwords, allwords$X3)[["baseball_offensive_stats"]]
    print(x[1,3])

    #find where the header/data columns start and end
    valuesCol <- which(x[1,]=="VALUES")
    lastCols <- which(apply(x, 2, function(y) all(is.na(y))))
    datLastCol <- head(c(lastCols, ncol(x)+1), 1) - 1

    #format and prepare for write to file
    df <- data.frame(x[,(valuesCol+1):datLastCol])
    df <- setNames(df, x[1,4:(valuesCol-1)])
    #type convert before writing to file otherwise its all strings
    df[] <- apply(df, 2, type.convert)
    #write to file
    write.csv(df, paste0(x[1,3],".csv"), row.names=F)
})

我认为您不会找到一种方法来导入 sql 转储(其中包含多个带引用的表),然后在 R 中对它们执行任意 sql 查询。这基本上要求 R 包在 R 中 运行 一个完整的数据库服务器(与创建转储的服务器兼容)。

我建议从您的数据库 (see here) 中将您需要的 tables/select 语句导出为 CSV。如果您只能从转储工作并且不想为转换设置服务器,您可以使用一些简单的正则表达式将转储中的 insert 语句转换为一堆 CSV 文件,用于表使用您选择的工具,例如 sedawk(或者甚至是其他答案所建议的 R,但对于此文件大小来说这可能相当慢)。

我会不情愿地回答我自己的问题,使用 +bnord 和 +chinsoon12(他们都贡献了拼图的一部分)的输入。

简短回答:没有开箱即用的解决方案。正如 +bnord 指出的那样,最好在服务器端修复它(例如,通过导出为 CSV 格式用我的sql转储)。但是,正如我的问题所指出的,我正在寻找一种解决方案,使我能够绕过服务器使用 sql 转储。

所以如果我们必须使用转储,怎么办?核心的手动方法是使用正则表达式将 INSERT 语句转换为 CSV,或者 (1) 在 R 外部使用 .sql 文本文件上的 sedawk( +bnord),或 (2) 在 R 内部,grepgsub 加载 readLines (+chinsoon12)。

一些好心人写道 a python script that can convert sql dumps to CSV。这需要另一个(对 install/maintain 来说可能并不平凡)软件,所以这不是我所希望的答案,但它看起来确实是一个很好的模型,以防有人想在 R 中重新发明轮子。

现在我会坚持我的做法(在 Windows)运行 MySQL 社区服务器并使用 WorkBench 导入转储,然后再谈从 R 到本地服务器。这是一种非常间接的方法,由于 MySQL 的访问权限系统难以理解(特别烦人,因为它都在 ASCII 文本文件中),但这是唯一的方法现在看来。感谢大家的参与!

(如果出现更好、更完整的答案,我会很乐意接受,如果可能的话将其转为评论。)