R 迭代查询数据库表而不使用 lambda 循环或 Shiny 应用程序的矢量化函数
R query database tables iteratively without for loop with lambda or vectorized function for Shiny app
我正在通过 R 中的 ODBC 连接连接到 SQL 服务器数据库。我有两种可能的方法来获取数据,并且正在尝试确定哪种方法更有效。 Shiny 仪表板需要数据,因此需要在加载应用程序时提取数据,而不是在用户使用应用程序时即时查询。
方法一是使用20多个存储过程,将需要的数据全部查询出来,存储起来使用。方法 2 是单独查询所有 table。
下面是我用来查询其中一个存储过程的方法:
get_proc_data <- function(proc_name, url, start_date, end_date){
dbGetQuery(con, paste0(
"EXEC dbo.", proc_name, " ",
"@URL = N'", url, "', ",
"@Startdate = '", start_date, "', ",
"@enddate = '", end_date, "' "
))
}
data <- get_proc_data(proc_name, url, today(), today() %m-% years(5))
但是,每个存储过程的参数设置略有不同,因此我必须分别定义它们。
我已经开始实施方法 2,但是 运行 遇到了迭代查询每个 table 的问题。
# use dplyr create list of table names
db_tables <- dbGetQuery(con, "SELECT * FROM [database_name].INFORMATION_SCHEMA.TABLES;") %>% select(TABLE_NAME)
# use dplyr pull to create list
table_list <- pull(db_tables , TABLE_NAME)
# get a quick look at the first few rows
tbl(con, "[TableName]") %>% head() %>% glimpse()
# iterate through all table names, get the first five rows, and export to .csv
for (table in table_list){
write.csv(
tbl(con, table) %>% head(), str_glue("{getwd()}/00_exports/tables/{table}.csv")
)
}
selected_tables <- db_tables %>% filter(TABLE_NAME == c("TableName1","TableName2"))
最终这个方法只是为了测试迭代 ~60 tables 并执行所需功能需要多长时间。我曾尝试将它放入一个函数中,但无法让它迭代,同时还提取了 table.
的名称
Pro/Con 对于方法 1:存储过程当前正在为用 C++ 编写的指标插件提供支持,并在网页上显示指标。这是供内部使用以监控网站性能。但是,存储过程对我来说并不都是可见的,客户需要我扩展他们当前的指标。我也没有可支配的 DBA 来帮助 SQL 服务器端,而且编写过程的人也不在。 procs 也使用彼此不同的逻辑,因此连接两个不同 procs 的结果会给出截然不同的值。例如,根据过程,每个日期将列出每天的总页面浏览量,或者已经按周或月度聚合,然后重复列出。所以加入和分组会导致实际页面浏览量出现严重错误。
Pro/Con 用于方法 2:我熟悉 dplyr 并且能够将 table 连接在一起以提取我需要的数据。但是,我对 SQL 并不熟悉,也没有任何类型的实体关系图 (ERD) 可供参考。否则,我会单独构建每个查询。
无论哪种方式,我都在尝试想出一种方法来处理命名函数、lambda 函数或用于迭代的向量化方法。最好为每个变量命名并适当地分配它们,以便我可以使用 dplyr 执行数据整理。
任何帮助将不胜感激,我不知所措。我在 R 中研究了等同于 Python 列表理解的方法,但未能使 R 中的函数执行类似的操作。
> db_table_head_to_csv <- function(table) {
+ write.csv(
+ tbl(con, table) %>% head(), str_glue("{getwd()}/00_exports/bibliometrics_tables/{table}.csv")
+ )
+ }
>
> bibliometrics_tables %>% db_table_head_to_csv()
Error in UseMethod("as.sql") :
no applicable method for 'as.sql' applied to an object of class "data.frame"
考虑使用 lapply
(与 Python 的 list/dict 理解对应)将所有 table 数据存储在命名列表中(与 Python 字典对应) ).如果你使用它的兄弟,sapply
,传入的字符向量将 return 作为元素的名称:
# RETURN VECTOR OF TABLE NAMES
db_tables <- dbGetQuery(
con, "SELECT [TABLE_NAME] FROM [database_name].INFORMATION_SCHEMA.TABLES"
)$TABLE_NAME
# RETURN NAMED LIST OF DATA FRAMES FOR EACH DB TABLE
df_list <- sapply(db_tables, function(t) dbReadTable(conn, t), simplify = FALSE)
您可以像 write.csv
一样为多个步骤扩展 lambda
函数或使用定义的方法。请务必将 return
数据框作为最后一行。下面使用新管道,|>
in base R 4.1.0+:
db_table_head_to_csv <- function(table) {
head_df <- dbReadTable(con, table) |> head()
write.csv(
head_df,
file.path(
"00_exports", "bibliometrics_tables", paste0(table, ".csv")
)
)
return(head_df)
}
df_list <- sapply(db_tables, db_table_head_to_csv, simplify = FALSE)
如果存储在列表中,您不会失去数据框对象的功能,并且可以按名称使用 $
或 [[
提取:
# EXTRACT SPECIFIC ELEMENT
head(df_list$table_1)
tail(df_list[["table_2"]])
summary(df_list$`table_3`)
我正在通过 R 中的 ODBC 连接连接到 SQL 服务器数据库。我有两种可能的方法来获取数据,并且正在尝试确定哪种方法更有效。 Shiny 仪表板需要数据,因此需要在加载应用程序时提取数据,而不是在用户使用应用程序时即时查询。
方法一是使用20多个存储过程,将需要的数据全部查询出来,存储起来使用。方法 2 是单独查询所有 table。
下面是我用来查询其中一个存储过程的方法:
get_proc_data <- function(proc_name, url, start_date, end_date){
dbGetQuery(con, paste0(
"EXEC dbo.", proc_name, " ",
"@URL = N'", url, "', ",
"@Startdate = '", start_date, "', ",
"@enddate = '", end_date, "' "
))
}
data <- get_proc_data(proc_name, url, today(), today() %m-% years(5))
但是,每个存储过程的参数设置略有不同,因此我必须分别定义它们。
我已经开始实施方法 2,但是 运行 遇到了迭代查询每个 table 的问题。
# use dplyr create list of table names
db_tables <- dbGetQuery(con, "SELECT * FROM [database_name].INFORMATION_SCHEMA.TABLES;") %>% select(TABLE_NAME)
# use dplyr pull to create list
table_list <- pull(db_tables , TABLE_NAME)
# get a quick look at the first few rows
tbl(con, "[TableName]") %>% head() %>% glimpse()
# iterate through all table names, get the first five rows, and export to .csv
for (table in table_list){
write.csv(
tbl(con, table) %>% head(), str_glue("{getwd()}/00_exports/tables/{table}.csv")
)
}
selected_tables <- db_tables %>% filter(TABLE_NAME == c("TableName1","TableName2"))
最终这个方法只是为了测试迭代 ~60 tables 并执行所需功能需要多长时间。我曾尝试将它放入一个函数中,但无法让它迭代,同时还提取了 table.
的名称Pro/Con 对于方法 1:存储过程当前正在为用 C++ 编写的指标插件提供支持,并在网页上显示指标。这是供内部使用以监控网站性能。但是,存储过程对我来说并不都是可见的,客户需要我扩展他们当前的指标。我也没有可支配的 DBA 来帮助 SQL 服务器端,而且编写过程的人也不在。 procs 也使用彼此不同的逻辑,因此连接两个不同 procs 的结果会给出截然不同的值。例如,根据过程,每个日期将列出每天的总页面浏览量,或者已经按周或月度聚合,然后重复列出。所以加入和分组会导致实际页面浏览量出现严重错误。
Pro/Con 用于方法 2:我熟悉 dplyr 并且能够将 table 连接在一起以提取我需要的数据。但是,我对 SQL 并不熟悉,也没有任何类型的实体关系图 (ERD) 可供参考。否则,我会单独构建每个查询。
无论哪种方式,我都在尝试想出一种方法来处理命名函数、lambda 函数或用于迭代的向量化方法。最好为每个变量命名并适当地分配它们,以便我可以使用 dplyr 执行数据整理。
任何帮助将不胜感激,我不知所措。我在 R 中研究了等同于 Python 列表理解的方法,但未能使 R 中的函数执行类似的操作。
> db_table_head_to_csv <- function(table) {
+ write.csv(
+ tbl(con, table) %>% head(), str_glue("{getwd()}/00_exports/bibliometrics_tables/{table}.csv")
+ )
+ }
>
> bibliometrics_tables %>% db_table_head_to_csv()
Error in UseMethod("as.sql") :
no applicable method for 'as.sql' applied to an object of class "data.frame"
考虑使用 lapply
(与 Python 的 list/dict 理解对应)将所有 table 数据存储在命名列表中(与 Python 字典对应) ).如果你使用它的兄弟,sapply
,传入的字符向量将 return 作为元素的名称:
# RETURN VECTOR OF TABLE NAMES
db_tables <- dbGetQuery(
con, "SELECT [TABLE_NAME] FROM [database_name].INFORMATION_SCHEMA.TABLES"
)$TABLE_NAME
# RETURN NAMED LIST OF DATA FRAMES FOR EACH DB TABLE
df_list <- sapply(db_tables, function(t) dbReadTable(conn, t), simplify = FALSE)
您可以像 write.csv
一样为多个步骤扩展 lambda
函数或使用定义的方法。请务必将 return
数据框作为最后一行。下面使用新管道,|>
in base R 4.1.0+:
db_table_head_to_csv <- function(table) {
head_df <- dbReadTable(con, table) |> head()
write.csv(
head_df,
file.path(
"00_exports", "bibliometrics_tables", paste0(table, ".csv")
)
)
return(head_df)
}
df_list <- sapply(db_tables, db_table_head_to_csv, simplify = FALSE)
如果存储在列表中,您不会失去数据框对象的功能,并且可以按名称使用 $
或 [[
提取:
# EXTRACT SPECIFIC ELEMENT
head(df_list$table_1)
tail(df_list[["table_2"]])
summary(df_list$`table_3`)