【问题标题】:RODBC sqlSave table creation problemsRODBC sqlSave 建表问题
【发布时间】:2014-07-17 19:04:09
【问题描述】:

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

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

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

我在 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 中的数据库,而不是只连接到默认(主)数据库,然后在 table =tablename = 语句中指定表的路径
  2. 在 SQL Server Management Studio 中创建表如下

GO

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

GO

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

  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

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

  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 在列表显示时会重置几次列表的编号。如果有人可以帮助我清理这篇文章的这方面,我将不胜感激。

【问题讨论】:

  • 我重新打开它是因为我认为@Andrie 可能有点草率。潜在的duplicate 没有任何明确的答案,而且您似乎已经尝试过那里的主要建议。
  • 请注意,对于无法访问您的数据库的人来说,这类问题可能很难解决。 (至少对于可能是也可能不是数据库专家的 R 人来说。)一种可能性是 R 正在尝试追加,但不知何故,表结构与您的数据框不够匹配,因此它正在尝试创建一个新的失败,因为存在同名的表。
  • 很公平。我也试过没有 append = TRUE 并创建一个新表,我遇到了同样的问题。
  • 谢谢,@joran 我仍然不习惯这些新的超级大国。我想标记重复项,而不是完全取消问题。

标签: sql sql-server r sql-server-2008 rodbc


【解决方案1】:

经过几个小时的工作,我终于能够在指定表名的同时让 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)

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

Table not found

sqlSave in R

RODBC

【讨论】:

  • 谢谢。残酷的是,这是必要的!
【解决方案2】:

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

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

完成。

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

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

【讨论】:

    【解决方案3】:

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

    即而不是写

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

    改为写

    table = "Jason.dbo.df"
    

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

    【讨论】:

      【解决方案4】:

      以下是一些经验法则:

      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 不起作用,则继续指定列,但将它们全部指定为VARCHAR(255)。将其视为临时表或临时表,并在下一步使用sqlQuery 移动数据,就像@danas.zuokas 建议的那样。这应该有效,但即使没有,它也能让您更接近金属,并让您在需要时使用 SQL Server Profiler 调试问题。

      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的实现,以及not due to any inherent limitation in T-SQL,R的logical类型(即[TRUE, FALSE])不会转换为T-SQL的BIT类型(即[1, 0]),所以不要尝试这个.在 R 层将logical 类型转换为 [1, 0] 或将其作为VARCHAR(5) 下放到 SQL 层,然后在 SQL 层将其转换为 BIT

      【讨论】:

      • 我完成了上述所有步骤,但没有为我工作,因为表名有括号。这是相同的[评论] (stackoverflow.com/a/14423966/5266371)。
      • 感谢@Jim,#2 为我工作。我挣扎了这么久,终于安顿下来了。
      【解决方案5】:

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

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

      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;")
      

      最后,运行不带表名参数的 sqlSave,这将创建表并使用您的数据框填充它:

      sqlSave(conn, RodbcTest, safer = FALSE, fast = TRUE)
      

      【讨论】:

        【解决方案6】:

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

        【讨论】:

        • 不幸的是,它仍然给我错误消息:2S01 2714 [Microsoft][ODBC SQL Server Driver][SQL Server]数据库中已经有一个名为“df”的对象。具有讽刺意味的是,如果我尝试使用不存在的表名,它会显示: sqlColumns(channel, tablename) 中的错误:'[Jason].[dbo].[df2]': table not found on channel
        • 是的,sqlSave 将创建对象,但它将为空。您需要做的是以常规语法删除df,然后以常规语法重新制作表格,然后在sqlSave 中附加到它
        • 我在 SQL Server Management Studio 中使用语句“CREATE TABLE somenewtable (BNR_Person_DIMKey int);”创建了它然后在 R 中,在这个新表上运行带有 append = TRUE 的 sqlSave 并得到了那个错误。我在 R 之外的 SQL 中创建的表从未存在于 R 中(这意味着在我第一次在 SQL Server Management Studio 中创建 TABLE 之前,我从未尝试使用该表名进行 sqlSave)。在你的评论确认后,我又试了一次。如果您有任何其他变体可以尝试,那么我可以立即尝试。
        • 啊。太糟糕了——我没有那个问题。
        猜你喜欢
        • 2011-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多