Here is mtcars data in the MonetDBLite database file.
library(MonetDBLite)
library(tidyverse)
library(DBI)
dbdir <- getwd()
con <- dbConnect(MonetDBLite::MonetDBLite(), dbdir)
dbWriteTable(conn = con, name = "mtcars_1", value = mtcars)
data_mt <- con %>% tbl("mtcars_1")
I want to use dplyr mutate to create new variables and add (commit!) that to the database table? Something like
data_mt %>% select(mpg, cyl) %>% mutate(var = mpg/cyl) %>% dbCommit(con)
The desired output should be same when we do:
dbSendQuery(con, "ALTER TABLE mtcars_1 ADD COLUMN var DOUBLE PRECISION")
dbSendQuery(con, "UPDATE mtcars_1 SET var=mpg/cyl")
How can do that?
Here's a couple of functions,
create
andupdate.tbl_lazy
.They respectively implement
CREATE TABLE
, which was straightforward, and theALTER TABLE
/UPDATE
pair which is much less so:CREATE
example:
UPDATE
example 1, define 2 new numeric columns :
example 2, modify an existing column, create 2 new columns of different types :
example 3, update where:
example 4 : update by group
GENERAL NOTES
The code uses uses
dbplyr::translate_sql
so we can use R functions or native ones alike just like in good oldmutate
calls.update
can only be used after onefilter
call OR onegroup_by
call OR zero of each, anything else and you'll get an error or unexpected results.The
group_by
implementation is VERY hackish, so no room for defining columns on the fly or grouping by an operation, stick to the basics.update
andcreate
both returntbl(con, table_name)
, which means you can chain as manycreate
orupdate
calls as you wish, with the appropriate amount ofgroup_by
andfilter
in between. In fact all of my 4 examples can be chained.To hammer the nail,
create
doesn't suffer from the same restrictions, you can have as muchdbplyr
fun as desired before calling it.I didn't implement type detection, so I needed the
new_type
parameter, it is recycled in thepaste
call of thealter_queries
definition in my code so it can be a single value or a vector.One way to solve the latter would be to extract the variables from the
translations
variable, find their types indbGetQuery(con,"PRAGMA table_info(iris)")
. Then we need coercion rules between all existing types, and we're set. But as different DBMS have different types I can't think of a general way to do it, and I don't knowMonetDBLite
.