RODBC sqlSave() останавливает запрос insert при нарушении PK
-
08-10-2019 - |
Вопрос
Я разработал онлайн-опрос, который хранит мои данные в базе данных Microsoft SQL 2005.Я написал набор дополнительных проверок своих данных в R.Общий рабочий процесс для этих сценариев таков:
- Считывание данных из базы данных SQL с помощью SqlQuery()
- Выполните анализ выбросов
- Запишите респондентов-нарушителей обратно в базу данных в отдельную таблицу с помощью 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, чтобы протестировать его, и я, вероятно, допустил бы синтаксическую ошибку, и я не хочу давать вам плохой код, но вот что должен сделать триггер:
- Определите все строки в tblTemp, которые нарушали бы PK в выбросах2.При обнаружении дубликатов измените их на 1.Это было бы сделано с помощью инструкции UPDATE.
- Скопируйте все строки, где duplicate=1, в tblDuplicates.Вы бы сделали это с помощью INSERT В tblDuplicates ......
- Теперь скопируйте неповторяющиеся строки в outliers2 с помощью инструкции INSERT INTO, которая выглядит почти точно так же, как та, что использовалась на шаге 2.
- УДАЛИТЕ все строки из tblTemp, чтобы очистить их для следующего пакета обновлений.Этот шаг очень важен.
Самое приятное в том, что sqlSave() не выдает ошибку только потому, что у вас нарушен ваш PK, и вы можете разобраться с совпадениями позже, например, завтра.:-)