首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SQL将许多tsv文件连接到数据库中的单个表中,同时跟踪文件源(MonetDBLite)。

SQL将许多tsv文件连接到数据库中的单个表中,同时跟踪文件源(MonetDBLite)。
EN

Stack Overflow用户
提问于 2017-05-15 15:05:22
回答 3查看 304关注 0票数 1

我正在使用MonetDBLite R包创建一个MonetDB。我可以很好地使用这里的说明创建数据库表,代码如下:

代码语言:javascript
复制
library(DBI)
library(MonetDBLite)

# Write tsv file of mtcars
write.table(mtcars, "mtcars.tsv", row.names=FALSE, sep= "\t")

# Initialize MonetDB
dbdir <- "/Users/admin/my_directory"
con <- dbConnect(MonetDBLite::MonetDBLite(), dbdir)

# Write table
dbWriteTable(con, "test4", "mtcars.tsv", delim="\t")

下面的查询给出

代码语言:javascript
复制
> dbGetQuery(con, "SELECT * FROM test4 LIMIT 3")
mpg cyl  disp  hp drat    wt  qsec vs am gear carb
1  21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
2  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
3  22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1

到目前一切尚好。但是,假设我有另一个具有不同mpg值的文件mtcars2:

代码语言:javascript
复制
mtcars2 <- mtcars
mtcars2$mpg <- mtcars2$mpg + 5
write.table(mtcars2, "mtcars2.tsv", row.names= FALSE, sep = "\t")

我可以把它装到另一张桌子上:

代码语言:javascript
复制
dbWriteTable(con, "test5", "mtcars2.tsv", delim = "\t")
> dbGetQuery(con, "SELECT * FROM test5 LIMIT 3")
mpg cyl disp  hp drat    wt  qsec vs am gear carb
1 26.0   6  160 110 3.90 2.620 16.46  0  1    4    4
2 26.0   6  160 110 3.90 2.875 17.02  0  1    4    4
3 27.8   4  108  93 3.85 2.320 18.61  1  1    4    1

也没问题。但是我的问题是:稍后我想查找所有有6cyl的汽车的cyl,并知道它来自哪个数据集(mtcar还是mtcars2)。根据我对SQL索引的理解(这不是很多,基本上就是我读过的这里),我应该将所有数据放在一个表中,以便进行最有效的搜索。我尝试加载第一个tsv文件,然后使用ALTER TABLE test4 ADD dataset TEXTUPDATE test4 SET dataset = dataset1命令添加另一列-

代码语言:javascript
复制
dbSendQuery(con, "UPDATE test4 SET dataset = dataset1")
dbSendQuery(con, "UPDATE test4 SET dataset = 1")
> dbGetQuery(con, "SELECT * FROM test4 LIMIT 3")
mpg cyl disp  hp drat    wt  qsec vs am gear carb dataset
1 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4       1
2 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4       1
3 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1       1

但是,当我试图将mtcars2附加到表中时,它有不同数量的列(正如我所期望的那样,duh)。在跟踪数据来源的同时,用相同的列将来自许多tsv文件的数据连接到一个表中的最佳方法是什么?

编辑--正如您可能已经猜到的,真正的数据不是mtcars-它是扁平的tsv文件,长达数百万行,这意味着我希望避免将整个文件读入内存并使用R。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-05-16 12:27:32

按照xQbert的建议,我只使用SQL命令解决了问题(考虑到我的数据是10 s文件,每百万行长),这比bash命令更必要,而且速度更快。

代码语言:javascript
复制
library(DBI)
library(MonetDBLite)

# Write tsv file of mtcars
write.table(mtcars, "mtcars.tsv", row.names=FALSE, sep= "\t")

# Write tsv of second mtcars
mtcars2 <- mtcars
mtcars2$mpg <- mtcars2$mpg + 5
write.table(mtcars2, "mtcars2.tsv", row.names= FALSE, sep = "\t")

# Initialize MonetDB
dbdir <- "/Users/admin/"
con <- dbConnect(MonetDBLite::MonetDBLite(), dbdir)

# Write table
dbWriteTable(con, "test4", "mtcars.tsv", delim="\t")

# Add data source information
dbSendQuery(con, "ALTER TABLE test4 ADD source TEXT")
dbSendQuery(con, "UPDATE test4 SET source = 'dataset1'")

# Write second dataset to a temporary table
dbWriteTable(con, "temptable", "mtcars2.tsv", delim="\t")

# Add data source information
dbSendQuery(con, "ALTER TABLE temptable ADD source TEXT")
dbSendQuery(con, "UPDATE temptable SET source = 'dataset2'")

# Insert temp table into main table
dbSendQuery(con, "INSERT INTO test4 SELECT * FROM temptable")

# Drop temp table
dbSendQuery(con, "DROP TABLE temptable")

# Checking the data, truncated for clarity
> dbGetQuery(con, "SELECT * FROM test4")
mpg cyl  disp  hp drat    wt  qsec vs am gear carb   source
1  21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4 dataset1
2  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4 dataset1
3  22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1 dataset1
...
33 26.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4 dataset2
34 26.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4 dataset2
35 27.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1 dataset2
...
64 26.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2 dataset2

很抱歉,如果我在问题中没有明确指出我的数据比mtcar大得多--如果您有中等大小的数据,data.tables包可能是一个比数据库更好的解决方案。

票数 3
EN

Stack Overflow用户

发布于 2017-05-15 15:48:09

您应该能够在读取文件之后执行dbWriteTable(),在data.frame中创建一个新变量。类似于:

代码语言:javascript
复制
  library(DBI)
  library(MonetDBLite)
  library(data.table)

  # Write tsv file of mtcars
  tmp <- tempfile()
  write.table(mtcars, tmp, row.names=FALSE, sep= "\t")

  # Initialize MonetDB
  dbdir <- "~/Desktop/temp"
  con <- dbConnect(MonetDBLite::MonetDBLite(), dbdir)

  test4df <- fread(tmp)
  test4df$dataset <- 1
  dbWriteTable(con, "test4", test4df)

  dbReadTable(con, "test4")

  test5df <- fread(tmp)
  test5df$mpg <- test5df$mpg + 5
  test5df$dataset <- 2
  dbWriteTable(con, "test4", test5df, append = TRUE)

  dbReadTable(con, "test4")

编辑(关于不打开文件的建议)

如果您想在一次不打开文件的情况下工作,您可以这样做来修改文件并附加另一个字段。正如我所写的,这将适用于bash操作系统。

代码语言:javascript
复制
infile <- tmp
outfile <- tempfile()

# open connections
incon <- file(description = infile, open = "r")
outcon <- file(description = outfile, open = "w")

# count the number of lines (this will work only with Mac/Linux)
com <- paste("wc -l ", infile, " | awk '{ print $1 }'", sep="")
n <- system(command=com, intern=TRUE)

# work with the first line
txt <- scan(file = incon, what = character(), nlines=1, quiet=TRUE)
txt <- c(txt, "dataset")
cat(paste(txt, collapse = "\t"), "\n", file = outcon, sep = "")

# work with the rest of the file
for(i in 2:n) {
  txt <- scan(file = incon, what = character(), nlines=1, quiet=TRUE)
  txt <- c(txt, "1")
  cat(paste(txt, collapse = "\t"), "\n", file = outcon, sep = "")
}
close(incon);close(outcon)
dbWriteTable(con, "test4", outfile, delim = "\t")
# do the similar for other files
票数 0
EN

Stack Overflow用户

发布于 2017-05-17 07:19:18

下面是我要做的事情,给出一组文件,它们在最后一个表中具有相同的结构和文件名,否则就是来自所有文件的数据的组合:

代码语言:javascript
复制
# say we have those files
write.table(mtcars, "mtcars1.tsv", row.names=FALSE, sep= "\t")
write.table(mtcars, "mtcars2.tsv", row.names=FALSE, sep= "\t")

# write them individually, and add a column that contains the file name
dbWriteTable(con, "mtcars1", "mtcars1.tsv", delim="\t")
dbSendQuery(con, "ALTER TABLE mtcars1 ADD COLUMN file STRING DEFAULT 'mtcars1.tsv';")
dbWriteTable(con, "mtcars2", "mtcars2.tsv", delim="\t")
dbSendQuery(con, "ALTER TABLE mtcars2 ADD COLUMN file STRING DEFAULT 'mtcars2.tsv';")

# now combine into a new table
dbSendQuery(con, "CREATE TABLE mtcars_mat AS SELECT * FROM mtcars1 UNION ALL SELECT * FROM mtcars2")

# or a view if you don't need to modify the data in the mtcars table (faster)
dbSendQuery(con, "CREATE view mtcars AS SELECT * FROM mtcars1 UNION ALL SELECT * FROM mtcars2")



# and here is the same as a loop with a filename glob and some added robustness (handy if you have 1000 files)
files <- Sys.glob("/some/path/mtcars*.tsv")
tables <- dbQuoteIdentifier(con, tools::file_path_sans_ext(basename(files)))
dbBegin(con)
for (i in 1:length(files)) {
  dbWriteTable(con, tables[i], files[i], delim="\t", transaction=FALSE)
  dbSendQuery(con, paste0("ALTER TABLE ", tables[i], " ADD COLUMN file STRING DEFAULT ",dbQuoteString(con, files[i]),";"))
}
dbSendQuery(con, paste0("CREATE TABLE somefinalresult AS ", paste0("SELECT * FROM ",tables, collapse=" UNION ALL ")))
# remove the parts again, optional
dbSendQuery(con, paste0("DROP TABLE ", tables, ";", collapse=" "))
dbCommit(con)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43982851

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档