A 'dplyr' Back End for Databases
Overview
A 'dplyr' back end for databases that allows you to work with remote database tables as if they are in-memory data frames. Basic features work with any database that has a 'DBI' back end; more advanced features require 'SQL' translation to be provided by the package author.
Lifecycle changes
- Newly deprecated:
- dbplyr 1st edition backends no longer work. This concludes over 2 years of work with backend developers to get everyone moved over to the 2nd edition (#1197).
as.sql(), as part of major internal refactoring of howsql()andident()are used (#1752).- The
cteargument ofcollect(),compute(),db_sql_render(),remote_query(), andshow_query(); passsql_options = sql_options(cte = TRUE)instead.collect()andcompute()gain ansql_optionsargument to support this (#1834). do(). Usecollect()then your favourite tidyverse functions instead (#1767).escape_ansi(). Useescape(x, con = dialect_ansi())instead (#1793).memdb_frame()no longer accepts data frames; this was never explicitly supported but worked by coincidence. Usecopy_to(memdb(), df)instead (#1704).sql_expr_matches(); provide anis_not_distinct_from()translation insql_translation()instead (#1803).src_memdb()andtbl_memdb(); usememdb()andcopy_to(memdb(), df)instead. There's also a newlocal_memdb_frame()for use in tests (#1704).str_like(ignore_case = ); usestr_ilike()instead (@edward-burn, #1630).- Previously-warning deprecations are defunct (#1834):
Show all changes in 2.6.0Hide the rest of the changes in 2.6.0
- Passing extra
...toacross()/if_all()/if_any()(deprecated in 2.3.0, 2023-01-16). - Using
by = character()to perform a cross join (deprecated in dplyr 1.1.0, 2023-01-29). compute(temporary = FALSE)without aname(deprecated in 2.3.3, 2023-07-07).sql_random()(deprecated in 2.3.2, 2023-03-21).sql_query_append()with a lazy table forfrom(deprecated in 2.3.2, 2023-03-21).tbl_sql(check_from)(deprecated in 2.5.0, 2024-03-15).- Previously-defunct functions have been removed:
group_by(add = ), deprecated in dplyr 1.0.0 (2020-06-01) (#1632).partial_eval(var), deprecated in 2.2.0 (2022-06-05) (#1632).src_sql(), deprecated in 1.4.0 (2019-04-23) (#1632).win_rank_tdata(), deprecated in 2.4.0 (2023-10-25) (#1642). (This is earlier than our usual policy because it was only used by the Teradata backend.)- Internal testing functions have been removed:
src_test(),test_frame(),test_load(),test_register_src(), andtest_register_con()(#1712). build_sql(),sql_expr(), andsql_call2()are superseded in favour ofsql_glue()andsql_glue2()(#1249).sql_options()is no longer marked experimental.
New features
New backends
- ADBC (via {adbi}, #1787) and JDBC (via {RJDBC}, #1359) connections are supported. Both use the connection name/class to dispatch to SQL dialects for existing backends. This is made possible by
sql_dialect(), a new generic that allows connections to choose a SQL dialect (#1624). If the default dialect is incorrect, you can override it withwith_dialect()(#1784). - IBM DB2 (@shearerpmm, #1800). Includes translations for
paste()/paste0()(using||), DB2-specific casts,runif(), string functions, date functions, clock helpers, statistical aggregates, and more.
New verb support
bind_queries()makes it easy to combine multiple lazy queries usingUNION ALL(#1342). It's the dbplyr equivalent ofdplyr::bind_rows().filter_out(), from dplyr 1.2.0, is now translated. The combined condition is wrapped inis_distinct_from(., TRUE), producing backend-appropriate SQL such asIS DISTINCT FROM TRUEon PostgreSQL orIS NOT TRUEon SQLite, so rows where the condition isNAare kept (#1803).mutate()gains.orderand.framearguments for specifying window function ordering and frame bounds within a single mutate call, similar to how.byworks for grouping (#1542).
New function translations
anyNA()is translated to SQL in the same way asany(is.na(x))(#1814).as(x, "type")is translated toCAST(x AS type), allowing you to cast to arbitrary database types not covered by the standardas.*()functions (#1729).is_distinct_from()andis_not_distinct_from()exposeIS DISTINCT FROM/IS NOT DISTINCT FROMsemantics with backend-specific dialects (#1803).%notin%(introduced in R 4.6.0) is translated toNOT IN(#1820).
Other new helpers
last_sql()retrieves the most recent SQL query generated by dbplyr, which is useful for debugging (#1471).- The
copyargument of join, set, and row operations accepts"inline"to usecopy_inline()instead of copying to a temporary table (#863).
Extensions
The following changes and new capabilities are of interest to dbplyr backend developers:
db_supports_table_alias_with_as()andsupports_window_clause()generics have been removed. They were not used by any packages and are now part of thenew_sql_dialect()data structure (#1760).db_table_drop_if_exists()is a new generic that allows backends to customize how tables are dropped whenoverwrite = TRUE(#1695). This was added to support Oracle.db_table_temporary()has been renamed tosql_table_temporary()for consistency with other SQL generation functions (#1760).dialect_*()translations use (approximately) correct quoting for all backends, so the generated SQL looks more like what you'll actually get when connected to a real database (#1464).remote_table()returns ansql()object containing the (correctly quoted) table identifier, rather than the internaldbplyr_table_path. This makes the result suitable for inlining intobuild_sql()andsql_glue2()(#1807).- New
sql_dialect()generic allows database connections to choose a SQL dialect, usingnew_sql_dialect()to create asql_dialectclass.new_sql_dialect()allows you to customize SQL generation including how identifiers are quoted (#1624). set_op_query()no longer has anallargument.sql_check_na_rm()is exported for use in other backends (#1483).sql_escape_string()defaults to using'(#1701).sql_glue()andsql_glue2()are exported and provide a convenient syntax for building SQL strings;sql_glue2()adds support for type markers (#1249).sql_infix()no longer has aconargument; the connection needs to be determined at call time, not at definition time.sql_optimise()is no longer used. It was only used for two cases (filter + summarise and arrange + summarise), and these are handled at a higher level (#1720). It will be removed in a future version.- New
sql_set_op_method()generic allows set operations (union(),intersect(),setdiff()) to customize the SQL keyword, e.g. usingUNION DISTINCTinstead ofUNIONfor databases that require it, orMINUSinstead ofEXCEPTfor Oracle (#1596).
SQL translation improvements
- Single-table SELECT queries use unqualified
*(e.g.SELECT *) instead of table-qualified*(e.g.SELECT "df".*) for most backends. Oracle and Teradata continue to use qualified stars as required by their syntax (#1577, #1485). .sqlpronoun makes it a little easier to use known SQL functions in packages, requiring only@importFrom dbplyr .sql(#1117). Now you can writedb |> mutate(.sql$custom_sql_function(x, y, z))and only need to import one function (.sql) to quiet allR CMD checknotes.- Custom translations of functions starting with
.work (@MichaelChirico, #1529). piis no longer translated toPI(). This caused problems if you had a column calledpi(#1531).arrange()is applied consecutively, matching dplyr's behavior, e.g.arrange(y) |> arrange(x)is equivalent toarrange(x, y). Emptyarrange()preserves existing ordering instead of clearing it (#789)..data$col,.data[[col]],.env$var, and.env$[[var]]work correctly insideacross()(#1520).distinct()after a join no longer creates a subquery (#722).distinct()with computed columns ignores grouping, matching dplyr's behavior (#1081).filter()afterleft_join()orinner_join()no longer creates a subquery (#722).filter()followed by asummarise()is once again inlined correctly (#1707).filter()afterrename()no longer rewrites field names of$and@expressions, so e.g.filter(z == ltr$z)afterrename(z = x)looks upltr$z, notltr$x(#1812).if_else()uses a simpler translation for themissingargument (#1573).join_by(between())correctly handles column renames (#1572).n_distinct()gains anna.rmargument, which warns whenever it's notTRUE(#1579).na_matches = "na"works correctly with inequality and overlap joins, preserving the comparison operator instead of converting to equality (#1505).semi_join()andanti_join()once again work with filtered windowed values (#1534, #1606).slice_*()handles missing values in line with the documentation, i.e. they are always removed (#1599).str_flatten()gains anna.rmargument, which warns whenever it's notTRUE(#1540).str_like()uses case-sensitiveLIKEwhenignore_caseis set toFALSE(@edward-burn, #1488).window_order()works withdplyr::desc()(not justdesc()) (#1486).- Backend-specific improvements:
- MS Access: correctly generates SQL for multiple joins by adding required parentheses (#1576).
- MySQL: gains slightly better translation for
as.integer()andas.integer64()(#1647). - Oracle: temporary tables use private temporary tables (Oracle 18c+) instead of global temporary tables. This ensures data persists correctly and table names are automatically prefixed with
ORA$PTT_(#750). - PostgreSQL: improved translation for
seconds(),minutes(),hours(),days(),weeks(),months(), andyears(). - Postgres, Redshift, Snowflake, and Spark: new translations for
str_ilike()(@edward-burn, #1628). - Redshift:
dbplyr_uncount()works (@owenjonesuob, #1601); corrected error message forquantile()andmedian()inmutate()(@edward-burn, #1571); fixed syntax error indate_build()translation (#1512). - Snowflake: correctly translates
$to:(@jsowder, #1608); fixed translations that were being reported as unknown (@edward-burn, #1570). - SQL Server:
between()usesCASE WHENinstead ofIIF()for compatibility with Azure Synapse (@rehbbea, #1773);if_else()usesCASE WHENinstead ofIIFsoNULLhandling matches R'sNAhandling (#1569);slice_sample()returns different results each run (@thomashulst, #1503);str_like()andstr_ilike()behave consistently (@edward-burn, #1669); on version 17.0 (2025) the stringr regex functionsstr_detect(),str_starts(),str_ends(),str_replace(),str_replace_all(),str_remove(),str_remove_all(),str_extract(), andstr_count()are translated, and fixed-pattern versions ofstr_detect(),str_starts(), andstr_ends()work on all versions (#1671); usesDATEDIFF_BIGinstead ofDATEDIFFsotally()andcount()work regardless of data size (@edward-burn, #1666);filter()correctly casts logical columns toBITwhen the filtered table is the right-hand side of a join (#1839). - Snowflake: correctly translates
$to:(@jsowder, #1608); fixed translations that were being reported as unknown (@edward-burn, #1570);pmin()andpmax()withna.rm = TRUEuseLEAST_IGNORE_NULLS()andGREATEST_IGNORE_NULLS()instead of a bespoke workaround (@mnelsonr, #1850). - SQL Server:
between()usesCASE WHENinstead ofIIF()for compatibility with Azure Synapse (@rehbbea, #1773);if_else()usesCASE WHENinstead ofIIFsoNULLhandling matches R'sNAhandling (#1569);slice_sample()returns different results each run (@thomashulst, #1503);str_like()andstr_ilike()behave consistently (@edward-burn, #1669); on version 17.0 (2025) the stringr regex functionsstr_detect(),str_starts(),str_ends(),str_replace(),str_replace_all(),str_remove(),str_remove_all(),str_extract(), andstr_count()are translated, and fixed-pattern versions ofstr_detect(),str_starts(), andstr_ends()work on all versions (#1671); usesDATEDIFF_BIGinstead ofDATEDIFFsotally()andcount()work regardless of data size (@edward-burn, #1666).
Minor improvements and bug fixes
- CTEs correctly quote table names when the same query is used multiple times (#1559).
- dbplyr uses the base pipe in all examples (#1626).
- The print method no longer mentions the "source", because that is an outdated dplyr concept (#897).
- All set operations (#1585) and
cross_join()(#1792) error if you pass extra arguments (instead of silently ignoring them or giving a confusing error). collapse(),collect(), andcompute()have their own documentation pages (#1637).copy_inline()works with blob columns (#1515).copy_to()works when the source is in the same database as the destination andoverwrite = TRUE(@liudvikasakelis, #1535).db_col_types()gains a SQLite method so thatrows_*()operations can preserve column types when copying data (#1821).expand()errors when column expressions don't reference any columns in the data, instead of generating invalid SQL (#720).fill()errors if you attempt to rename a column, for consistency with dplyr (#1536).if_else()andifelse()give a clear error iftrue/falseoryes/noare missing (#1798).pivot_wider()accepts anonymous functions (e.g.\(x) max(x, na.rm = TRUE)) invalues_fn, not just purrr-style lambdas (#1816).pull()correctly handles aNULLquosure passed toname(#1808).show_query()gains ause_colourargument (#1590).summarise()reports grouping immediately, rather than when the SQL is generated (#1721).
From NEWS.md in the release
Install
Health
- OK13 OK2026-10-17
- WARNING12 OK, 1 WARNING2026-10-01
- OK13 OK2026-08-05
- NOTE12 OK, 1 NOTE2026-08-01
- OK13 OK2026-07-21
Show 9 earlier changesHide 9 earlier changes
- ERROR12 OK, 1 ERROR2026-07-18
- OK13 OK2026-06-27
- ERROR12 OK, 1 ERROR2026-06-24
- OK13 OK2026-06-09
- ERROR12 OK, 1 ERROR2026-06-08
- OK13 OK2026-05-05
- ERROR12 OK, 1 ERROR2026-05-04
- OK12 OK2026-04-25
- ERROR12 OK, 2 ERROR2026-03-10
Documentation
- Help pages
- 93 (26 internal)includes a package overview page
- Examples that run
- 96%66 run in a plain check (6 of them under a condition) · 1 only when donttest examples are enabled (R CMD check --as-cran) · 2 hold no code
- Exported functions with examples
- 69%
- Documented parameters
- 65%
- Return-value docs
- 22%
- Help pages citing references
- 0%
Downloads
Repository
- PRs merged (all time)
- 86%
- Median days to close, 50 most recently updated closed issues
- 37
- Median days to close, 50 most recently updated closed PRs
- 1
Stars over time
Forks over time
Releases over time
Issues over time
PRs over time
20 development-tooling and community-health practices detected across 8 families in the upstream repository
Checks run against github.com/tidyverse/dbplyr on 2026-10-18.
The R CMD check workflow runs on Linux, macOS and Windows, and on R-devel
GitHub Pages site last deployed 2026-06-17 · The repository has a site deploy workflow
pkgdown site last built 2026-06-17
Show all practicesHide 4 practices
This repository shows signs of AI coding tools.
- Claude Codefirst seen 2025-11-28Seen in the repository: .claude, .claude/skillsNamed in .Rbuildignore: .claudeCommits: at least 2 crediting it in the message
- Claude Opus 4.51 commit · Jan 2026
- Claude Opus 4.71 commit · May 2026
Dependencies
Installing dbplyr adds 22 packages (12 with compiled code, 18 MB of source tarballs). Heaviest: stringi 11 MB, vctrs 1.0 MB, dplyr 902 KB.
Show the 48 most downloaded dependentsHide the 48 most downloaded dependents
and 27 more dependents and 77 packages that suggest it on CRAN ↗
Code & Tests
People & History
Pick two releases to compare their code metrics.
- 2.6.0Latest2026-06-17 · current release · diff ↗ ·
removed 11 exports
%>%, db_supports_table_alias_with_as, db_table_temporary, join_query, src_test, supports_window_clause, test_frame, test_load, test_register_con, test_register_src, win_rank_tdataadded 34 exports
.sql, bind_queries, db_table_drop_if_exists, dialect_access, dialect_ansi, dialect_db2, dialect_hana, dialect_hive, dialect_impala, dialect_mariadb, dialect_mssql, dialect_mysql, dialect_odbc, dialect_oracle, dialect_postgres, dialect_redshift, dialect_snowflake, dialect_spark_sql, dialect_sqlite, dialect_teradata, last_sql, local_memdb_frame, memdb, new_sql_dialect, rf_join_query, sql_check_na_rm, sql_dialect, sql_escape_ident, sql_escape_string, sql_glue and 4 more - RR 4.6.0 released · 2026-04-24
- 2.5.22026-02-13 · diff ↗
- 2.5.12025-09-10 · diff ↗
- RR 4.5.0 released · 2025-04-11
- RR 4.4.0 released · 2024-04-24
- 2.5.02024-03-19 · diff ↗ ·
added 6 exports
as_table_path, check_table_path, is_table_path, simulate_mariadb, table_path_components, table_path_name - 2.4.02023-10-26 · diff ↗ ·
removed 3 exports
simulate_vars, simulate_vars_is_typed, supports_star_without_aliasadded 11 exports
db_col_types, db_supports_table_alias_with_as, dbplyr_pivot_wider_spec, lazy_rf_join_query, lazy_union_query, remote_table, simulate_spark_sql, sql_options, sql_query_union, sql_runif, union_query - 2.3.42023-09-27 · diff ↗
- 2.3.32023-07-07 · diff ↗
- RR 4.3.0 released · 2023-04-21
- 2.3.22023-03-21 · diff ↗
- 2.3.12023-02-24 · diff ↗
- 2.3.02023-01-16 · diff ↗ ·
removed 1 export
lazy_join_queryadded 3 exports
lazy_multi_join_query, sql_query_multi_join, win_rank_tdata - 2.2.1
- 2.2.02022-06-05 · diff ↗ ·
removed 4 exports
add_op_single, op_base, op_double, op_singleadded 21 exports
copy_inline, get_returned_rows, has_returned_rows, in_catalog, lazy_base_query, lazy_join_query, lazy_query, lazy_select_query, lazy_semi_join_query, lazy_set_op_query, simulate_vars, simulate_vars_is_typed, sql_indent_subquery, sql_query_append, sql_query_delete, sql_query_insert, sql_query_update_from, sql_query_upsert, sql_random, sql_returning_cols, supports_window_clause
Show 20 earlier eventsHide 20 earlier events
- RR 4.2.0 released · 2022-04-22
- RR 4.1.0 released · 2021-05-18
- 2.1.1
- 2.1.0
- 2.0.02020-11-03 · diff ↗ ·
added 21 exports
db_connection_describe, db_table_temporary, dbplyr_edition, simulate_hana, simulate_redshift, sql_aggregate_n, sql_expr_matches, sql_join_suffix, sql_query_explain, sql_query_fields, sql_query_join, sql_query_rows, sql_query_save, sql_query_select, sql_query_semi_join, sql_query_set_op, sql_query_wrap, sql_table_analyze, sql_table_index, sql_translation, sql_try_cast - 1.4.4
- RR 4.0.0 released · 2020-04-24
- 1.4.3
- 1.4.22019-06-17 · diff ↗
- 1.4.12019-06-06 · diff ↗
- RR 3.6.0 released · 2019-04-26
- 1.4.02019-04-24 · diff ↗ ·
removed 2 exports
simulate_odbc_access, simulate_odbc_postgresqladded 6 exports
escape_ansi, simulate_access, sql_call2, sql_str_sub, sql_substr, tbl_memdb - 1.3.02019-01-09 · diff ↗
- 1.2.22018-07-25 · diff ↗
- RR 3.5.0 released · 2018-04-23
- 1.2.12018-02-19 · diff ↗
- 1.2.02018-01-03 · diff ↗ ·
added 17 exports
remote_con, remote_name, remote_query, remote_query_plan, remote_src, simulate_odbc_access, simulate_teradata, sql_aggregate, sql_aggregate_2, sql_cot, sql_expr, sql_log, sql_paste, sql_paste_infix, src_test, win_aggregate, win_aggregate_2 - 1.1.02017-06-27 · diff ↗ ·
added 7 exports
op_frame, simulate_hive, simulate_odbc_postgresql, simulate_oracle, win_current_frame, window_frame, window_order - 1.0.02017-06-09
- RR 3.4.0 released · 2017-04-21
Package metadata
- First published
- 2017-06-09
- Total releases
- 26 / 9 yrs
- License
- MIT + file LICENSE OSI
- Minimum R
- ≥ 4.1
- Download size
- 598 KB
Cite
Cite this package
Run in R for the authors' preferred citation:
citation("dbplyr")This package has no citation file, so citation() returns this entry built from DESCRIPTION.
Cite the R Observatory
For a number measured here: a download total, a coverage figure, an archival date.
From data release v2026-10-22, which the citation names so these numbers can be found later. More on citing and the projects behind them.