提问人:Hack-R 提问时间:5/28/2014 最后编辑:Hack-R 更新时间:2/22/2021 访问量:20851
RODBC sqlSave 表创建问题
RODBC sqlSave table creation problems
问:
我在使用 RODBC 的 sqlSave 创建表时遇到问题(或者更准确地说,将数据写入创建的表)。
这与现有的 sqlSave 问题/答案不同,因为
- 他们遇到的问题是不同的,我可以创建表格,而他们不能
- 我已经没有成功地合并了他们的解决方案,例如在运行 sqlSave 之前关闭和重新打开连接
- 错误消息是不同的,唯一的例外是上述 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 读取空表,事实上,我可以。
更新
我通过以下步骤更接近了一点:
- 我创建了一个 ODBC 连接,该连接直接转到 SQL Server 中的数据库,而不仅仅是转到默认(主)数据库,然后在 or 语句中指定表的路径
table =
tablename =
- 在 SQL Server Management Studio 中创建表,如下所示
GO
CREATE TABLE [dbo].[testing123](
[Person_DIMKey] [int] NULL
) ON [PRIMARY]
GO
在 R 中,我使用了新的 ODBC 连接,并且表名周围没有括号
sqlUpdate
现在 sqlUpdate() 看到该表,但它抱怨它需要一个唯一的列
指示表中唯一的列是唯一的列,并导致错误,指出该列不存在
index = colname
我删除并重新创建了指定主键的表,
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
- 我在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 语法创建一个空表,然后通过 .出于某种原因,当我按照您的方式尝试时,我实际上可以在 MSSQL 数据库中看到表名 - 即使在 R 抛出您上面显示的错误消息之后 - 但它将是空的。CREATE TABLE
sqlSave
评论
df
sqlSave
重新阅读 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
除了之前发布的一些答案外,这是我的解决方法。注意:我将其用作小型 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)
经过几个小时的工作,我终于能够让 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.character
as.Date
- 我已经创建了这张表,因为我已经工作了几个小时,所以我不得不使用 .
sqlDrop(myconn2, "##R_Claims_Data")
- 然后我跑了:
sqlSave(myconn2, MainClmDF2, tablename = "##R_Claims_Data", verbose=TRUE, rownames= FALSE, varTypes=columnTypes)
然后我的头掉了下来,因为它起作用了!我真的希望这对某人有所帮助。以下是帮助我达到这一点的链接:
评论
我们遇到了同样的问题,经过一些测试,我们通过在架构和表名引用中不使用方括号解决了这个问题。
即而不是写作
table = "[Jason].[dbo].[df]"
改为写入
table = "Jason.dbo.df"
欣赏这现在已经远远超出了最初的问题,但对于后来遇到这个问题的其他人来说,这就是我们解决它的方式。作为参考,我们通过将一个简单的 1 项数据帧写入一个新表来发现这一点,该表在 SQL 中检查时,表名称中包含方括号。
以下是一些经验法则:
- 如果问题不顺利,请按照@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 不起作用,则继续指定列,但将它们全部指定为 .将其视为临时表或临时表,并在下一步中移动数据,就像 @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')
- 由于 RODBC 的实现,而不是由于 T-SQL 中的任何固有限制,R 的类型(即 )不会转换为 T-SQL 的类型(即 [1, 0]),因此不要尝试此操作。在 R 层中将类型转换为 [1, 0],或者将其作为 a 下移到 SQL 层,然后在 SQL 层中将其转换为 a。
logical
[TRUE, FALSE]
BIT
logical
VARCHAR(5)
BIT
评论