奇怪的删除查询,是否写得正确?

时间:2011-07-07 14:11:45

标签: sql sql-server sql-server-2005

我们最近遇到了一些问题,其中从表中删除重复条目的sql脚本不会使用最新的条目作为要保留的条目。我认为这一行是问题

delete from vaccine_patient_details 
where vacc_pat_guid <> 
    (Select top 1 vacc_pat_guid 
     from vaccine_patient_details as v 
     where v.patient_guid = patient_guid and 
           v.vaccine_guid = vaccine_guid 
     order by date_given desc)

这是正确的语法吗?我发现另一个版本的脚本在另一个表上工作。 (名称已更改为与第一个示例匹配)

delete from vaccine_patient_details 
where vacc_pat_guid <> 
    (Select top 1 vacc_pat_guid 
     from vaccine_patient_details as v 
     where v.patient_guid = vaccine_patient_details.patient_guid and 
           v.vaccine_guid = vaccine_patient_details.vaccine_guid 
     order by date_given desc)

这个使用内部where子句中已删除表的表名,是否会导致我的第一个版本出现问题?

有关表的详细信息:

  1. 任何以guid结尾的列都是 uniqueidentifier的数据类型
  2. vacc_pat_guid是主键,是唯一的。
  3. date_given是一个可以为null的日期时间。如果有一个副本,其中一个为null且一个不为null,则应该更喜欢not null。

5 个答案:

答案 0 :(得分:3)

第一个表上没有任何别名,查询等同于:

delete from vaccine_patient_details 
where vacc_pat_guid <> 
    (Select top 1 vacc_pat_guid 
     from vaccine_patient_details as v 
     where v.patient_guid = v.patient_guid and 
           v.vaccine_guid = v.vaccine_guid 
     order by date_given desc)

一个好的将是

delete v1 from vaccine_patient_details as v1
where v1.vacc_pat_guid <> 
    (Select top 1 v.vacc_pat_guid 
     from vaccine_patient_details as v 
     where v.patient_guid = v1.patient_guid and 
           v.vaccine_guid = v1.vaccine_guid 
     order by v.date_given desc)

通过在您向我们展示的第二个查询中指定表名,优化器明白他必须加入第一个表,因为seconde表名为'v',第一个是'vaccine_patient_details',并且他不要混淆。

他在第一个中感到困惑,因为他不知道patient_guid是第一个表格还是第二个表格中的字段。所以它越接近,所以第二个。

编辑:

来自http://dev.mysql.com/doc/refman/5.0/en/delete.html

  

如果声明表的别名,   你在引用时必须使用别名   到桌子:

     

DELETE t1 FROM test AS t1, test2 WHERE   ...

答案 1 :(得分:1)

您的代码的相关部分(如您所述)此...

 where v.patient_guid = patient_guid and 
       v.vaccine_guid = vaccine_guid

等于运算符的右侧没有指定表。优化器将首先检查最本地范围的匹配表。在这种情况下,子查询中的表具有那些字段,优化后甚至不检查外部查询中的表。

代码的第二个版本明确指出要引用哪个表,这恰好是外部查询中的表。

所以,简而言之,是的;问题是第一个版本隐式引用了内部查询的表实例,它应该显式引用外部查询的表实例。

注意:我不同意这种自我加入是一个问题。

答案 2 :(得分:1)

delete a from vaccine_patient_details a, vaccine_patient_details b
where a.patient_guid = b.patient_guid
   and a.vaccine_guid = b.vaccine_guid
   and a.date_given < b.date_given

答案 3 :(得分:0)

加入同一张表是否合法,这不是一个好主意。您最好将您认为应该删除的记录的ID提取到一个单独的表中(然后您可以验证它们是否正确),并使用它们来运行删除。

我认为尝试根据这样的复杂查询进行删除会在某些时候遇到麻烦。

答案 4 :(得分:0)

尝试一下(当然在你的开发环境中)

delete vaccine_patient_details 
  from vaccine_patient_details V
 where vacc_pat_guid <> 
    (Select top 1 vacc_pat_guid 
       from vaccine_patient_details 
      where V.patient_guid = patient_guid and 
            V.vaccine_guid = vaccine_guid 
      order by date_given desc)