当PK违反时,RODBC sqlSave()停止插入查询

时间:2010-11-11 18:32:30

标签: sql-server-2005 r rodbc

我开发了一项在线调查,将我的数据存储在Microsoft SQL 2005数据库中。我已经在R中对我的数据写了一组离群值检查。这些脚本的一般工作流程是:

  1. 使用sqlQuery()
  2. 从SQL数据库中读取数据
  3. 执行离群值分析
  4. 使用sqlSave()
  5. 将违规的受访者写回单独的表中的数据库

    我写回的表格有以下结构:

    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表,但这看起来非常沉重,无疑会导致问题。

1 个答案:

答案 0 :(得分:2)

在这种情况下,一切都按预期工作。您将所有内容作为批处理上载,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

行。现在您需要做的就是创建一个触发器,将新行从tblTemp移动到outliers2。此触发器将所有重复的行移动到tblDuplicates,以便以后处理,删除等等。

CREATE TRIGGER FindDups
ON tblOutliersTemp
AFTER INSERT
AS 

我不打算通过编写整个触发器。我没有SQL Server 2005来测试它,我可能会出现语法错误,我不想给你错误的代码,但这是触发器需要做的事情:

  1. 识别tblTemp中违反异常值2中PK的所有行。如果找到重复项,请将重复项更改为1.这将使用UPDATE语句完成。
  2. 将duplicate = 1的所有行复制到tblDuplicates。你可以通过INSERT INTO tblDuplicates ......
  3. 来做到这一点
  4. 现在使用INSERT INTO语句将非重复行复制到outliers2,该语句看起来几乎与步骤2中使用的语句完全相同。
  5. 从tblTemp中删除所有行,以清除它以进行下一批更新。这一步很重要。
  6. 关于这样做的好处是sqlSave()不会因为你违反PK而错误,你可以在以后处理比赛,比如明天。 : - )