在 WRDS MSRB 数据集上使用 SQL 查询从许多 CUSIP 检索数据
Retrieving data from many CUSIPs using a SQL query on the WRDS MSRB dataset
我是 SQL 的新手,所以很抱歉,如果这是一个简单的问题,我在搜索时没有找到任何东西,但我可能错过了明显的搜索词。
我正在尝试下载一组市政债券的所有交易数据,我有一个 CUSIP 列表,目前存储为一个 .txt 文件,每行一个 CUSIP。 WRDS 的在线版本允许用户上传这样一个 .txt 文件来检索他们的数据。
我想在 R 中自动执行此过程,并按照 WRDS 指南在 R 中设置 SQL 查询。最终我将使用类似
的内容
res <- dbSendQuery(wrds, "select *
from msrb.msrb
where cusip IN ???")
data <- dbFetch(res, n=-1)
dbClearResult(res)
data
如何将我的 CUSIP 列表实际放入查询中?直接列出每个 CUSIP 太长了,不可行。我能否以某种方式引用 .txt 文件,或者至少引用 R 中的字符向量或其他内容?有没有更好的方法?
我认为有两种有效的方法可以在 SQL 中以编程方式执行 IN (...)
,一种方法很流行但有风险(我通常不鼓励这样做)。
使用参数绑定。这在某些主观限制下是实用的;可能有一个 real 限制参数 DBI
允许绑定的数量,但我不知道;我不知道 SQL 实现是否经常限制您可以在文字 IN (...)
语句中放入的值的数量(我刚刚用 5000 测试了 PG11,没问题)。在某些时候,使用下面的选项 2 可能更有效或更可取。但是,如果我们谈论的是几十个,那么试试这个。
cusips <- c(...) # vector of CUSIPs
params <- paste(paste0("$", seq_along(cusips)), collapse = ",")
ret <- DBI::dbGetQuery(con,
paste("select * from msrb.msrb where cusip in (", params, ")"),
params = as.list(cusips))
(, , )
的使用是postgres特有的;其他 DBMS 可能使用不同的命名法,包括 (?,?,?)
(sql 服务器和其他)。
将 ID 上传到临时 table 并对其进行查询。 (如果您从另一个查询获取要使用的 ID,也可以部分使用它,只需更新内部 SQL 以反映您的其他查询。)
cusips <- c(...) # vector of CUSIPs
tmptbl <- paste0("tmptable_", paste(sample(9), collapse = ""))
DBI::dbWriteTable(con, tmptbl, data.frame(cusip = cusips))
DBI::dbGetQuery(con,
paste("select * from msrb.msrb where cusip in",
"(select cusip from", tmptbl, ")"))
或加入临时 table,与
DBI::dbGetQuery(con,
paste("select msrb.* from ", tmptbl, "t",
"left join msrb on t.cusip = msrb.cusip"))
总的来说,我是使用参数绑定的坚定拥护者,因为它会 side-step 任何形式的 SQL 注入,无论是恶意的还是意外的。但是,如果您赶时间,可以自己组成 IN (...)
。您可以使用 glue::glue_sql
来确保始终使用正确的引号(针对您的特定 DBMS);如果不是,使用单引号通常是安全的。
cusips <- c(...) # vector of CUSIPs
params <- paste("(", paste(sQuote(cusips), collapse = ","), ")")
# or
params <- glue::glue_sql("({cusips*})", .con = con)
DBI::dbGetQuery(con, paste("select * from msrb.msrb where cusip in", params))
请注意,glue::glue_sql
提供了 *
表示法。来自 ?glue::glue_sql
:
If you place a '*' at the end of a glue expression the values will be collapsed with commas. This is useful for the SQL IN Operator for instance.
对于所有三种方法,我都使用了 more-direct DBI::dbGetQuery
,但如果您愿意,您仍然可以使用 DBI::dbSendQuery
/DBI::dbFetch
two-step。
根据您的 msrb
table 及其索引的大小,这些查询可能不会达到所有优化。如果是这种情况,请考虑根据 DBA 的建议添加到查询中。
我是 SQL 的新手,所以很抱歉,如果这是一个简单的问题,我在搜索时没有找到任何东西,但我可能错过了明显的搜索词。
我正在尝试下载一组市政债券的所有交易数据,我有一个 CUSIP 列表,目前存储为一个 .txt 文件,每行一个 CUSIP。 WRDS 的在线版本允许用户上传这样一个 .txt 文件来检索他们的数据。
我想在 R 中自动执行此过程,并按照 WRDS 指南在 R 中设置 SQL 查询。最终我将使用类似
的内容res <- dbSendQuery(wrds, "select *
from msrb.msrb
where cusip IN ???")
data <- dbFetch(res, n=-1)
dbClearResult(res)
data
如何将我的 CUSIP 列表实际放入查询中?直接列出每个 CUSIP 太长了,不可行。我能否以某种方式引用 .txt 文件,或者至少引用 R 中的字符向量或其他内容?有没有更好的方法?
我认为有两种有效的方法可以在 SQL 中以编程方式执行 IN (...)
,一种方法很流行但有风险(我通常不鼓励这样做)。
使用参数绑定。这在某些主观限制下是实用的;可能有一个 real 限制参数
DBI
允许绑定的数量,但我不知道;我不知道 SQL 实现是否经常限制您可以在文字IN (...)
语句中放入的值的数量(我刚刚用 5000 测试了 PG11,没问题)。在某些时候,使用下面的选项 2 可能更有效或更可取。但是,如果我们谈论的是几十个,那么试试这个。cusips <- c(...) # vector of CUSIPs params <- paste(paste0("$", seq_along(cusips)), collapse = ",") ret <- DBI::dbGetQuery(con, paste("select * from msrb.msrb where cusip in (", params, ")"), params = as.list(cusips))
(, , )
的使用是postgres特有的;其他 DBMS 可能使用不同的命名法,包括(?,?,?)
(sql 服务器和其他)。将 ID 上传到临时 table 并对其进行查询。 (如果您从另一个查询获取要使用的 ID,也可以部分使用它,只需更新内部 SQL 以反映您的其他查询。)
cusips <- c(...) # vector of CUSIPs tmptbl <- paste0("tmptable_", paste(sample(9), collapse = "")) DBI::dbWriteTable(con, tmptbl, data.frame(cusip = cusips)) DBI::dbGetQuery(con, paste("select * from msrb.msrb where cusip in", "(select cusip from", tmptbl, ")"))
或加入临时 table,与
DBI::dbGetQuery(con, paste("select msrb.* from ", tmptbl, "t", "left join msrb on t.cusip = msrb.cusip"))
总的来说,我是使用参数绑定的坚定拥护者,因为它会 side-step 任何形式的 SQL 注入,无论是恶意的还是意外的。但是,如果您赶时间,可以自己组成
IN (...)
。您可以使用glue::glue_sql
来确保始终使用正确的引号(针对您的特定 DBMS);如果不是,使用单引号通常是安全的。cusips <- c(...) # vector of CUSIPs params <- paste("(", paste(sQuote(cusips), collapse = ","), ")") # or params <- glue::glue_sql("({cusips*})", .con = con) DBI::dbGetQuery(con, paste("select * from msrb.msrb where cusip in", params))
请注意,
glue::glue_sql
提供了*
表示法。来自?glue::glue_sql
:If you place a '*' at the end of a glue expression the values will be collapsed with commas. This is useful for the SQL IN Operator for instance.
对于所有三种方法,我都使用了 more-direct DBI::dbGetQuery
,但如果您愿意,您仍然可以使用 DBI::dbSendQuery
/DBI::dbFetch
two-step。
根据您的 msrb
table 及其索引的大小,这些查询可能不会达到所有优化。如果是这种情况,请考虑根据 DBA 的建议添加到查询中。