英文:
Get the results sets of a parametrized query `rbind`ed *and* directly in the database using R's `DBI`
问题
使用package:DBI
,我需要:
- 运行一个带有不同参数(即参数向量)的参数化查询;
- 获取连接的结果集(根据R术语的
rbind
或根据SQL术语的union
进行连接); - 并在数据库中获取生成的表以进行进一步操作。
dbBind()
/dbGetquery()
满足了要求1和2,但然后我需要使用dbWriteTable()
将生成的数据帧写入数据库,这是低效的:
library(DBI)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(con, "iris", iris)
res <- dbGetQuery(con,
"select * from iris where Species = ?",
params = list(c("setosa", "versicolor")))
dbWriteTable(con, "mytable", res)
相反,dbExecute()
满足要求3,但我认为它没有"rbind特性"。当然,这会引发错误,因为表将被覆盖:
dbExecute(con,
"create table mytable as select * from iris where Species = ?",
params = list(c("setosa", "versicolor")))
如何以最高效/推荐的方式进行操作?
备注:
- 我不是数据库管理员,只能通过R访问数据库。
- 我的示例过于简单,可以在单个查询中实现。我的用例确实需要多次使用不同参数运行参数化查询。
- 我必须使用Oracle,但我对即使不适用于Oracle的解决方案也感兴趣。
英文:
Using package:DBI
, I need to:
- run a parametrized query with different parameters (i.e. a vector of parameters);
- get the results sets concatenated (i.e.
rbind
ed as per R terminology orunion
ed as per SQL terminology); - and get the resulting table in the database for further manipulation.
dbBind()
/dbGetquery()
fullfils requirements 1 and 2, but I then need to write the resulting data frame to the database using dbWriteTable()
, which is ineficient:
library(DBI)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
dbWriteTable(con, "iris", iris)
res <- dbGetQuery(con,
"select * from iris where Species = ?",
params = list(c("setosa", "versicolor")))
dbWriteTable(con, "mytable", res)
Conversely, dbExecute()
fulfils requirement 3, but I don't think it has the "rbind
feature". Of course, this throw an error because the table would get overwritten:
dbExecute(con,
"create table mytable as select * from iris where Species = ?",
params = list(c("setosa", "versicolor")))
What is the most efficient/recommended way of doing so?
Notes:
- I am not the DBA and can only access the database through R.
- My example is too trivial and could be achieved in a single query. My use case really requires a parametrized query to be run multiple times with different parameters.
- I have to use Oracle, but I am interested in a solution even if it don't works with Oracle.
答案1
得分: 1
- 使用第一个参数创建表格,然后将其他参数插入其中。
library(RSQLite)
con <- dbConnect(SQLite())
dbWriteTable(con, "iris", iris)
parms <- c("setosa", "versicolor")
dbExecute(con, "create table mytable as
select * from iris where Species = ?",
params = parms[1])
for (p in parms[-1]) {
dbExecute(con, "insert into mytable
select * from iris where Species = ?",
params = p)
}
# 检查
res <- dbGetQuery(con, "select * from mytable")
str(res)
- 交替生成执行所有操作的SQL语句。sqldf引入了RSQLite和gsubfn,后者提供了fn$,以实现文本替换。
library(sqldf)
con <- dbConnect(SQLite())
dbWriteTable(con, "iris", iris)
parms <- c("setosa", "versicolor")
parmString <- toString(sprintf("'%s'", parms))
fn$dbExecute(con, "create table mytable as
select * from iris where Species in ($parmString)")
# 检查
res <- dbGetQuery(con, "select * from mytable")
str(res)
- (2)的变种是插入适当数量的问号。
library(sqldf)
con <- dbConnect(SQLite())
dbWriteTable(con, "iris", iris)
params <- list("setosa", "versicolor")
quesString <- toString(rep("?", length(params))
fn$dbExecute(con, "create table mytable as
select * from iris where Species in ($quesString)", params = params)
# 检查
res <- dbGetQuery(con, "select * from mytable")
str(res)
英文:
1) Create the table with the first parameter and then insert each of the others into it.
library(RSQLite)
con <- dbConnect(SQLite())
dbWriteTable(con, "iris", iris)
parms <- c("setosa", "versicolor")
dbExecute(con, "create table mytable as
select * from iris where Species = ?",
params = parms[1])
for (p in parms[-1]) {
dbExecute(con, "insert into mytable
select * from iris where Species = ?",
params = p)
}
# check
res <- dbGetQuery(con, "select * from mytable")
str(res)
2) Alternately generate the text of an SQL statement to do it all. sqldf pulls in RSQLite and gsubfn which supplies fn$ that enables the text substitution.
library(sqldf)
con <- dbConnect(SQLite())
dbWriteTable(con, "iris", iris)
parms <- c("setosa", "versicolor")
parmString <- toString(sprintf("'%s'", parms))
fn$dbExecute(con, "create table mytable as
select * from iris where Species in ($parmString)")
# check
res <- dbGetQuery(con, "select * from mytable")
str(res)
3) A variation of (2) is to insert the appropriate number of question marks.
library(sqldf)
con <- dbConnect(SQLite())
dbWriteTable(con, "iris", iris)
params <- list("setosa", "versicolor")
quesString <- toString(rep("?", length(params)))
fn$dbExecute(con, "create table mytable as
select * from iris where Species in ($quesString)", params = params)
# check
res <- dbGetQuery(con, "select * from mytable")
str(res)
答案2
得分: 0
根据 @r2evans 的评论和 @G.Grothendieck 的回答,我使用了一个参数化查询,直接将数据插入到表中。
首先,我创建了一个具有适当列的表来收集结果:
library(DBI)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
create_table <-
"
CREATE TABLE
warpbreaks2 (
breaks real,
wool text,
tension text
);
"
dbExecute(con, create_table)
然后,我执行了一个 INSERT INTO
步骤:
dbWriteTable(con, "warpbreaks", warpbreaks)
insert_into <-
"
INSERT INTO
warpbreaks2
SELECT
warpbreaks.breaks,
warpbreaks.wool,
warpbreaks.tension
FROM
warpbreaks
WHERE
tension = ?;
"
dbExecute(con, insert_into, params = list(c("L", "M")))
这是一个示例用于说明的虚拟示例。可以更直接地实现,例如:
direct_query <-
"
CREATE TABLE
warpbreaks3 AS
SELECT
*
FROM
warpbreaks
WHERE
tension IN ('L', 'M');
"
dbExecute(con, direct_query)
英文:
Based on @r2evans comment and @G.Grothendieck answer, instead of query/download/combine/upload, I used a parameterized query that inserts directly into a table.
First, I created the table with the appropriate columns to collect the results:
library(DBI)
con <- dbConnect(RSQLite::SQLite(), ":memory:")
create_table <-
"
CREATE TABLE
warpbreaks2 (
breaks real,
wool text,
tension text
);
"
dbExecute(con, create_table)
Then I executed an INSERT INTO
step:
dbWriteTable(con, "warpbreaks", warpbreaks)
insert_into <-
"
INSERT INTO
warpbreaks2
SELECT
warpbreaks.breaks,
warpbreaks.wool,
warpbreaks.tension
FROM
warpbreaks
WHERE
tension = ?;
"
dbExecute(con, insert_into, params = list(c("L", "M")))
This is a dummy example for illustration purpose. It could be achieve more directly with e.g.:
direct_query <-
"
CREATE TABLE
warpbreaks3 AS
SELECT
*
FROM
warpbreaks
WHERE
tension IN ('L', 'M');
"
dbExecute(con, direct_query )
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论