【问题标题】:SQL NOT IN() not working, returning data it shouldn'tSQL NOT IN() 不工作,返回不应该的数据
【发布时间】:2021-02-03 19:24:06
【问题描述】:

下面的存储过程不应该尝试插入任何记录,如果它们存在于我的临时表“r”或我试图将它们插入“记录”的实际表中。

我收到主键约束错误,因为 NOT IN 函数仍在尝试插入已经在记录表中的记录。

有人可以看看我下面的代码并告诉我这是否是正确的方法吗?

    INSERT INTO [RxEvidence].[Record] ([RecordID], [Source], [Notes], [ReceivedFrom], [ReceivedDate], [CompleteDate])
    SELECT r.[RecordID], r.[Source], r.[Notes], r.[ReceivedFrom], r.[ReceivedDate], r.[CompleteDate]
    FROM @Records r WHERE r.RecordID NOT IN (SELECT RecordId FROM RxEvidence.Record)
    GROUP BY r.[RecordID], r.[Source], r.[Notes], r.[ReceivedFrom], r.[ReceivedDate], r.[CompleteDate];

【问题讨论】:

  • 样本数据和期望的结果真的很有帮助。
  • 这是 EXCEPT 可能无需分组就能为您做的事情(假设行可以或应该在所有列上匹配,而不仅仅是 ID)。
  • 抱歉,这是生产数据,我不确定要包含哪些样本。 @Records 包含 RxEvidence.Record 表中已经存在的 RecordID,因此它不应该尝试将它添加到给定“NOT IN”的表中,但它仍然会,这会导致主键约束错误。我想我只是希望有人能根据该信息发现这是否写错了。
  • 为什么最后有 GROUP BY?
  • 这句话一点都不复杂,所以我必须相信主键异常是正确的。所以我猜主键是一个复合键,因为 RecordID 来自外部源。只是猜测,但如果主键是 {RecordId, Source}

标签: sql tsql select ssms sql-insert


【解决方案1】:

你可以试试这样的

INSERT INTO RxEvidence.Record (RecordID, [Source], Notes, ReceivedFrom, ReceivedDate, CompleteDate)
SELECT r.RecordID, r.[Source], r.Notes, r.ReceivedFrom, r.ReceivedDate, r.CompleteDate
FROM @Records r 
WHERE not exists (select 1 
                  from RxEvidence.Record rr
                  where r.RecordID=rr.RecordId);

【讨论】:

    【解决方案2】:

    @Records 和 RxEvidence.Record 似乎都有一个 RecordId 列,因此要消除任何错误的可能性,可以尝试使用表别名( "x" 在下面的示例中)在此处的 SELECT 语句中:

    FROM @Records r WHERE r.RecordID NOT IN (SELECT x.RecordId FROM RxEvidence.Record x)
    

    这可能不是问题,但至少不应该受到伤害。 RxEvidence.Record 和 @Records 中 RecordId 列的数据类型是什么?它们是一样的吗? RxEvidence.Record 表上是否有插入触发器?

    【讨论】:

      【解决方案3】:

      考虑使用 NOT EXISTS 或连接而不是 NOT IN。当您处理 NULL 值时,NOT IN 无法按预期工作。

      考虑这个脚本

      set nocount on
      drop table if exists #src;
      drop table if exists #dest;
      
      select * into #src from (values (1),(2),(3),(4))x (col_src) 
      select * from #src 
          
      select * into #dest from (values (2),(4),(5))z(col_dest) where col_dest not in (select col_src from #src)
      select * from #dest
      

      结果如下(正确):

      col_src
      -----------
      1
      2
      3
      4
      
      col_dest
      -----------
      5
      

      现在,更改脚本以将 3 替换为 null

      set nocount on
      drop table if exists #src;
      drop table if exists #dest;
      
      select * into #src from (values (1),(2),(null),(4))x (col_src) 
      select * from #src 
      
      
      select * into #dest from (values (2),(4),(5))z(col_dest) where col_dest not in (select col_src from #src)
      select * from #dest
      

      结果不是你所期望的。

      col_src
      -----------
      1
      2
      NULL
      4
      
      col_dest
      -----------
      

      当 where 子句类似于“where null not in (select .....)”时,您会得到同样不想要的结果。

      要获得更好的解释(和更多细节),请阅读本章“处理可空性变化:NOT IN 与 NOT EXISTS” http://assets.red-gate.com/community/books/defensive-database-programming.pdf

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多