dbWriteTable 函数返回 TRUE 状态,即使它未能插入记录,因为它违反了架构约束

Abh*_*ute 5 r unique-constraint rmysql shiny r-dbi

我正在使用DBI,RMySql包与数据库交互MySql

以下是有关配置的更多详细信息:

  • R版本:3.3.2
  • DBI版本:0.7
  • RMySql版本:0.10.13

以下是表 Site 的架构

+------------+-------------+------+-----+---------+----------------+
| Field      | Type        | Null | Key | Default | Extra          |
+------------+-------------+------+-----+---------+----------------+
| id         | int(11)     | NO   | PRI | NULL    | auto_increment |
| short_name | varchar(10) | NO   | UNI | NULL    |                |
| full_name  | varchar(50) | NO   | UNI | NULL    |                |
+------------+-------------+------+-----+---------+----------------+
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,字段short_name&full_name具有UNIQUE&NOT NULL约束。

在尝试插入具有重复项short_namefull_name表中已存在的行时,dbWriteTable不会发生此类行插入,但它会返回状态TRUE,即使它违反了UNIQUE约束。对于约束也会发生同样的情况NOT NULL

DBI这是&的预期行为吗dbWriteTable?为什么它不返回FALSE状态?

编辑:我还观察到,即使在违反约束的情况下dbSendStatement(),也dbSendQuery()不会给出任何错误。有什么办法可以了解这个吗?

Ada*_*son 1

我觉得必须有更好的方法来做到这一点,但我知道的解决方案是使用 tryCatch 来捕获错误消息。除了捕获消息之外,还有其他选项......例如,您可以采取行动。

文档中解释了 dbWriteTable 不返回 FALSE 的原因。仅当 DBI 函数出现问题时,它才会返回 FALSE。你的问题出在数据库上。我知道这是语义,但它在这里有所不同。

我编了一个例子,因为我没有从问题中得到一个例子。

library(DBI)
library(RSQLite)

con <- dbConnect(RSQLite::SQLite(), ":memory:")

dbSendQuery(con,
            "CREATE TABLE mtcars
            (
              mpg REAL,
              cyl INTEGER,
              disp REAL,
              hp REAL, 
              drat REAL NOT NULL
            );")

dbWriteTable(con, "mtcars", mtcars[1:5,1:5], append = TRUE)

test_db <- dbGetQuery(con,"SELECT * FROM mtcars")
test_db
# mpg cyl disp  hp drat
# 1 21.0   6  160 110 3.90
# 2 21.0   6  160 110 3.90
# 3 22.8   4  108  93 3.85
# 4 21.4   6  258 110 3.08
# 5 18.7   8  360 175 3.15

# Can't capture output
result <- dbWriteTable(con, "mtcars", 
             data.frame(mpg = 1, cyl = 2, disp = 3, hp = 4, drat = NA),
             append = TRUE)
result
# Error: object 'result' not found

# Let's try checking exceptions
# This doesn't work because it is checking for exceptions in the DBI commands...not in the database.
result <- dbGetException(con)
result
# $errorNum
# [1] 0
# 
# $errorMsg
# [1] "OK"

# Because of the error there wasn't a change in the database.
test_db <- dbGetQuery(con,"SELECT * FROM mtcars")
test_db
# mpg cyl disp  hp drat
# 1 21.0   6  160 110 3.90
# 2 21.0   6  160 110 3.90
# 3 22.8   4  108  93 3.85
# 4 21.4   6  258 110 3.08
# 5 18.7   8  360 175 3.15

# We can use a tryCatch to capture error or warning messages
tryCatch({
  dbWriteTable(con, "mtcars", 
               data.frame(mpg = 1, cyl = 2, disp = 3, hp = 4, drat = NA),
               append = TRUE)
  result <- dbGetException(con)
},
  error = function(e) result <<- conditionMessage(e),
  warning = function(w) result <<- conditionMessage(w)
)
Run Code Online (Sandbox Code Playgroud)