| Title: | SQL for Dataframes, but with Ducks |
|---|---|
| Description: | An SQL interface for R dataframes built on the DuckDB embedded analytical database. Dataframes are registered directly with an in-process DuckDB instance and queried with standard SQL, so analyses can join, filter, aggregate and reshape R objects with SQL while results are returned as dataframes, without copying data to an external database server. The package wraps the 'duckdb' R package with a DBI-compliant connection and provides a small, checked surface for the common register-query-unregister workflow. The underlying engine and its vectorised execution model are described in Raasveldt and Mühleisen (2019) <doi:10.1145/3299869.3320212>. |
| Authors: | Phill Clarke [aut, cre] |
| Maintainer: | Phill Clarke <[email protected]> |
| License: | AGPL-3 |
| Version: | 0.2.1 |
| Built: | 2026-11-14 12:05:40 UTC |
| Source: | https://github.com/phillc73/duckdf |
cleanup removes all traces of the named duckdb database from
disk and closes the shared in-memory connection.
cleanup(db_name)cleanup(db_name)
db_name |
String. The specific name of the duckdb database to be removed. Required. |
Invisibly, the character vector of files removed. Missing files are not errors.
## Not run: # Query the mtcars dataframe and write the whole table to an on-disk duckdb duckdf("SELECT mpg, cyl FROM mtcars WHERE disp >= 200", persist = TRUE) # Remove all traces of the on-disk duckdb database called mtcars duckdf::cleanup("mtcars") ## End(Not run)## Not run: # Query the mtcars dataframe and write the whole table to an on-disk duckdb duckdf("SELECT mpg, cyl FROM mtcars WHERE disp >= 200", persist = TRUE) # Remove all traces of the on-disk duckdb database called mtcars duckdf::cleanup("mtcars") ## End(Not run)
duckdf runs a SQL query against R dataframes registered as
zero-copy DuckDB views. Like SQL? Like dataframes? Like ducks?
duckdf( query, persist = FALSE, df_name = NULL, df = NULL, params = NULL, db_name = NULL, as.data.table = FALSE )duckdf( query, persist = FALSE, df_name = NULL, df = NULL, params = NULL, db_name = NULL, as.data.table = FALSE )
query |
String. A single SQL statement (multi-statement queries are rejected whenever the json extension is available; in its absence the degraded path executes them last-wins). Required. |
persist |
Logical. If TRUE, delegate to |
df_name |
Character vector of variable names holding
dataframes - registered verbatim, the extractor is not invoked.
This is also the escape hatch: multi-statement queries and DDL
(CREATE TABLE ...) pass through raw. A table created this way
stays on the shared connection, is not listed by
|
df |
Named list of dataframes - registered under their list
names; those names are the extraction candidate scope. Preferred
form inside functions: no caller-frame dependency. When the json
extension is unavailable, the degraded path passes DDL and
multi-statement queries through as |
params |
Parameter list forwarded to |
db_name |
String. On-disk database name for the persist path. The extractor is not invoked when df_name is given, so multi-statement queries and DDL also pass through here. |
as.data.table |
Logical. Return a data.table instead of a plain data.frame. |
Bare queries (no df/df_name) use DuckDB's
json extension to extract table names; machines where the
extension cannot be autoloaded should pass df_name or
df (df runs a once-per-session availability probe;
neither form needs the extension for its work). Offline, the
degraded path executes multi-statement queries last-wins and
passes DDL through, mirroring df_name's documented
passthrough semantics, and scope errors surface as engine errors
at execution.
The query result: data.frame by default, data.table when
as.data.table = TRUE.
## Not run: # Query the mtcars dataframe duckdf("SELECT mpg, cyl FROM mtcars WHERE disp >= 200") # Parameterised, function-safe form cyl_query <- function(x) { duckdf("SELECT mpg FROM mtcars WHERE cyl = $1", df = list(mtcars = mtcars), params = list(x)) } # Read a csv without registering anything - DuckDB reads it natively duckdf("SELECT * FROM read_csv_auto('myfile.csv')") ## End(Not run)## Not run: # Query the mtcars dataframe duckdf("SELECT mpg, cyl FROM mtcars WHERE disp >= 200") # Parameterised, function-safe form cyl_query <- function(x) { duckdf("SELECT mpg FROM mtcars WHERE cyl = $1", df = list(mtcars = mtcars), params = list(x)) } # Read a csv without registering anything - DuckDB reads it natively duckdf("SELECT * FROM read_csv_auto('myfile.csv')") ## End(Not run)
duckdf_views lists the views currently registered on the
shared duckdf connection.
duckdf_views()duckdf_views()
A data.frame with one row per registered view: the view name and the class of the backing R object. Empty (not an error) when nothing is registered. Read-only: no unregistration happens here.
## Not run: # See what duckdf is currently quacking about duckdf::duckdf_views() ## End(Not run)## Not run: # See what duckdf is currently quacking about duckdf::duckdf_views() ## End(Not run)
gander returns some brief information about an on-disk
duckdb database.
gander(db_name, show_types = FALSE)gander(db_name, show_types = FALSE)
db_name |
String. The specific name of the duckdb database to have a gander at. Required. |
show_types |
Logical. Add column type information to each element. Default FALSE. |
A named list, one element per table in the database, each
holding the table's first five rows. Element names are the table
names. With show_types = TRUE each element gains a
"types" attribute naming the columns and their types.
## Not run: # Query the mtcars dataframe and write the whole table to an on-disk duckdb duckdf("SELECT mpg, cyl FROM mtcars WHERE disp >= 200", persist = TRUE) # Gander at the tables in the on-disk duckdb database for mtcars, # showing column types duckdf::gander("mtcars", show_types = TRUE) ## End(Not run)## Not run: # Query the mtcars dataframe and write the whole table to an on-disk duckdb duckdf("SELECT mpg, cyl FROM mtcars WHERE disp >= 200", persist = TRUE) # Gander at the tables in the on-disk duckdb database for mtcars, # showing column types duckdf::gander("mtcars", show_types = TRUE) ## End(Not run)
ingest loads a CSV file via duckdb_read_csv and
returns either a new data.frame, data.table, tibble or an on-disk
duckdb.
ingest(name, files, persist = TRUE, object_type = "data.frame", ...)ingest(name, files, persist = TRUE, object_type = "data.frame", ...)
name |
String. The name of the new data.frame, data.table, tibble or on-disk duckdb. Required. |
files |
String. The name of the CSV file to ingest. File must be located in the current working directory. Required. |
persist |
Logical. If TRUE the CSV lands as table |
object_type |
String. The type of object to return when
|
... |
All |
With persist = TRUE: the duckdb_read_csv result,
invisibly. With persist = FALSE: the ingested data as an
object of object_type. Callers capture:
mtcars2 <- ingest("mtcars2", "mtcars.csv", persist = FALSE).
## Not run: # Ingest the filename.csv file as an on-disk duckdb # database named `descriptive_name` duckdf::ingest(name = "descriptive_name", files = "filename.csv") # Ingest the filename.csv file as a data.table, returned for capture mtcars2 <- duckdf::ingest(name = "mtcars2", files = "filename.csv", persist = FALSE, object_type = "data.table") ## End(Not run)## Not run: # Ingest the filename.csv file as an on-disk duckdb # database named `descriptive_name` duckdf::ingest(name = "descriptive_name", files = "filename.csv") # Ingest the filename.csv file as a data.table, returned for capture mtcars2 <- duckdf::ingest(name = "mtcars2", files = "filename.csv", persist = FALSE, object_type = "data.table") ## End(Not run)
persist executes a query against an on-disk duckdb database
in the current working directory, creating it (and writing the
queried dataframes as tables) when it does not exist.
persist( query, db_name = NULL, df = NULL, df_name = NULL, params = NULL, as.data.table = FALSE )persist( query, db_name = NULL, df = NULL, df_name = NULL, params = NULL, as.data.table = FALSE )
query |
String. A single SQL statement (multi-statement
queries are rejected). The name of the
on-disk database will be the same as the first named dataframe
in this query string, unless specified differently in
|
db_name |
String. Specifies the name of the on disk duckdb to read from or write to. If an on-disk duckdb matching this name is not found in the current working directory, one will be created (writing the df/df_name tables); if it exists, df and df_name are an error - the query runs against the data already on disk. |
df |
Named list of dataframes to write as tables when creating the database; those names are the extraction candidate scope. |
df_name |
Character vector of variable names in the calling scope to write as tables - registered verbatim, the extractor is not invoked, so multi-statement queries and DDL also pass through here. |
params |
Parameter list forwarded to |
as.data.table |
Logical. Return a data.table instead of a plain data.frame. |
Bare queries (no df/df_name) use DuckDB's
json extension to extract table names; machines where the
extension cannot be autoloaded should pass df_name or
df together with db_name, which never touch the
extractor.
The results of the SQL statement: data.frame by default,
data.table when as.data.table = TRUE. All tables are
written before any query executes; the connection is closed on
every exit path.
## Not run: # Query the mtcars dataframe and write the whole table to an on-disk duckdb duckdf::persist("SELECT mpg, cyl FROM mtcars WHERE disp >= 200") # Same, with a different database name duckdf::persist("SELECT mpg, cyl FROM mtcars WHERE disp >= 200", db_name = "mtcars_duckdb") ## End(Not run)## Not run: # Query the mtcars dataframe and write the whole table to an on-disk duckdb duckdf::persist("SELECT mpg, cyl FROM mtcars WHERE disp >= 200") # Same, with a different database name duckdf::persist("SELECT mpg, cyl FROM mtcars WHERE disp >= 200", db_name = "mtcars_duckdb") ## End(Not run)