Skip to content

Commit 3316463

Browse files
javierluraschihadley
authored andcommitted
Add support for CROSS JOIN through full_join (#24)
CROSS JOIN will be generated whenever by = character() Fixes tidyverse/dplyr#2924
1 parent d485326 commit 3316463

File tree

4 files changed

+37
-12
lines changed

4 files changed

+37
-12
lines changed

NEWS.md

+3
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@
7474

7575
## New features
7676

77+
* `full_join()` over non-overlapping columns `by = character()` translated to
78+
`CROSS JOIN` (#2924).
79+
7780
* `case_when()` now translates to SQL "CASE WHEN" (#2894)
7881

7982
* `x %in% c(1)` now generates the same SQL as `x %in% 1` (#2898).

R/sql-generic.R

+20-11
Original file line numberDiff line numberDiff line change
@@ -51,27 +51,19 @@ sql_join.DBIConnection <- function(con, x, y, vars, type = "inner", by = NULL, .
5151
inner = sql("INNER JOIN"),
5252
right = sql("RIGHT JOIN"),
5353
full = sql("FULL JOIN"),
54+
cross = sql("CROSS JOIN"),
5455
stop("Unknown join type:", type, call. = FALSE)
5556
)
5657

5758
select <- sql_join_vars(con, vars)
58-
59-
on <- sql_vector(
60-
paste0(
61-
sql_table_prefix(con, by$x, "TBL_LEFT"),
62-
" = ",
63-
sql_table_prefix(con, by$y, "TBL_RIGHT")
64-
),
65-
collapse = " AND ",
66-
parens = TRUE
67-
)
59+
on <- sql_join_tbls(con, by)
6860

6961
# Wrap with SELECT since callers assume a valid query is returned
7062
build_sql(
7163
"SELECT ", select, "\n",
7264
" FROM ", x, "\n",
7365
" ", JOIN, " ", y, "\n",
74-
" ON ", on, "\n",
66+
if (!is.null(on)) build_sql(" ON ", on, "\n") else NULL,
7567
con = con
7668
)
7769
}
@@ -108,6 +100,23 @@ sql_join_var <- function(con, alias, x, y) {
108100
}
109101
}
110102

103+
sql_join_tbls <- function(con, by) {
104+
on <- NULL
105+
if (length(by$x) + length(by$y) > 0) {
106+
on <- sql_vector(
107+
paste0(
108+
sql_table_prefix(con, by$x, "TBL_LEFT"),
109+
" = ",
110+
sql_table_prefix(con, by$y, "TBL_RIGHT")
111+
),
112+
collapse = " AND ",
113+
parens = TRUE
114+
)
115+
}
116+
117+
on
118+
}
119+
111120
sql_coalesce <- function(...) {
112121
vars <- sql_vector(list(...), parens = FALSE, collapse = ", ")
113122
build_sql("coalesce(", vars, ")")

R/tbl-lazy.R

+9-1
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,16 @@ distinct_.tbl_lazy <- function(.data, ..., .dots = list(), .keep_all = FALSE) {
211211
add_op_join <- function(x, y, type, by = NULL, copy = FALSE,
212212
suffix = c(".x", ".y"),
213213
auto_index = FALSE, ...) {
214+
by_intersect <- intersect(tbl_vars(x), tbl_vars(y))
215+
216+
if (length(by_intersect) == 0 && length(by) == 0 &&
217+
identical(type, "full") && is.character(by)) {
218+
type <- "cross"
219+
by <- list(x = character(0), y = character(0))
220+
} else {
221+
by <- common_by(by, x, y)
222+
}
214223

215-
by <- common_by(by, x, y)
216224
y <- auto_copy(
217225
x, y,
218226
copy = copy,

tests/testthat/test-joins.R

+5
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,8 @@ test_that("sql generated correctly for all sources", {
9292

9393
expect_equal_tbls(xy)
9494
})
95+
96+
test_that("full join is promoted to cross join for no overlapping variables", {
97+
result <- df1 %>% full_join(df2, by = character()) %>% collect()
98+
expect_equal(nrow(result), 25)
99+
})

0 commit comments

Comments
 (0)