R, dbGetQuery() will not select records for all values passed in params

南楼画角 提交于 2021-02-11 17:17:14

问题


I am trying to get dbGetQuery to retrieve all rows referenced in a char list (test_ID2) from a SybaseIQ table (test_in). The result is that only the first entry in test_ID2 is retrieved.

the dbGetQuery() looks like this:

test_con <- DBI::dbConnect(odbc::odbc(),
                           driver = 'SybaseIQ',
                           host = 'xxx.xx.xxx',
                           port = 'xxxx',
                           uid = 'xxxx',
                           pwd = 'xxxx')

test_out <- dbGetQuery(test_con,"SELECT * FROM test_in WHERE ID2 = ?", 
                           params = list(test_ID2))

test_in looks like this:

> test_in
          ID1       DATE       ID2  QTY
115 18383M472 2017-02-01 93964W108  594
116 18383M472 2017-02-01 939653101  254
117 18383M472 2017-02-01 948741103  437
118 18383M472 2017-02-01 95040Q104 1236
119 25459W458 2017-02-01 G5876H105 4542
120 25459W458 2017-02-01 N07059210  557
121 25459W458 2017-02-01 N6596X109 1205
122 25459W458 2017-02-01 Y09827109 1401
123 25459W458 2017-02-01 007903107 8223
124 25459W458 2017-02-01 032654105 1609
125 25459W458 2017-02-01 038222105 3709

test_ID2 looks like this:

> test_ID2
[1] "939653101" "N6596X109" "N99999999"

the result from the above dbGetQuery() contains only one entry

> test_out
          ID1       DATE       ID2 QTY
116 18383M472 2017-02-01 939653101 254

and it misses the entry with ID2 = "N6596X109".

What am I doint wrong?

Thanks for your thoughts!


UPDATE

what seems to work is using glue_sql() along with dbSendQuery() and dbFetch()

test_ID2 <- as.character(test_ID2)

detail_qry <- glue_sql("select * from test_in where ID2 IN ({ID2*})",
                       ID2 = test_ID2, .con = test_con)

details <- dbSendQuery(test_con,detail_qry)

test_out <- dbFetch(details)

I am still curious to understand why the previous code doesn't work. It seems to be more direct.


回答1:


In SQL, prepared statements can be reused more efficiently. With this, prepared statements that use bound parameters can benefit, so using a data-less prepared statement can take advantage of this when you need to reuse the query. (There is a little hand-waving going on here, admittedly ... for now, I'll just offer this as an alternative to glue_sql.)

Starting with a vanilla SQL query, a demonstration of how we want simple sets to be provided (using params=).

# con <- DBI::dbConnect(...)
DBI::dbGetQuery(con, "select 1 where 1 in (1,2)")
#    
# 1 1
DBI::dbGetQuery(con, "select 1 where 1 in (?,?)", params=list(1,2))
#    
# 1 1
DBI::dbGetQuery(con, "select 1 where 1 in (?,?)", params=list(2,3))
# [1] 
# <0 rows> (or 0-length row.names)

Let's formalize this a little:

DBI::dbWriteTable(con, "testcars", mtcars)
cyls <- c(4, 6)
qry <- sprintf("select * from testcars where cyl in (%s)", paste(rep("?", length(cyls)), collapse = ","))
qry
# [1] "select * from testcars where cyl in (?,?)"

Normally, R users will just use DBI::dbGetQuery for a one-shot query, optionally with bound parameters. However, you can do a multi-step if you have an elaborate query and/or need some improvement in query speed. (I cannot off-hand quantify this difference at the moment.) The steps are typically:

  1. Send the query/statement;
  2. Optionally bind parameters;
  3. Fetch the data; finally
  4. Close the resultset.
res <- DBI::dbSendQuery(con, qry)
res
# <OdbcResult>
#   SQL  select * from testcars where cyl in (?,?)
#   ROWS Fetched: 0 [complete]
#        Changed: 0
res2 <- DBI::dbBind(res, list(2, 4))
DBI::dbFetch(res2)
#         row_names  mpg cyl  disp  hp drat    wt  qsec vs am gear carb
# 1      Datsun 710 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
# 2       Merc 240D 24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
# 3        Merc 230 22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
# 4        Fiat 128 32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
# 5     Honda Civic 30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
# 6  Toyota Corolla 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
# 7   Toyota Corona 21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
# 8       Fiat X1-9 27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
# 9   Porsche 914-2 26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
# 10   Lotus Europa 30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
# 11     Volvo 142E 21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2

And we can reuse that query (that result set, specifically) with binding new parameters (without a new query):

res2 <- DBI::dbBind(res, list(6, 7))
DBI::dbFetch(res2)
#        row_names  mpg cyl  disp  hp drat    wt  qsec vs am gear carb
# 1      Mazda RX4 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
# 2  Mazda RX4 Wag 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
# 3 Hornet 4 Drive 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
# 4        Valiant 18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
# 5       Merc 280 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
# 6      Merc 280C 17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
# 7   Ferrari Dino 19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
DBI::dbClearResult(res2)


来源:https://stackoverflow.com/questions/61799476/r-dbgetquery-will-not-select-records-for-all-values-passed-in-params

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!