【问题标题】:RODBC sqlSave() stopping insert query when PK violatedRODBC sqlSave() 在违反 PK 时停止插入查询
【发布时间】:2010-11-12 22:18:18
【问题描述】:

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

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

我要回信的表具有以下结构:

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

如您所见,我已将主键设置为 modelid 和 reason。同一受访者可能是多次检查的异常值,但我不想为任何受访者插入相同的模型 ID 和原因组合。

由于我们仍在收集数据,因此我希望能够在开发基于数据估计的模型时每天/每周更新这些脚本。这是我正在使用的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-2005 r rodbc


    【解决方案1】:

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

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

    好的。现在您需要做的就是创建一个触发器以将新行从 tblTemp 移动到异常值2。此触发器会将所有重复的行移动到 tblDuplicates 以供以后处理、删除等。

    CREATE TRIGGER FindDups
    ON tblOutliersTemp
    AFTER INSERT
    AS 
    

    我不会写整个触发器。我没有 SQL Server 2005 来测试它,我可能会犯语法错误,我不想给你糟糕的代码,但这是触发器需要做的:

    1. 确定 tblTemp 中所有违反离群值 2 中 PK 的行。如果发现重复项,请将重复项更改为 1。这将通过 UPDATE 语句完成。
    2. 将重复=1 的所有行复制到 tblDuplicates。您可以使用 INSERT INTO tblDuplicates ......
    3. 现在使用与步骤 2 中使用的几乎完全相同的 INSERT INTO 语句将非重复行复制到异常值 2。
    4. 删除 tblTemp 中的所有行,以便为您的下一批更新清除它。这一步很重要。

    这样做的好处是 sqlSave() 不会因为你违反了你的 PK 而出错,你可以在以后处理比赛,比如明天。 :-)

    【讨论】:

    • 感谢您的提示。我最终使用了一些不同的方法(我将在上面详细说明),但这让我朝着正确的方向思考。我没有想到的一件事是,如果我通过管理工作室运行设置插入查询(比如其中 10 个)并且第 6 个违反了 PK,SQL Server 会对该语句感到愤怒,但随后继续正常进行语句 7 - 10。这不是 R 与 SQL 交互时的行为。
    • 我相信这是由 ODBC 连接引起的,它会序列化更新。直接接口的行为会有所不同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-18
    • 2014-07-17
    • 1970-01-01
    • 1970-01-01
    • 2019-01-27
    相关资源
    最近更新 更多