如何使用RODBC将数据帧保存到具有在数据库中生成的主键的表

Mat*_*hew 5 sql sql-server r rodbc

我想使用R脚本将数据框输入到数据库中的现有表中,并且我希望数据库中的表具有顺序主键.我的问题是RODBC似乎不允许主键约束.

这是用于创建我想要的表的SQL:

CREATE TABLE [dbo].[results] (
    [ID]         INT            IDENTITY (1, 1) NOT NULL,
    [FirstName]  VARCHAR (255) NULL,
    [LastName]   VARCHAR (255) NULL,
    [Birthday]   DATETIME      NULL,
    [CreateDate] DATETIME      NULL,
    CONSTRAINT [PK_dbo.results] PRIMARY KEY CLUSTERED ([ID] ASC)
);
Run Code Online (Sandbox Code Playgroud)

并使用一些R代码进行测试:

ConnectionString1="Driver=ODBC Driver 11 for SQL Server;Server=myserver; Database=TestDb; trusted_connection=yes"
ConnectionString2="Driver=ODBC Driver 11 for SQL Server;Server=notmyserver; Database=TestDb; trusted_connection=yes"
db1=odbcDriverConnect(ConnectionString1)    
query="SELECT a.[firstname] as FirstName
  , a.[lastname] as LastName
  , Cast(a.[dob] as datetime) as Birthday
  , cast(a.createDate as datetime) as CreateDate
FROM [dbo].[People] a"
results=NULL
results=sqlQuery(db1,query,stringsAsFactors=FALSE)
close(db1)

db2=odbcDriverConnect(ConnectionString)
sqlSave(db2, 
    results, 
    append = TRUE, 
    varTypes=c(Birthday="datetime", CreateDate="datetime"),
    colnames = FALSE,  
    rownames = FALSE,fast=FALSE)
close(db2)
Run Code Online (Sandbox Code Playgroud)

R代码的第一部分只是将一些测试数据放入数据框中 - 它工作正常,这不是我的问题的一部分(我只是在这里包含它,所以你可以看到测试数据是什么格式).当我运行该sqlSave函数时,我收到一条错误消息:

dimnames(x)中的错误< - dn:'dimnames'的长度[2]不等于数组范围

但是,如果我从数据库中删除主键,一切都可以正常使用此表:

CREATE TABLE [dbo].[results] (
    [FirstName]  VARCHAR (255) NULL,
    [LastName]   VARCHAR (255) NULL,
    [Birthday]   DATETIME      NULL,
    [CreateDate] DATETIME      NULL
);
Run Code Online (Sandbox Code Playgroud)

显然,主要关键是问题.通常使用实体框架或其他任何东西(据我所知),当您输入数据时,主密钥将在数据库中创建.

我想要一种仅使用R脚本将数据附加到具有主键的表的方法.那可能吗?我正在添加的表中已经存在数据,所以在尝试追加到表之前,我并没有真正看到在R中创建键的方法.

R Y*_*oda 4

问题是http://github.com/cran/RODBC/blob/master/R/sql.R中的第 361 行- data.frame 和 DB 表必须具有完全相同的列数,否则您会收到此错误这个堆栈跟踪:

Error in dimnames(x) <- dn : 
  length of 'dimnames' [2] not equal to array extent 
3. `colnames<-`(`*tmp*`, value = c("ID", "FirstName", "LastName", 
   "Birthday", "CreateDate")) at sql.R#361
2. sqlwrite(channel, tablename, dat, verbose = verbose, fast = fast, 
   test = test, nastring = nastring) at sql.R#211
1. sqlSave(db2, results, append = TRUE, varTypes = c(Birthday = "datetime", 
    CreateDate = "datetime"), colnames = FALSE, rownames = FALSE, 
    fast = FALSE, verbose = TRUE) 
Run Code Online (Sandbox Code Playgroud)

如果将 ID 列添加到您的列表中,data.frame您将无法再使用autoincID 列,因此这不是解决方案(或解决方法)。

解决“相同列”限制的“简单”解决方法RODBC::sqlSave是:

  1. 用于sqlSave将新行保存到另一个表名中
  2. 发送insert into ... select from ...viaRODBC::sqlQuery以将新行追加到包含 autoinc ID 列的原始表中
  3. 再次删除包含新行的表 ( drop table...)

更好的选择是使用新odbc包,它还通过批量插入提供更好的性能,而不是像insert这样发送单个语句RODBC

https://github.com/r-dbi/odbc

查找函数dbWriteTable(它是接口的实现DBI::dbWriteTable)。