RODBC sqlSave 表创建问题

RODBC sqlSave table creation problems

提问人:Hack-R 提问时间:5/28/2014 最后编辑:Hack-R 更新时间:2/22/2021 访问量:20851

问:

我在使用 RODBC 的 sqlSave 创建表时遇到问题(或者更准确地说,将数据写入创建的表)。

这与现有的 sqlSave 问题/答案不同,因为

  1. 他们遇到的问题是不同的,我可以创建表格,而他们不能
  2. 我已经没有成功地合并了他们的解决方案,例如在运行 sqlSave 之前关闭和重新打开连接
  3. 错误消息是不同的,唯一的例外是上述 2 种方式不同的帖子

我在 Windows RDP 上使用 MS SQL Server 2008 和 64 位 R。

我有一个简单的数据框,只有 1 列充满 3、4 或 5 位整数。

> head(df)
                        colname
1                           564
2                          4336
3                         24810
4                         26206
5                         26433
6                         26553

当我尝试使用 sqlSave 时,没有数据写入表。此外,错误消息听起来像无法创建表,尽管该表实际上是使用 0 行创建的。

根据我发现的建议,我尝试在运行 sqlSave 之前关闭并重新打开 RODBC 连接。即使我使用 ,我也尝试过在执行此操作之前删除表,但这不会影响任何事情。append = TRUE

> sqlSave(db3, df, table = "[Jason].[dbo].[df]", append = TRUE, rownames = FALSE)
Error in sqlSave(db3, df, table = "[Jason].[dbo].[df]",  : 
  42S01 2714 [Microsoft][ODBC SQL Server Driver][SQL Server]There is already 
an object named 'df' in the database.
[RODBC] ERROR: Could not SQLExecDirect 'CREATE TABLE [Jason].[dbo].[df]  
("df" int)'

我还尝试在创建表后在表上使用 sqlUpdate()。无论我是在 R 还是 SQL Server Management Studio 中创建它,我都会收到错误table not found on channel

最后,请注意,我也尝试过在没有 append = TRUE 的情况下,在创建新表时,以及使用和不使用 rownames 选项。

Freenode #R 的 Mr.Flick 让我检查我是否可以使用 sqlQuery 读取空表,事实上,我可以。

更新

我通过以下步骤更接近了一点:

  1. 我创建了一个 ODBC 连接,该连接直接转到 SQL Server 中的数据库,而不仅仅是转到默认(主)数据库,然后在 or 语句中指定表的路径table =tablename =
  2. 在 SQL Server Management Studio 中创建表,如下所示

GO

CREATE TABLE [dbo].[testing123]( [Person_DIMKey] [int] NULL ) ON [PRIMARY]

GO

  1. 在 R 中,我使用了新的 ODBC 连接,并且表名周围没有括号sqlUpdate

  2. 现在 sqlUpdate() 看到该表,但它抱怨它需要一个唯一的列

  3. 指示表中唯一的列是唯一的列,并导致错误,指出该列不存在index = colname

  4. 我删除并重新创建了指定主键的表,

GO

CREATE TABLE [dbo].[jive_BNR_Person_DIMKey]( [jive_BNR_Person_DIMKey] [int] NOT NULL PRIMARY KEY ) ON [PRIMARY]

GO

它生成了主键和索引(根据 SQL Sever Management Studio 的 GUI 界面),名为PK__jive_BNR__2754EC2E30F848ED

  1. 我在sqlUpdate()中将此索引/键指定为唯一列,但出现以下错误:

Error in sqlUpdate(db4, jive_BNR_Person_DIMKey, tablename = "jive_BNR_Person_DIMKey", : index column(s) PK__jive_BNR__2754EC2E30F848ED not in database table

为了记录在案,我为索引指定了正确的列名(而不是“colname”);感谢 MrFlick 要求澄清。

此外,这些步骤在我的帖子中编号为 1 到 7,但 StackOverflow 在显示列表时会重置列表的编号几次。如果有人能帮我清理这篇文章的这一方面,我将不胜感激。

sql-server r sql-server-2008 rodbc

评论

0赞 joran 5/28/2014
我重新打开了它,因为我认为@Andrie可能有点仓促。潜在的重复没有任何明确的答案,无论如何,您似乎已经尝试了那里的主要建议。
0赞 joran 5/28/2014
但请注意,对于无法访问您的数据库的人来说,这些问题可能很难提供帮助。(至少对于可能是也可能不是数据库专家的 R 人员而言。一种可能性是 R 正在尝试追加,但不知何故,表结构与您的数据框不够匹配,因此它正在尝试创建一个新数据框并失败,因为存在具有该名称的表。
0赞 Hack-R 5/28/2014
很公平。我也尝试过没有 append = TRUE 并创建一个新表,我遇到了同样的问题。
0赞 Andrie 5/28/2014
谢谢,@joran我仍然不习惯这些新的超能力。我想标记重复项,而不是完全杀死问题。

答:

0赞 Bryan 5/29/2014 #1

我遇到了同样的问题——我发现解决它的方法是使用常规 SQL 语法创建一个空表,然后通过 .出于某种原因,当我按照您的方式尝试时,我实际上可以在 MSSQL 数据库中看到表名 - 即使在 R 抛出您上面显示的错误消息之后 - 但它将是空的。CREATE TABLEsqlSave

评论

0赞 Hack-R 5/30/2014
不幸的是,它仍然给我错误消息:2S01 2714 [Microsoft][ODBC SQL Server 驱动程序][SQL Server]数据库中已经有一个名为“df”的对象。具有讽刺意味的是,如果我尝试使用不存在的表名,它会说:sqlColumns(channel, tablename) 中的错误:'[Jason]。[dbo]。[df2]':在通道上找不到表
0赞 Bryan 5/30/2014
是的,sqlSave 将创建对象,但它将是空的。您需要做的是删除常规语法,然后以常规语法重新制作表,然后在dfsqlSave
0赞 Hack-R 5/30/2014
我在 SQL Server Management Studio 中使用语句“CREATE TABLE somenewtable (BNR_Person_DIMKey int);”创建了它,然后在 R 中对这个新表运行带有 append = TRUE 的 sqlSave 并出现该错误。我在 R 之外的 SQL 中创建的表在 R 中从未存在过(这意味着在我首次在 SQL Server Management Studio 中执行 CREATE TABLE 之前,我从未尝试使用该表名进行 sqlSave)。我只是在您的评论后再次尝试确认。如果您有任何其他变体要尝试,那么我可以立即尝试。
0赞 Bryan 5/30/2014
啊。无赖 - 我没有那个问题。
9赞 Hack-R 6/3/2014 #2

重新阅读 RODBC 小插曲后,这是有效的简单解决方案:

sqlDrop(db, "df", errors = FALSE)
sqlSave(db, df)

做。

在进行了几天的实验之后,问题似乎源于使用其他选项,特别是或等效地。这些应该是有效的选项,但不知何故,它们设法导致我的特定版本的 RStudio(Windows,64 位,桌面版本,当前版本)、R(Windows,64 位,v3)和/或 MS SQL Server 2008 出现问题。table =tablename =

sqlSave(db, df)如果该表从未存在过,也可以在没有的情况下工作,但作为最佳实践,我在代码中的所有语句之前编写。sqlDrop(db, "df")try(sqlDrop(db, "df", errors = FALSE), silent = TRUE)sqlSave

1赞 squeekwull 1/20/2016 #3

除了之前发布的一些答案外,这是我的解决方法。注意:我将其用作小型 ETL 过程的一部分,并且每次都会删除并重新创建数据库中的目标表。

基本上,您希望将目标表的名称命名为 DataFrame:

RodbcTest <- read.xlsx('test.xlsx', sheet = 4, startRow = 1, colNames = TRUE, skipEmptyRows = TRUE)

然后,请确保连接字符串包含目标数据库(而不仅仅是服务器):

conn <- odbcDriverConnect(paste("DRIVER={SQL Server};Server=localhost\\sqlexpress;Database=Charter;Trusted_Connection=TRUE"))

之后,我运行一个简单的 sqlQuery,如果它存在,则有条件地删除该表:

sqlQuery(conn, "IF OBJECT_ID('Charter.dbo.RodbcTest') IS NOT NULL DROP TABLE Charter.dbo.RodbcTest;")

最后,运行不带 tablename 参数的 sqlSave,这将创建表并使用 DataFrame 填充它:

sqlSave(conn, RodbcTest, safer = FALSE, fast = TRUE)
10赞 d84_n1nj4 10/13/2016 #4

经过几个小时的工作,我终于能够让 sqlSave 工作,同时指定表名 - 深呼吸,从哪里开始。以下是我为使其工作而做的事情的列表:

  • 打开 32 位 ODBC 管理器并创建用户 DSN,并针对特定数据库进行配置。就我而言,我正在创建一个全局临时表,因此我链接到了 tempdb。在 .这是我的代码。odbcConnection(Name)myconn2 <- odbcConnect("SYSTEMDB")
  • 然后,我使用以下代码定义了我的数据类型:.columnTypes <- list(Record = "VARCHAR(10)", Case_Number = "VARCHAR(15)", Claim_Type = "VARCHAR(15)", Block_Date = "datetime", Claim_Processed_Date = "datetime", Status ="VARCHAR(100)")
  • 然后,我使用 和 更新了我的数据框类类型,以匹配上面列出的数据类型。as.characteras.Date
  • 我已经创建了这张表,因为我已经工作了几个小时,所以我不得不使用 .sqlDrop(myconn2, "##R_Claims_Data")
  • 然后我跑了:sqlSave(myconn2, MainClmDF2, tablename = "##R_Claims_Data", verbose=TRUE, rownames= FALSE, varTypes=columnTypes)

然后我的头掉了下来,因为它起作用了!我真的希望这对某人有所帮助。以下是帮助我达到这一点的链接:

未找到表

SQL R 中的 Save

罗德布克

评论

1赞 Nova 3/28/2019
谢谢。残酷的是,这是必要的!
2赞 Jon 6/20/2017 #5

我们遇到了同样的问题,经过一些测试,我们通过在架构和表名引用中不使用方括号解决了这个问题。

即而不是写作

table = "[Jason].[dbo].[df]"

改为写入

table = "Jason.dbo.df"

欣赏这现在已经远远超出了最初的问题,但对于后来遇到这个问题的其他人来说,这就是我们解决它的方式。作为参考,我们通过将一个简单的 1 项数据帧写入一个新表来发现这一点,该表在 SQL 中检查时,表名称中包含方括号。

2赞 Jim G. 1/18/2018 #6

以下是一些经验法则:

  1. 如果问题不顺利,请按照@d84_n1nj4建议手动指定列类型。

columnTypes <- list(Record = "VARCHAR(10)", Case_Number = "VARCHAR(15)", Claim_Type = "VARCHAR(15)", Block_Date = "datetime", Claim_Processed_Date = "datetime", Status ="VARCHAR(100)")

sqlSave(myconn2, MainClmDF2, tablename = "##R_Claims_Data", verbose=TRUE, rownames= FALSE, varTypes=columnTypes)

  1. 如果 #1 不起作用,则继续指定列,但将它们全部指定为 .将其视为临时表或临时表,并在下一步中移动数据,就像 @danas.zuokas 建议的那样。这应该有效,但即使它不起作用,它也能让你更接近金属,并让你在需要时更好地使用 SQL Server Profiler 调试问题。<- 是的,如果您仍然有问题,那可能是由于解析错误或类型转换造成的。VARCHAR(255)sqlQuery

columnTypes <- list(Record = "VARCHAR(255)", Case_Number = "VARCHAR(255)", Claim_Type = "VARCHAR(255)", Block_Date = "VARCHAR(255)", Claim_Processed_Date = "VARCHAR(255)", Status ="VARCHAR(255)")

sqlSave(myconn2, MainClmDF2, tablename = "##R_Claims_Data", verbose=TRUE, rownames= FALSE, varTypes=columnTypes)

sqlQuery(channel, 'insert into real_table select * from R_Claims_Data')

  1. 由于 RODBC 的实现,而不是由于 T-SQL 中的任何固有限制,R 的类型(即 )不会转换为 T-SQL 的类型(即 [1, 0]),因此不要尝试此操作。在 R 层中将类型转换为 [1, 0],或者将其作为 a 下移到 SQL 层,然后在 SQL 层中将其转换为 a。logical[TRUE, FALSE]BITlogicalVARCHAR(5)BIT

评论

1赞 Mahsa Chitsaz 3/14/2018
我完成了上述所有步骤,但对我不起作用,因为我有表名的括号。这是相同的[评论](stackoverflow.com/a/14423966/5266371)。
1赞 heisenbug47 5/14/2019
谢谢@Jim,#2 为我工作。我挣扎了这么久,现在终于安定下来了。