RODBC sqlSave() останавливает запрос insert при нарушении PK

StackOverflow https://stackoverflow.com/questions/4157961

  •  08-10-2019
  •  | 
  •  

Вопрос

Я разработал онлайн-опрос, который хранит мои данные в базе данных 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 .Один и тот же респондент может быть выбросом для нескольких проверок, но я не хочу вставлять одну и ту же комбинацию 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 таблица в начале первого сценария, но это кажется довольно трудным делом и, несомненно, приведет к проблемам в будущем.

Это было полезно?

Решение

В этом случае все работает так, как ожидалось.Вы загружаете все в пакетном режиме, и 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 в outliers2.

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

ОК.Теперь все, что вам нужно сделать, это создать триггер для перемещения новых строк из 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 В tblDuplicates ......
  3. Теперь скопируйте неповторяющиеся строки в outliers2 с помощью инструкции INSERT INTO, которая выглядит почти точно так же, как та, что использовалась на шаге 2.
  4. УДАЛИТЕ все строки из tblTemp, чтобы очистить их для следующего пакета обновлений.Этот шаг очень важен.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top