Проблемы с созданием таблицы RODBC sqlSave

У меня возникли проблемы с созданием таблицы с помощью RODBC sqlSave (или, точнее, с записью данных в созданную таблицу).

Это отличается от существующих вопросов/ответов sqlSave, поскольку

  1. проблемы, с которыми они сталкивались, были другими, я могу создавать таблицы, а они не могут, и
  2. Я уже безуспешно включил их решения, такие как закрытие и повторное открытие соединения перед запуском sqlSave, а также
  3. Сообщение об ошибке отличается, за исключением сообщения, которое отличается двумя указанными выше способами.

Я использую MS SQL Server 2008 и 64-битный R на Windows RDP.

У меня есть простой фрейм данных только с 1 столбцом, состоящим из 3, 4 или 5-значных целых чисел.

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

Когда я пытаюсь использовать sqlSave, данные в таблицу не записываются. Кроме того, сообщение об ошибке звучит так, как будто таблица не может быть создана, хотя на самом деле таблица создается с 0 строками.

Основываясь на предложении, которое я нашел, я попытался закрыть и снова открыть соединение RODBC прямо перед запуском sqlSave. Несмотря на то, что я использую 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's #R попросил меня проверить, могу ли я читать пустую таблицу с помощью sqlQuery, и действительно могу.

Обновить

Я стал немного ближе со следующими шагами:

  1. Я создал соединение ODBC, которое идет непосредственно к моей базе данных в SQL Server, а не только к базе данных по умолчанию (Master) DB, а затем указал путь к таблице в операторах 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

который сгенерировал как первичный ключ, так и индекс (в соответствии с графическим интерфейсом SQL Sever Management Studio) с именем 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 несколько раз сбрасывает нумерацию списка при его отображении. Если кто-нибудь может помочь мне очистить этот аспект этого сообщения, я был бы признателен.


person Hack-R    schedule 28.05.2014    source источник
comment
Я снова открыл это, потому что я думаю, что @Andrie, возможно, был немного поспешным. Потенциальный дубликат не имеет четкого ответа, и вы, похоже, уже попробовали основное предложение.   -  person joran    schedule 28.05.2014
comment
Имейте в виду, однако, что люди, не имеющие доступа к вашей базе данных, могут столкнуться с такими проблемами. (По крайней мере, для пользователей R, которые могут быть или не быть экспертами по БД.) Одна из возможностей заключается в том, что R пытается добавить, но каким-то образом структура таблицы недостаточно хорошо соответствует вашему фрейму данных, поэтому он пытается создать новый. и сбой, потому что таблица с таким именем существует.   -  person joran    schedule 28.05.2014
comment
Справедливо. Я также пробовал без добавления = TRUE и создания новой таблицы, у меня была такая же проблема.   -  person Hack-R    schedule 28.05.2014
comment
Спасибо, @joran Я все еще не привык к этим новым сверхспособностям. Я хотел пометить дубликат, а не полностью убить вопрос.   -  person Andrie    schedule 28.05.2014


Ответы (6)


После нескольких часов работы над этим я, наконец, смог заставить 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)

Тогда у меня отвалилась голова, потому что это сработало! Я действительно надеюсь, что это поможет кому-то идти вперед. Вот ссылки, которые помогли мне добраться до этого момента:

Таблица не найдена

sqlSave в R

RODBC

person d84_n1nj4    schedule 12.10.2016
comment
Спасибо. Брутально, что это необходимо! - person Nova; 27.03.2019

После повторного прочтения виньетки 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"), если таблицы никогда не существовало, но в качестве наилучшей практики я пишу try(sqlDrop(db, "df", errors = FALSE), silent = TRUE) перед всеми операторами sqlSave в своем коде.

person Hack-R    schedule 02.06.2014

У нас была такая же проблема, которую после небольшого тестирования мы решили, просто не используя квадратные скобки в ссылке на схему и имя таблицы.

то есть вместо того, чтобы писать

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

вместо этого напишите

table = "Jason.dbo.df"

Учтите, что этот вопрос уже давно позади, но для всех, кто впоследствии столкнется с этой проблемой, мы решили ее именно так. Для справки, мы обнаружили это, записав простой кадр данных с 1 элементом в новую таблицу, которая при проверке в SQL содержала квадратные скобки в имени таблицы.

person Jon    schedule 20.06.2017

Вот несколько практических правил:

  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, а также не из-за каких-либо внутренних ограничений T-SQL, R logical тип (т.е. [TRUE, FALSE]) не преобразуется в тип BIT T-SQL (т.е. [1, 0]), поэтому не пытайтесь это сделать. Либо преобразуйте тип logical в [1, 0] на уровне R, либо перенесите его на уровень SQL как VARCHAR(5) и преобразуйте в BIT на уровне SQL.
person Jim G.    schedule 18.01.2018
comment
Я сделал все вышеперечисленные шаги, но у меня это не сработало, так как у меня были скобки для имени таблицы. Вот тот же [комментарий] (stackoverflow.com/a/14423966/5266371). - person Mahsa Chitsaz; 14.03.2018
comment
спасибо @Jim, № 2 у меня сработал. Я так долго боролся и, наконец, успокоился. - person heisenbug47; 14.05.2019

В дополнение к некоторым ответам, опубликованным ранее, вот мой обходной путь. ПРИМЕЧАНИЕ. Я использую это как часть небольшого процесса 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 без параметра tablename, который создаст таблицу и заполнит ее вашим фреймом данных:

sqlSave(conn, RodbcTest, safer = FALSE, fast = TRUE)
person squeekwull    schedule 20.01.2016

Я столкнулся с той же проблемой - способ, которым я ее нашел, - создать пустую таблицу с использованием обычного синтаксиса CREATE TABLE SQL, а затем добавить к ней через sqlSave. По какой-то причине, когда я попробовал сделать это по-вашему, я действительно мог видеть имя таблицы в базе данных MSSQL - даже после того, как R выдал сообщение об ошибке, которое вы показали выше, - но оно было пустым.

person Bryan    schedule 28.05.2014
comment
К сожалению, он по-прежнему выдает мне сообщение об ошибке: 2S01 2714 [Microsoft] [Драйвер ODBC SQL Server] [SQL Server] В базе данных уже есть объект с именем «df». По иронии судьбы, если я попробую это с несуществующим именем таблицы, он скажет: Ошибка в sqlColumns (канал, имя таблицы): ‘[Jason].[dbo].[df2]’: таблица не найдена на канале - person Hack-R; 29.05.2014
comment
Да, sqlSave создаст объект, но он будет пустым. Что вам нужно сделать, так это удалить df в обычном синтаксисе, затем переделать таблицу в обычном синтаксисе, а затем добавить к ней sqlSave - person Bryan; 29.05.2014
comment
Я создал его в SQL Server Management Studio с помощью инструкции CREATE TABLE somenewtable (BNR_Person_DIMKey int); затем в R запустил sqlSave с append = TRUE для этой новой таблицы и получил эту ошибку. Таблица, которую я создал в SQL вне R, никогда не существовала в R (это означает, что я никогда не пытался sqlSave использовать это имя таблицы, пока впервые не сделал CREATE TABLE в SQL Server Management Studio). Я только что попробовал еще раз после вашего комментария, чтобы подтвердить. Если у вас есть какой-либо другой вариант, чтобы попробовать, я готов попробовать его немедленно. - person Hack-R; 29.05.2014
comment
Арх. Облом - у меня не было этой проблемы. - person Bryan; 29.05.2014