0

我对 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 中的字符向量或其他东西吗?有更好的方法吗?

4

1 回答 1

1

我认为在 SQL 中以编程方式执行有两种有效的方法IN (...),一种是流行但有风险的方法(我通常不鼓励它)。

  1. 使用参数绑定。这在某些主观限制下是实用的;允许绑定多少个参数可能有一个真正的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))
    

    的使用($1, $2, $3)是特定于 postgres 的;其他 DBMS 可能使用不同的命名法,包括(?,?,?)(sql server 和其他)。

  2. 将 id 上传到临时表中并对其进行查询。(如果您从另一个查询中获取要使用的 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, ")"))
    

    或加入临时表,与

    DBI::dbGetQuery(con,
      paste("select msrb.* from ", tmptbl, "t",
            "left join msrb on t.cusip = msrb.cusip"))
    
  3. 总的来说,我是使用参数绑定的坚定拥护者,因为它会回避任何形式的 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

    如果您在胶合表达式的末尾放置一个“*”,则值将用逗号折叠。例如,这对于 SQL IN 运算符很有用。

对于所有三种方法,我都使用了 more-direct DBI::dbGetQuery,但如果您愿意,仍然可以使用DBI::dbSendQuery/DBI::dbFetch两步。

根据msrb表的大小及其索引,这些查询可能不会达到所有优化。如果是这种情况,请考虑根据 DBA 的建议添加到查询中。

于 2020-10-05T14:50:22.217 回答