英文:
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. 
rbinded as per R terminology orunioned 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 )
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论