将外键上的 SQL 连接转换为 R data.table 语法

Posted

技术标签:

【中文标题】将外键上的 SQL 连接转换为 R data.table 语法【英文标题】:Translating SQL joins on foreign keys to R data.table syntax 【发布时间】:2012-04-12 11:19:11 【问题描述】:

data.table 包提供了许多与 SQL 相同的表处理方法。如果一个表有一个键,则该键由一个或多个列组成。但是一个表不能有多个键,因为它不能同时以两种不同的方式排序。

在此示例中,XY 是具有单个键列“id”的 data.tables; Y 也有一个非键列“x_id”。

   X <- data.table(id = 1:5, a=4:8,key="id")
   Y <- data.table(id = c(1,1, 3,5,7), x_id=c(1,4:1), key="id")

以下语法将在其键上连接表:

  X[Y]

如何将以下 SQL 语法转换为 data.table 代码?

  select * from X join Y on X.id = Y.x_id; 

我得到的最接近的是:

Y[X,list(id, x_id),by = x_id,nomatch=0]

但是,这与 SQL 语句执行的内连接不同。


这是一个更清晰的示例,其中外键是 y_id,我们希望连接查找 Y2 的值,其中 X2$y_id = Y2$id

    X2 <- data.table(id = 1:5, y_id = c(1,1,2,2,2), key="id")
    Y2 <- data.table(id = 1:5, b = letters[1:5], key="id")

我要制作表格:

   id  y_id  b
    1     1 "a"
    2     1 "a"
    3     2 "b"
    4     2 "b"
    5     2 "b"

类似于以下 kludge 所做的事情:

> merge(data.frame(X2), data.frame(Y2), by.x = "y_id", by.y = "id")
  y_id id b
1    1  1 a
2    1  2 a
3    2  3 b
4    2  4 b
5    2  5 b

但是,当我这样做时:

    X2[Y2, 1:2,by = y_id]

我没有得到想要的结果:

    y_id V1
[1,]    1  1
[2,]    1  2
[3,]    2  1
[4,]    2  2

【问题讨论】:

您可以临时更改X2键并将其设置为"y_id";然后执行普通连接Y2[X2](或X2[Y2],取决于方向)然后恢复X2的前一个键。 @digEmAll 这很有用,我认为这就是 by 参数的作用......但这可以应用于目标(左)表具有的多个(>2)表连接>1 个外键? 我同意@digEmAll:setkey(X2, y_id) 后跟X2[Y2, nomatch=0] 是您的示例所需要的全部内容。这也应该与几个键一起使用。但是,我对 SQL 中的外键语法并不是很熟悉,所以如果您正在为更多键而苦苦挣扎,您可以扩展您的示例吗? "以下语法将在其键上连接表:X[Y] -- 我认为等效的 SQL 语法是:SELECT * FROM A NATURAL JOIN B; 我编辑了问题的顶部以清除术语。希望没事。会回答... 【参考方案1】:

好问题。请注意?data.table 中的以下内容(不可否认):

idata.table 时,x 必须有一个密钥。 i 使用键连接到 x 并返回 x 中匹配的行。在i 中的每一列与x 的键中的每一列之间执行等值连接。匹配是在 O(log n) 时间内编译的 C 中的二进制搜索。如果i 的列数少于x 的键,那么x 的许多行可能与i 的每一行匹配。如果i 的列多于x 的键,则i 未参与连接的列将包含在结果中。 如果i 也有一个键,则i 的键列用于匹配x 的键列,并执行两个表的二进制合并。

所以,这里的关键是 i 不必键入。只有x 必须键入。

X2 <- data.table(id = 11:15, y_id = c(14,14,11,12,12), key="id")
     id y_id
[1,] 11   14
[2,] 12   14
[3,] 13   11
[4,] 14   12
[5,] 15   12
Y2 <- data.table(id = 11:15, b = letters[1:5], key="id")
     id b
[1,] 11 a
[2,] 12 b
[3,] 13 c
[4,] 14 d
[5,] 15 e
Y2[J(X2$y_id)]  # binary search for each item of (unsorted and unkeyed) i
     id b
[1,] 14 d
[2,] 14 d
[3,] 11 a
[4,] 12 b
[5,] 12 b

或者,

Y2[SJ(X2$y_id)]  # binary merge of keyed i, see ?SJ
     id b
[1,] 11 a
[2,] 12 b
[3,] 12 b
[4,] 14 d
[5,] 14 d

identical(Y2[J(X2$y_id)], Y2[X2$y_id])
[1] FALSE

【讨论】:

谢谢。但是identical(Y2[J(X2$y_id)], Y2[X2$y_id]) == TRUE,有区别吗? @David 已更改示例数据以使其更清晰。前面的示例数据的键值与行号相同,即1:5

以上是关于将外键上的 SQL 连接转换为 R data.table 语法的主要内容,如果未能解决你的问题,请参考以下文章

实体 Remove() 将外键属性设置为 null

SQL将外键添加到现有列

sql SQL将外键添加到现有表

使用 annotate 或 extra 将外键字段添加到查询集? (相当于 SQL“AS”?)

外键上的教义模式更新失败

外键 VS 主键上的聚集索引