使用glue_sql() 并避免粘贴在动态SELECT 语句中的方法?
Posted
技术标签:
【中文标题】使用glue_sql() 并避免粘贴在动态SELECT 语句中的方法?【英文标题】:Way to use glue_sql() and avoid paste in dynamic SELECT statement?使用glue_sql() 并避免粘贴在动态SELECT 语句中的方法?
【发布时间】:2021-10-17 02:05:08
【相关技术】:@tags@
【问题描述】:
我正在学习如何从 R 中查询 SQLite dbs,并使用 glue_sql()
构建这些查询。下面是我的工作流程中子查询的简化示例。有没有一种方法可以在不使用paste0()
的情况下创建s10_wtX
和s20_wtX
,如下面的代码所示?
library(DBI)
library(dplyr)
library(glue)
# example database
set.seed(1)
ps <- data.frame(plot = rep(1:3, each = 4),
spp = rep(1:3*10, 2),
wtX = rnorm(12, 10, 2) %>% round(1))
con <- dbConnect(RSQLite::SQLite(), "")
dbWriteTable(con, "ps", ps)
# species of interest
our_spp <- c(10, 20)
# for the spp of interest, sum wtX on each plot
sq <- glue_sql(paste0(
'SELECT ps.plot,\n',
paste0('SUM(CASE WHEN ps.spp = ', our_spp,
' THEN (ps.wtX) END) AS s', our_spp,
'_wtX',
collapse = ',\n'), '\n',
' FROM ps
WHERE ps.spp IN (our_spp*) -- spp in our sample
GROUP BY ps.plot'),
.con = con)
# the result of the query should look like:
dbGetQuery(con, sq)
plot s10_wtX s20_wtX
1 1 21.9 10.4
2 2 11.0 22.2
3 3 9.4 13.0
在我的实际工作流程中,我有两种以上的兴趣,所以我宁愿不完整地写出每一行(例如,SUM(CASE WHEN ps.spp = 10 THEN (ps.wtX) END) AS s10_wtX
)。
【问题讨论】:
您可以更轻松地在 SQL 中进行简单的聚合并在 R 中进行透视,您是否试图避免这种情况? 使用glue
,您可以使用our_spp
并避免使用paste
(来自我之前的评论)例如,您可以使用dbGetQuery(con, "select ps.plot, ps.spp, sum(ps.wtX) as wtX from ps where ps.spp in (10,20) group by ps.plot, ps.spp") %>% tidyr::pivot_wider(plot, names_from="spp", values_from="wtX")
(如果您可以使用dplyr+tidyr
,与reshape2
或data.table
的结果类似)来获得所需的输出。
我不确定您是否只有sqlite,但其他DBMS 有PIVOT
运算符。例如,在 Oracle 中它将是 SELECT * FROM (SELECT ps.plot, ps.spp, ps.wtX FROM ps WHERE ps IN (10, 20)) PIVOT (SUM(wtX) FOR spp IN (10 as s10_wtx, 20 as s20_wtx)
。但是...在 R 中进行处理可能更有意义。
标记了@akrun 的答案,因为它显示了glue_collapse()
,并且很容易融入我的工作流程;但将重新审视@r2evans 的想法,尽可能避免glue_sql()
++
【参考方案1】:
OP的原始问题是
有没有一种方法可以在不使用 paste0() 的情况下创建 s10_wtX 和 s20_wtX,如下面的代码所示?
如果我们只想用glue
构造,也可以使用glue_collapse
library(glue)
sq1 <- glue_sql('SELECT ps.plot,', glue_collapse(glue('SUM(CASE WHEN ps.spp = our_spp THEN (ps.wtX) END) AS sour_spp_wtX'), sep = ",\n"), '\nFROM ps\n WHERE ps.spp IN (our_spp*) -- spp in our sample\n GROUP BY ps.plot', .con = con)
dbGetQuery(con, sq1)
plot s10_wtX s20_wtX
1 1 21.9 10.4
2 2 11.0 22.2
3 3 9.4 13.0
【讨论】:
很好奇(因为我不经常使用glue
),是glue_collapse
实际上只是paste
-ing 它与collapse=""
?
它在内部使用paste
和collapse
,并在调用as_glue
时返回胶水格式【参考方案2】:
为了正式一点(即使它不是你最终使用的),这里是我的 cmets,详细:
out <- DBI::dbGetQuery(con, "
select ps.plot, ps.spp, sum(ps.wtX) as wtX
from ps
where ps.spp in (10,20)
group by ps.plot, ps.spp")
out
# plot spp wtX
# 1 1 10 21.9
# 2 1 20 10.4
# 3 2 10 11.0
# 4 2 20 22.2
# 5 3 10 9.4
# 6 3 20 13.0
这可以很容易地根据您的需要进行调整。例如,使用tidyr::pivot_wider
,
tidyr::pivot_wider(out, plot, names_from="spp", values_from="wtX")
# # A tibble: 3 x 3
# plot `10` `20`
# <int> <dbl> <dbl>
# 1 1 21.9 10.4
# 2 2 11 22.2
# 3 3 9.4 13
(名称需要清理。)
【讨论】:
以上是关于使用glue_sql() 并避免粘贴在动态SELECT 语句中的方法?的主要内容,如果未能解决你的问题,请参考以下文章
如何避免在旋转端口登陆Android4.X后在智能手机中剪切/复制/粘贴?
vbscript 在Excel VBA中复制和粘贴的三种方法。请注意,`Range.Copy`和`Range.PasteSpecial`使用剪贴板,因此请避免复制任何内容