Как использовать RODBC для сохранения кадра данных в таблицу с первичным ключом, сгенерированным в базе данных - PullRequest
0 голосов
/ 12 мая 2018

Я хотел бы ввести фрейм данных в существующую таблицу в базе данных, используя скрипт R, и я хочу, чтобы таблица в базе данных имела последовательный первичный ключ. Моя проблема в том, что RODBC, похоже, не допускает ограничения первичного ключа.

Вот SQL для создания таблицы, которую я хочу:

CREATE TABLE [dbo].[results] (
    [ID]         INT            IDENTITY (1, 1) NOT NULL,
    [FirstName]  VARCHAR (255) NULL,
    [LastName]   VARCHAR (255) NULL,
    [Birthday]   DATETIME      NULL,
    [CreateDate] DATETIME      NULL,
    CONSTRAINT [PK_dbo.results] PRIMARY KEY CLUSTERED ([ID] ASC)
);

И тест с некоторым кодом R:

ConnectionString1="Driver=ODBC Driver 11 for SQL Server;Server=myserver; Database=TestDb; trusted_connection=yes"
ConnectionString2="Driver=ODBC Driver 11 for SQL Server;Server=notmyserver; Database=TestDb; trusted_connection=yes"
db1=odbcDriverConnect(ConnectionString1)    
query="SELECT a.[firstname] as FirstName
  , a.[lastname] as LastName
  , Cast(a.[dob] as datetime) as Birthday
  , cast(a.createDate as datetime) as CreateDate
FROM [dbo].[People] a"
results=NULL
results=sqlQuery(db1,query,stringsAsFactors=FALSE)
close(db1)

db2=odbcDriverConnect(ConnectionString)
sqlSave(db2, 
    results, 
    append = TRUE, 
    varTypes=c(Birthday="datetime", CreateDate="datetime"),
    colnames = FALSE,  
    rownames = FALSE,fast=FALSE)
close(db2)

Первая часть кода R просто передает некоторые тестовые данные в фрейм данных - он работает нормально, и это не часть моего вопроса здесь (я просто включаю его здесь, чтобы вы могли увидеть, в каком формате тестовые данные ). Когда я запускаю функцию sqlSave, я получаю сообщение об ошибке:

Ошибка в dimnames (x) <- dn: длина 'dimnames' [2] не равна экстенту массива </p>

Однако, если я удаляю первичный ключ из базы данных, все отлично работает с этой таблицей:

CREATE TABLE [dbo].[results] (
    [FirstName]  VARCHAR (255) NULL,
    [LastName]   VARCHAR (255) NULL,
    [Birthday]   DATETIME      NULL,
    [CreateDate] DATETIME      NULL
);

Очевидно, что первичным ключом является проблема. Обычно в рамках сущности или где-либо еще (насколько я понимаю) первичный ключ создается в базе данных при вводе данных.

Я бы хотел добавить данные в таблицу с первичным ключом, используя только R-скрипт. Это возможно? В таблице, к которой я добавляю, уже могут быть данные, поэтому я не вижу способа создать ключи в R, прежде чем пытаться добавить в таблицу.

1 Ответ

0 голосов
/ 12 мая 2018

Проблема в строке 361 в http://github.com/cran/RODBC/blob/master/R/sql.R - data.frame и таблица БД должны иметь одинаковое количество столбцов, в противном случае вы получите эту ошибку с этой трассировкой стека:

Error in dimnames(x) <- dn : 
  length of 'dimnames' [2] not equal to array extent 
3. `colnames<-`(`*tmp*`, value = c("ID", "FirstName", "LastName", 
   "Birthday", "CreateDate")) at sql.R#361
2. sqlwrite(channel, tablename, dat, verbose = verbose, fast = fast, 
   test = test, nastring = nastring) at sql.R#211
1. sqlSave(db2, results, append = TRUE, varTypes = c(Birthday = "datetime", 
    CreateDate = "datetime"), colnames = FALSE, rownames = FALSE, 
    fast = FALSE, verbose = TRUE) 

Если вы добавите столбец идентификатора в ваш data.frame, вы больше не сможете использовать столбец autoinc ID, так что это не решение (или обходной путь).

«Простой» обходной путь с ограничением «одинаковые столбцы»из RODBC::sqlSave is:

  1. Используйте sqlSave для сохранения новых строк в другое имя таблицы
  2. Отправьте insert into ... select from ... через RODBC::sqlQuery, чтобы добавить новые строки в вашисходная таблица, содержащая столбец идентификатора autoinc
  3. Удалите таблицу с новыми строками снова (drop table...)

Лучшим вариантом будет использование нового пакета odbc, которыйтакже предлагает лучшую производительность благодаря групповым вставкам вместо отправки отдельных insert операторов, таких как RODBC:

https://github.com/r-dbi/odbc

Ищите функцию dbWriteTable (которая является реализациейинтерфейса DBI::dbWriteTable).

...