如何以比这更快的方式将数据从 oracle 检索到 R?
How to retrieve data from oracle to R in a faster way than this?
这是我的数据框
trail_df= data.frame(d= seq.Date(as.Date("2020-01-01"), as.Date("2020-02-01"), by= 1),
AA= NA,
BB= NA,
CC= NA)
现在我将循环到 trail_df 的列并分别从 oracle 数据库中获取给定日期的列名数据,我正在这样做。
for ( i in 2:ncol(trail_df)){
c_name = colnames(trail_df)[i]
query = paste0("SELECT * FROM tablename WHERE ID= '",c_name,"' ") # this query would return Date and price
result= dbGetQuery(con, query) # con is the connection variable from db
for (k in nrow(trail_df)){
trail_df [which(as.Date(result[k,1])==as.Date(trail_df[,1])),i]= result[k,2]
# just matching the date in trail_df dataframe and pasting the value in front of respective column
}
}
这是代码片段和日期过滤,所有内容都已在实际代码中处理。
问题是,我有超过 6000 列和 500 行,我必须匹配日期(
因为日期是随机的)并把价格放在前面,现在这就像永远一样。
我是 R 语言的新手,如果有任何帮助可以在 R 中固定此代码或多进程,我将不胜感激。
这个答案有两个步骤:
- 使用参数化查询获取原始数据;和
- 将此数据转换为您想要的“宽”格式。
参数化查询
我的(第一个)建议是使用parameterized queries,这样更安全。相对于@RonakShah 的回答(使用 sprintf
),它可能不会提高速度,至少第一次不会。
但是,如果重复查询,a touch 可能会有所帮助:DBMS 倾向于 parse/optimize 查询并缓存此优化。当一个查询发生一点点变化时,这种缓存就不会发生,并且查询会被重新优化。在这种情况下,这种缓存失效是不必要的,如果我们使用绑定参数就可以避免。
query <- sprintf("SELECT * FROM tablename WHERE ID IN (%s)",
paste(rep("?", ncol(trail_df[-1])), collapse = ","))
query
# [1] "SELECT * FROM tablename WHERE ID IN (?,?,?)"
res <- dbGetQuery(con, query, params = list(trail_df$ID))
一些想法:
如果数据库的日期比您在这里的日期多很多,您可以通过减少日期范围查询来限制返回的数据。如果您的 trail_df
日期很近,这将很有效:
query <- sprintf("SELECT * FROM tablename WHERE ID IN (%s) and Date between ? and ?",
paste(rep("?", ncol(mtcars)), collapse = ","))
query
res <- dbGetQuery(con, query, params = c(list(trail_df$ID), as.list(range(df$d))))
如果你的日期变化很大,你最终查询的行比你实际需要的多,我建议你可以将你的 trail_df
日期上传到一个临时的 table 和类似于:
"select tb.Date, tb.ID, tb.Price
from mytemptable tmp
left join tablename tb on tmp.d = tb.Date
where ..."
重塑
看起来您的数据库 table 可能更“长”,而您希望它在框架中“宽”。有很多方法可以从长到宽 (examples) 进行重塑,但这些应该有效:
reshape2::dcast(res, Date ~ ID, value.var = "Price") # 'Price' is the 'value' column, unk here
tidyr::pivot_wider(res, id_cols = "Date", names_from = "ID", values.from = "Price")
这是我的数据框
trail_df= data.frame(d= seq.Date(as.Date("2020-01-01"), as.Date("2020-02-01"), by= 1),
AA= NA,
BB= NA,
CC= NA)
现在我将循环到 trail_df 的列并分别从 oracle 数据库中获取给定日期的列名数据,我正在这样做。
for ( i in 2:ncol(trail_df)){
c_name = colnames(trail_df)[i]
query = paste0("SELECT * FROM tablename WHERE ID= '",c_name,"' ") # this query would return Date and price
result= dbGetQuery(con, query) # con is the connection variable from db
for (k in nrow(trail_df)){
trail_df [which(as.Date(result[k,1])==as.Date(trail_df[,1])),i]= result[k,2]
# just matching the date in trail_df dataframe and pasting the value in front of respective column
}
}
这是代码片段和日期过滤,所有内容都已在实际代码中处理。
问题是,我有超过 6000 列和 500 行,我必须匹配日期( 因为日期是随机的)并把价格放在前面,现在这就像永远一样。
我是 R 语言的新手,如果有任何帮助可以在 R 中固定此代码或多进程,我将不胜感激。
这个答案有两个步骤:
- 使用参数化查询获取原始数据;和
- 将此数据转换为您想要的“宽”格式。
参数化查询
我的(第一个)建议是使用parameterized queries,这样更安全。相对于@RonakShah 的回答(使用 sprintf
),它可能不会提高速度,至少第一次不会。
但是,如果重复查询,a touch 可能会有所帮助:DBMS 倾向于 parse/optimize 查询并缓存此优化。当一个查询发生一点点变化时,这种缓存就不会发生,并且查询会被重新优化。在这种情况下,这种缓存失效是不必要的,如果我们使用绑定参数就可以避免。
query <- sprintf("SELECT * FROM tablename WHERE ID IN (%s)",
paste(rep("?", ncol(trail_df[-1])), collapse = ","))
query
# [1] "SELECT * FROM tablename WHERE ID IN (?,?,?)"
res <- dbGetQuery(con, query, params = list(trail_df$ID))
一些想法:
如果数据库的日期比您在这里的日期多很多,您可以通过减少日期范围查询来限制返回的数据。如果您的
trail_df
日期很近,这将很有效:query <- sprintf("SELECT * FROM tablename WHERE ID IN (%s) and Date between ? and ?", paste(rep("?", ncol(mtcars)), collapse = ",")) query res <- dbGetQuery(con, query, params = c(list(trail_df$ID), as.list(range(df$d))))
如果你的日期变化很大,你最终查询的行比你实际需要的多,我建议你可以将你的
trail_df
日期上传到一个临时的 table 和类似于:"select tb.Date, tb.ID, tb.Price from mytemptable tmp left join tablename tb on tmp.d = tb.Date where ..."
重塑
看起来您的数据库 table 可能更“长”,而您希望它在框架中“宽”。有很多方法可以从长到宽 (examples) 进行重塑,但这些应该有效:
reshape2::dcast(res, Date ~ ID, value.var = "Price") # 'Price' is the 'value' column, unk here
tidyr::pivot_wider(res, id_cols = "Date", names_from = "ID", values.from = "Price")