RODBC sqlSave () останавливает запрос вставки при нарушении PK - PullRequest
0 голосов
/ 11 ноября 2010

Я разработал онлайн-опрос, в котором мои данные хранятся в базе данных Microsoft SQL 2005.Я написал набор проверок выбросов для своих данных в R. Общий рабочий процесс для этих сценариев:

  1. Чтение данных из базы данных SQL с помощью sqlQuery ()
  2. Выполнение анализа выбросов
  3. Запись респондентов-нарушителей обратно в базу данных в отдельной таблице с использованием sqlSave ()

Таблица, в которую я пишу, имеет структуру:

CREATE TABLE outliers2(
    modelid int
    , password varchar(50)
    , reason varchar(50),
Constraint PK_outliers2 PRIMARY KEY(modelid, reason)
)
GO

Как вы можетевидите, я установил первичный ключ для modelid и reason.Один и тот же респондент может быть отклонением для нескольких проверок, но я не хочу вставлять одно и то же сочетание модели и причины для любого респондента.

Поскольку мы все еще собираем данные, я хотел бы иметь возможность обновлять эти сценарии ежедневно / еженедельно по мере разработки моделей, которые я оцениваю на основе данных.Вот общая форма команды sqlSave(), которую я использую:

sqlSave(db, db.insert, "outliers2", append = TRUE, fast = FALSE, rownames = FALSE)

, где db - действительное соединение ODBC, а db.insert имеет форму

> head(db.insert)
  modelid password          reason
1     873       abkd WRONG DIRECTION
2     875       ab9d WRONG DIRECTION
3     890       akdw WRONG DIRECTION
4     905       pqjd WRONG DIRECTION
5     941       ymne WRONG DIRECTION
6     944       okyt WRONG DIRECTION

sqlSave() дросселирует при попытке вставить строку, которая нарушает ограничение первичного ключа и не продолжается с другими записями для вставки.Я бы подумал, что установка fast = FALSE облегчила бы эту проблему, но это не так.

Есть идеи, как обойти эту проблему?Я всегда мог drop таблица в начале первого сценария, но это выглядит довольно тяжело и, несомненно, приведет к проблемам в будущем.

1 Ответ

2 голосов
/ 12 ноября 2010

В этом случае все работает как положено. Вы загружаете все как пакет, и SQL Server останавливает пакет, как только обнаруживает ошибку. К сожалению, я не знаю изящного встроенного решения. Но я думаю, что можно создать систему в базе данных, чтобы справиться с этим более эффективно. Мне нравится делать хранение / управление данными в базах данных, а не в R, поэтому мое решение очень тяжело для баз данных. Другие могут предложить вам решение, более ориентированное на R.

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

CREATE TABLE tblTemp(
    modelid int
    , password varchar(50)
    , reason varchar(50)
    , duplicate int()
)
GO

Ваш запрос на размещение информации в этой таблице должен принимать «Нет» для столбца «Дубликат». Я использую шаблон, где 1 = Y & 5 = N. Вы также можете пометить только те, которые являются выбросами, но я предпочитаю быть явным с моей логикой.

Вам также понадобится место для сброса всех строк, которые нарушают PK в выбросах2.

CREATE TABLE tblDuplicates(
    modelid int
    , password varchar(50)
    , reason varchar(50)
)
GO

OK. Теперь все, что вам нужно сделать, это создать триггер, чтобы переместить новые строки из tblTemp в outliers2. Этот триггер переместит все дублирующиеся строки в tblDuplicates для последующей обработки, удаления, чего угодно.

CREATE TRIGGER FindDups
ON tblOutliersTemp
AFTER INSERT
AS 

Я не собираюсь проходить и писать весь триггер. У меня нет SQL Server 2005 для тестирования, и я, вероятно, сделал бы синтаксическую ошибку, и я не хочу давать вам плохой код, но вот что нужно сделать триггеру:

  1. Определите все строки в tblTemp, которые будут нарушать PK в выбросах2. Если найдены дубликаты, замените дубликаты на 1. Это можно сделать с помощью оператора UPDATE.
  2. Скопировать все строки, где duplicate = 1, в tblDuplicates. Вы бы сделали это с INSERT INTO tblDuplicates ......
  3. Теперь скопируйте неповторяющиеся строки в outliers2 с помощью оператора INSERT INTO, который выглядит почти так же, как тот, который использовался в шаге 2.
  4. Удалите все строки из tblTemp, чтобы очистить их для следующей партии обновлений. Этот шаг важен.

Приятной особенностью такого способа является то, что sqlSave () не выдаст ошибку только потому, что вы нарушили PK, и вы можете заняться матчами позже, например завтра. : -)

...