dplyr的安排操作在远程源中似乎不是可交换的,何时才重要?

时间:2019-08-19 05:20:25

标签: sql r dplyr dbplyr

使用cars数据集(具有postgres连接con_psql):

tmp_cars_sdf <-
    copy_to(con_psql, cars, name = "tmp_cars_sdf", overwrite = T)

我们看到以下两个操作序列(仅交换filterarrange的顺序导致了不同的SQL转换:

tmp_cars_sdf %>%
    filter(speed == 4) %>%
    arrange(dist) %>%
    sql_render

# <SQL> SELECT *
#     FROM "tmp_cars_sdf"
# WHERE ("speed" = 4.0)
# ORDER BY "dist"

vs

tmp_cars_sdf %>%
    arrange(dist) %>%
    filter(speed == 4) %>%
    sql_render

# <SQL> SELECT *
#     FROM (SELECT *
#               FROM "tmp_cars_sdf"
#           ORDER BY "dist") "dbplyr_006"
# WHERE ("speed" = 4.0)

我不是SQL方面的专家,但是在收集结果或在其他操作中使用远程表时,似乎只能保证前者的顺序,而不能保证后者的顺序:

Is order in a subquery guaranteed to be preserved? https://dba.stackexchange.com/questions/82930/database-implementations-of-order-by-in-a-subquery

我该怎么办?

编辑:

进行了一些进一步的研究后,我不确定从数据分析的角度来看这是否重要(即像对待ram中的数据帧一样对待远程表)。

tmp_cars_sdf %>%
    arrange(dist) %>%
    group_by(speed) %>%
    filter(dist > 10) %>%
    mutate(lag_dist = lag(dist)) %>%
    sql_render

# <SQL> SELECT "speed", "dist", LAG("dist", 1, NULL) OVER 
# (PARTITION BY "speed" ORDER BY "dist") AS "lag_dist"
# FROM (SELECT *
#           FROM "tmp_cars_sdf"
#       ORDER BY "dist") "dbplyr_014"
# WHERE ("dist" > 10.0)

虽然看起来arrange()在子查询中似乎已翻译成ORDER BY,但事实证明,这并不重要,至少对于自排序以来基于该顺序计算新变量而言信息不会被“遗忘”。

1 个答案:

答案 0 :(得分:1)

您是正确的,订购仅保留在第一个示例中,而不保留在第二个示例中。实际上,您的第二个示例可能会导致某些版本的SQL中的错误,这些版本不接受子查询中的<textarea style="height:150px;width:200px"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu tortor vitae neque iaculis finibus viverra nec metus. Proin rhoncus justo ipsum, at consequat leo posuere id. Duis tincidunt consectetur efficitur. Curabitur semper rhoncus semper. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu tortor vitae neque iaculis finibus viverra nec metus. Proin rhoncus justo ipsum, at consequat leo posuere id. Duis tincidunt consectetur efficitur. Curabitur semper rhoncus semper. </textarea>子句。

使用ORDER BY时,远程表实质上由构造表的当前状态的SQL查询定义。 dbplyr到SQL的转换一次只能一次执行一个命令,一次是使用现有查询并对其进行扩充以反映下一个转换。这通常会导致以前的查询成为新查询的子查询。

通常,仅当结果返回到R(例如,由dbplyr)时,查询才会评估。可以使用一些技巧来强制和保存中间评估,但是我找不到能保证排序的任何

鉴于上述情况,我的建议是:

  • 由于数据库通常不关心顺序,因此只能使用ranging命令来准备输出以供人类查看。
  • 当顺序对于创建新变量很重要时,请在函数内使用collect子句,而不要使用order by。例如:
    • 使用arrange
    • 代替my_data %>% mutate(new = lag(old, order_by = "date"))

您可能还会发现this对行号/排名很有帮助。