交叉应用和外部应用一起使用时违反 PRIMARY KEY 约束

Posted

技术标签:

【中文标题】交叉应用和外部应用一起使用时违反 PRIMARY KEY 约束【英文标题】:Violation of PRIMARY KEY constraint when using cross apply and outer apply together 【发布时间】:2017-08-15 19:10:07 【问题描述】:

我使用的是 Microsoft SQL Server。我想使用这两个函数来解析进入我的表的数据。所以我同时使用交叉应用和外部应用。

CROSS APPLY CA_Parse_CorpActnDtls_fn(MessageID) ent
outer apply CA_Parse_CorpActnOptnDtls_fn(ev.MessageID) cod

但是当我这样做时,它抱怨以下错误:

违反主键约束“PK_AfterParse_CA_Events”。无法在对象“dbo.AfterParse_CA_Events”中插入重复键。重复键值为 (105818432, 37819929)。 声明已终止。

整个 T-sql 代码如下:

insert into AfterParse_CA_Events (
           EventID
           ,MessageID
          ,cdtprFunction
          ,CreationDate
          ,MsgDefIdr
          ,EventType
          ,CFI
          ,EventProcessingType
          ,MndtryVlntryEvtTp
          ,RecordDate
          ,EffectiveDate
          ,DueBillRdmDate
          ,CUSIP
          ,LSCI_DateOfRecord
          ,RoundingDesc

        )

    SELECT  ent.EventID
            ,ent.MessageID
            ,ent.cdtprFunction
            ,ent.CreationDate
            ,ent.MsgDefIdr
            ,ent.EventType
            ,ent.CFI
            ,ent.EventProcessingType
            ,ent.MndtryVlntryEvtTp
            ,ent.RecordDate
            ,ent.EffectiveDate_Cmpny
            ,ent.DueBillRdmDate
            ,ent.CUSIP
            ,ROXSQL.dbo.GetNthTradeDay_fn(
            case when ent.EventProcessingType = 'DISN'
                then COALESCE (ent.ExDividendDate, ent.RecordDate)
                ELSE COALESCE(ent.EffectiveDate_Xchg, ent.EffectiveDate_Cmpny,cod.EarliestPaymentDate_Secu,cod.PaymentDate_Secu ,cod.PaymentDate_Cash)
            END,-1) AS LSCI_DateOfRecord
            ,cod.RoundingDesc


    FROM #EventsToDo ev 
    CROSS APPLY CA_Parse_CorpActnDtls_fn(MessageID) ent
    outer apply CA_Parse_CorpActnOptnDtls_fn(ev.MessageID) cod

你可以看到我需要第二个函数 CA_Parse_CorpActnOptnDtls_fn(ev.MessageID) 因为我想使用我的用户定义函数来编写 LSCI_DateOfRecord 数据。那么当我同时使用这两个功能时,有什么办法可以避免重复?

或者有什么方法可以分别从第二个函数 CA_Parse_CorpActnOptnDtls_fn(ev.MessageID) 为 LSCI_DateOfRecord 和 RoundingDesc 构建临时列表?然后我可以更新表格。

非常感谢任何帮助。

【问题讨论】:

你可以将它们插入到临时表中,删除重复的并插入到真实表中吗? 有几种方法可以解决这个问题。但它们都取决于你所说的重复是什么意思。它只是一个重复的键值还是整个行都被重复了?也许一个简单的分组就可以解决问题。也许是别的东西。 一些示例数据在这里会有很长的路要走,就像你拥有的那 2 个 UDF 的定义一样。这将有助于我们了解您定义为重复的内容。请告诉我们你得到了什么(作为一个选择语句)以及你希望看到什么 2 UDF 有点长。但他们正在从 XML 中读取数据。所以我的表的主键是 EventID。基本上他们正在做的是将公司行动事件详细数据解析到我的表中。 如果这些表值函数有点长,我担心它们不是内联表,而是可怕的多语句表值函数。它们的性能很糟糕……通常甚至比标量函数还要糟糕。但正如我之前所说,我们没有足够的信息来提供最佳解决方案。您是否尝试过简单地向您的选择查询添加一个 distinct? 【参考方案1】:

查看错误和您的 SQL 代码,并不是 APPLY 运算符本身导致了问题。事实上,一个或两个函数返回的 EvenID 和 MessageID 集合不止一行,这就是导致 PK 违规的原因。

下面是一个简化的演示,使用了一个字符串分割函数 (DelimitedSplit8K)

IF OBJECT_ID('tempdb..#EventsToDo ', 'U') IS NOT NULL 
DROP TABLE #EventsToDo ;
GO

CREATE TABLE #EventsToDo (
    EventID BIGINT NOT NULL,
    MessageID BIGINT NOT NULL,
    MessageText VARCHAR(1000) NOT NULL 
    );
GO

INSERT #EventsToDo (EventID, MessageID, MessageText) VALUES
    (105818432, 37819929, 'Part 1,Part 2,Part 3,Part 4,Part 5');
GO

-----------------------------------------------------------------

-- create the AfterParse_CA_Events table with PRIMARY KEY (EvenID, MessageID)...
IF OBJECT_ID('tempdb..#AfterParse_CA_Events', 'U') IS NOT NULL 
DROP TABLE #AfterParse_CA_Events;
GO

CREATE TABLE #AfterParse_CA_Events (
    EvenID BIGINT NOT NULL,
    MessageID BIGINT NOT NULL,
    MessagePart VARCHAR(1000) NULL 
    PRIMARY KEY (EvenID, MessageID)
    );
GO

--===============================================================

-- see what happens when we try to insert the parsed message values
-- into AfterParse_CA_Events while it has a PK of (EvenID, MessageID)...
INSERT #AfterParse_CA_Events (EvenID, MessageID, MessagePart)
SELECT 
    etd.EventID, 
    etd.MessageID, 
    dsk.Item
FROM
    #EventsToDo etd
    CROSS APPLY dbo.DelimitedSplit8K(etd.MessageText, ',') dsk;
GO

--===============================================================
-- execute the code below in a separate execution
--===============================================================

-- now, let's modify the  AfterParse_CA_Events table so that we have "MessagePartID" 
-- and make that part of the PK
IF OBJECT_ID('tempdb..#AfterParse_CA_Events', 'U') IS NOT NULL 
DROP TABLE #AfterParse_CA_Events;
GO 

CREATE TABLE #AfterParse_CA_Events (
    EvenID BIGINT NOT NULL,
    MessageID BIGINT NOT NULL,
    MessagePartID INT NOT NULL,
    MessagePart VARCHAR(1000) NOT NULL 
    PRIMARY KEY (EvenID, MessageID, MessagePartID)
    );
GO

--===============================================================

-- Now let's try the insertion again...
INSERT #AfterParse_CA_Events (EvenID, MessageID, MessagePartID, MessagePart)
SELECT 
    etd.EventID, 
    etd.MessageID, 
    dsk.ItemNumber,
    dsk.Item
FROM
    #EventsToDo etd
    CROSS APPLY dbo.DelimitedSplit8K(etd.MessageText, ',') dsk;
GO

--===============================================================

-- check the inserted values...
SELECT 
    *
FROM
    #AfterParse_CA_Events apce;

HTH,杰森

【讨论】:

以上是关于交叉应用和外部应用一起使用时违反 PRIMARY KEY 约束的主要内容,如果未能解决你的问题,请参考以下文章

使用实体框架添加记录时违反链接记录的PRIMARY KEY约束

数据导入时违反 PRIMARY KEY 约束错误

违反 PRIMARY KEY 约束。无法插入重复键

违反 PRIMARY KEY 约束“[Table_id]”。使用实体框架时无法在对象“[Table_id]”中插入重复键

MySQL中的交叉/外部应用

在扩展的 Asp.Net Identity 2 错误中将角色分配给用户违反 PRIMARY KEY 约束“PK_dbo.AspNetUserRoles”