简体   繁体   English

RODBC sqlSave 表创建问题

[英]RODBC sqlSave table creation problems

I'm having trouble creating a table using RODBC's sqlSave (or, more accurately, writing data to the created table).我在使用 RODBC 的 sqlSave 创建表时遇到问题(或者更准确地说,将数据写入创建的表)。

This is different than the existing sqlSave question/answers, as这与现有的 sqlSave 问题/答案不同,因为

  1. the problems they were experiencing were different, I can create tables whereas they could not and他们遇到的问题是不同的,我可以创建表而他们不能并且
  2. I've already unsuccesfully incorporated their solutions, such as closing and reopening the connection before running sqlSave, also我已经没有成功地合并他们的解决方案,例如在运行 sqlSave 之前关闭和重新打开连接,也
  3. The error message is different, with the only exception being a post that was different in the above 2 ways错误信息是不同的,唯一的例外是上述两种方式不同的帖子

I'm using MS SQL Server 2008 and 64-bit R on a Windows RDP.我在 Windows RDP 上使用 MS SQL Server 2008 和 64 位 R。

I have a simple data frame with only 1 column full of 3, 4, or 5-digit integers.我有一个简单的数据框,其中只有 1 列包含 3、4 或 5 位整数。

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

When I try to use sqlSave, no data is written to the table.当我尝试使用 sqlSave 时,没有数据写入表中。 Additionally, an error message makes it sound like the table can't be created though the table does in fact get created with 0 rows.此外,一条错误消息使它听起来像是无法创建该表,尽管该表实际上是用 0 行创建的。

Based on a suggestion I found, I've tried closing and re-opening the RODBC connection right before running sqlSave.根据我发现的建议,我尝试在运行 sqlSave 之前关闭并重新打开 RODBC 连接。 Even though I use append = TRUE , I've tried dropping the table before doing this but it doesn't affect anything.即使我使用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)'

I've also tried using sqlUpdate() on the table once it's been created.一旦它被创建,我也尝试在表上使用 sqlUpdate() 。 It doesn't matter if I create it in R or SQL Server Management Studio, I get the error table not found on channel无论我是在 R 还是 SQL Server Management Studio 中创建它都没有关系,但在table not found on channel错误table not found on channel

Finally, note that I have also tried this without append = TRUE and when creating a new table, as well as with and without the rownames option.最后,请注意,我在没有 append = TRUE 的情况下以及在创建新表时以及使用和不使用 rownames 选项时也尝试了此操作。

Mr.Flick from Freenode's #R had me check if I could read in the empty table using sqlQuery and indeed, I can. Freenode's #R 的 Mr.Flick 让我检查是否可以使用 sqlQuery 读取空表,确实可以。

Update更新

I've gotten a bit closer with the following steps:我通过以下步骤更接近了:

  1. I created an ODBC connection that goes directly to my Database within the SQL Server, instead of just to the default (Master) DB then specifying the path to the table within the table = or tablename = statements我创建了一个 ODBC 连接,它直接连接到 SQL Server 中的数据库,而不是仅连接到默认(主)数据库,然后在table =tablename =语句中指定表的路径
  2. Created the table in SQL Server Management Studio as follows在 SQL Server Management Studio 中创建表如下

GO

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

GO

  1. In RI used sqlUpdate with my new ODBC connection and no brackets around the tablename在 RI 中使用sqlUpdate和我的新 ODBC 连接并且表名周围没有括号

  2. Now sqlUpdate() sees the table, however it complains that it needs a unique column现在 sqlUpdate() 看到了表,但是它抱怨它需要一个唯一的列

  3. Indicating that the only column in the table is the unique column with index = colname results in an error saying that the column does not exist指示表中唯一的列是index = colname的唯一列会导致错误,指出该列不存在

  4. I dropped and recreated the table specifying a primary key,我删除并重新创建了指定主键的表,

GO

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

GO

which generated both a Primary Key and Index (according to the GUI interface of SQL Sever Management Studio) named PK__jive_BNR__2754EC2E30F848ED它生成了一个名为PK__jive_BNR__2754EC2E30F848ED的主键和索引(根据 SQL Sever Management Studio 的 GUI 界面)

  1. I specified this index/key as the unique column in sqlUpdate() but I get the following error:我将此索引/键指定为 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 Error in sqlUpdate(db4, jive_BNR_Person_DIMKey, tablename = "jive_BNR_Person_DIMKey", : index column(s) PK__jive_BNR__2754EC2E30F848ED not in database table

For the record, I was specifying the correct column name (not "colname") for index;为了记录,我为索引指定了正确的列名(不是“colname”); thanks to MrFlick for requesting clarification.感谢 MrFlick 要求澄清。

Also, these steps are numbered 1 through 7 in my post but StackOverflow resets the numbering of the list a few times when it gets displayed.此外,这些步骤在我的帖子中编号为 1 到 7,但 StackOverflow 会在显示列表时多次重置列表的编号。 If anyone can help me clean that aspect of this post up I'd appreciate it.如果有人能帮我清理这篇文章的那个方面,我将不胜感激。

After hours of working on this, I was finally able to get sqlSave to work while specifying the table name--deep breathe, where to start.经过数小时的工作,我终于能够在指定表名的同时让 sqlSave 工作——深呼吸,从哪里开始。 Here is the list of things I did to get this to work:这是我为使其工作而做的事情列表:

  • Open 32-bit ODBC Administrator and create a User DSN and configure it for your specific database.打开 32 位 ODBC 管理器并创建一个用户 DSN 并为您的特定数据库配置它。 In my case, I am creating a global temp table so I linked to tempdb.就我而言,我正在创建一个全局临时表,因此我链接到了 tempdb。 Use this connection Name in your odbcConnection(Name) .在您的odbcConnection(Name)使用此连接名称。 Here is my code myconn2 <- odbcConnect("SYSTEMDB") .这是我的代码myconn2 <- odbcConnect("SYSTEMDB")
  • Then I defined my data types with the following code: columnTypes <- list(Record = "VARCHAR(10)", Case_Number = "VARCHAR(15)", Claim_Type = "VARCHAR(15)", Block_Date = "datetime", Claim_Processed_Date = "datetime", Status ="VARCHAR(100)") .然后我用以下代码定义了我的数据类型: columnTypes <- list(Record = "VARCHAR(10)", Case_Number = "VARCHAR(15)", Claim_Type = "VARCHAR(15)", Block_Date = "datetime", Claim_Processed_Date = "datetime", Status ="VARCHAR(100)")
  • I then updated my data frame class types using as.character and as.Date to match the data types listed above.然后我使用as.characteras.Date更新了我的数据框类类型以匹配上面列出的数据类型。
  • I already created the table since I've been working on it for hours so I had to drop the table using sqlDrop(myconn2, "##R_Claims_Data") .我已经创建了这个表,因为我已经工作了几个小时,所以我不得不使用sqlDrop(myconn2, "##R_Claims_Data")删除该表。
  • I then ran: sqlSave(myconn2, MainClmDF2, tablename = "##R_Claims_Data", verbose=TRUE, rownames= FALSE, varTypes=columnTypes)然后我跑了: sqlSave(myconn2, MainClmDF2, tablename = "##R_Claims_Data", verbose=TRUE, rownames= FALSE, varTypes=columnTypes)

Then my head fell off because it worked!然后我的头掉了下来,因为它有效! I really hope this helps someone going forward.我真的希望这有助于有人前进。 Here are the links that helped me get to this point:以下是帮助我达到这一点的链接:

Table not found 未找到表

sqlSave in R R中的sqlSave

RODBC RODBC

After re-reading the RODBC vignette and here's the simple solution that worked:重新阅读 RODBC 小插图后,这是一个有效的简单解决方案:

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

Done.完毕。

After experimenting with this a lot more for several days, it seems that the problems stemmed from the use of the additional options, particularlly table = or, equivalently, tablename = .经过几天的更多实验,似乎问题源于使用附加选项,特别是table =或等效的tablename = Those should be valid options but somehow they manage to cause problems with my particular version of RStudio ((Windows, 64 bit, desktop version, current build), R (Windows, 64 bit, v3), and/or MS SQL Server 2008.这些应该是有效的选项,但不知何故,它们设法导致我的特定版本的 RStudio((Windows,64 位,桌面版本,当前版本),R(Windows,64 位,v3)和/或 MS SQL Server 2008 出现问题。

sqlSave(db, df) will also work without sqlDrop(db, "df") if the table has never existed, but as a best practice I'm writing try(sqlDrop(db, "df", errors = FALSE), silent = TRUE) before all sqlSave statements in my code.如果表从未存在, sqlSave(db, df)也可以在没有sqlDrop(db, "df")的情况下工作,但作为最佳实践,我正在编写try(sqlDrop(db, "df", errors = FALSE), silent = TRUE)在我的代码中的所有sqlSave语句之前。

We have had this same problem, which after a bit of testing we solved simply by not using square brackets in the schema and table name reference.我们遇到了同样的问题,经过一些测试,我们通过在架构和表名引用中不使用方括号来解决。

ie rather than writing即而不是写作

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

instead write而是写

table = "Jason.dbo.df"

Appreciate this is now long past the original question, but just for anyone else who subsequently trips up on this problem, this is how we solved it.欣赏这现在已经超越了最初的问题,但对于随后遇到这个问题的其他人来说,这就是我们解决它的方式。 For reference, we found this out by writing a simple 1 item dataframe to a new table, which when inspected in SQL contained the square brackets in the table name.作为参考,我们通过将一个简单的 1 项数据框写入一个新表发现了这一点,当在 SQL 中检查时,该表包含表名中的方括号。

Here are a few rules of thumb:以下是一些经验法则:

  1. If things aren't working out, then manually specify the column types just as @d84_n1nj4 suggested.如果事情没有解决,那么就像@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. If #1 doesn't work, then continue to specify the columns, but specify them all as VARCHAR(255) .如果 #1 不起作用,则继续指定列,但将它们全部指定为VARCHAR(255) Treat this as a temp or staging table, and move the data over with sqlQuery with your next step, just as @danas.zuokas suggested.将其视为临时表或临时表,并在下一步中使用sqlQuery移动数据,就像@danas.zuokas建议的那样。 This should work, but even if it doesn't, it gets you closer to the metal and puts you in better position to debug the problem with SQL Server Profiler if you need it.这应该有效,但即使无效,它也会让您更接近实际情况,并使您在需要时可以更好地使用 SQL Server Profiler 调试问题。 <- And yes, if you still have a problem, it's likely due to either a parsing error or type conversion. <- 是的,如果您仍然遇到问题,可能是由于解析错误或类型转换造成的。

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. Due to RODBC's implementation, and not due to any inherent limitation in T-SQL , R's logical type (ie [TRUE, FALSE] ) will not convert to T-SQL's BIT type (ie [1, 0]), so don't try this.由于 RODBC 的实现,而不是由于 T-SQL 中的任何固有限制,R 的logical类型(即[TRUE, FALSE] )不会转换为 T-SQL 的BIT类型(即 [1, 0]),所以不要尝试这个。 Either convert the logical type to [1, 0] in the R layer or take it down to the SQL layer as a VARCHAR(5) and convert it to a BIT in the SQL layer.在 R 层将logical类型转换为 [1, 0] 或将其作为VARCHAR(5)下放到 SQL 层并在 SQL 层将其转换为BIT

In addition to some of the answered posted earlier, here's my workaround.除了之前发布的一些回答之外,这是我的解决方法。 NOTE: I use this as part of a small ETL process, and the destination table in the DB is dropped and recreated each time.注意:我将此用作小型 ETL 过程的一部分,并且每次都会删除并重新创建数据库中的目标表。

Basically you want to name your dataframe what you destination table is named:基本上,您想将数据框命名为目标表的名称:

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

Then make sure your connection string includes the target database (not just server):然后确保您的连接字符串包含目标数据库(不仅仅是服务器):

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

after that, I run a simple sqlQuery that conditionally drops the table if it exists:之后,我运行一个简单的 sqlQuery,如果表存在,则有条件地删除该表:

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

Then finally, run sqlSave without the tablename param, which will create the table and populate it with your dataframe:最后,在没有 tablename 参数的情况下运行 sqlSave,这将创建表并用您的数据框填充它:

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

I've encountered the same problem-- the way I found around it is to create the an empty table using regular CREATE TABLE SQL syntax, and then append to it via sqlSave .我遇到了同样的问题——我发现的方法是使用常规的CREATE TABLE SQL 语法创建一个空表,然后通过sqlSave附加到它。 For some reason, when I tried it your way, I could actually see the table name in the MSSQL database - even after R threw the error message you showed above - but it would be empty.出于某种原因,当我按照你的方式尝试时,我实际上可以在 MSSQL 数据库中看到表名——即使在 R 抛出你上面显示的错误消息之后——但它会是空的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM