【问题标题】:Strange delete query, is it written correctly?奇怪的删除查询,写对了吗?
【发布时间】:2011-07-07 14:11:44
【问题描述】:

我们最近遇到了一些问题,即从表中删除重复条目的 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 是一个可以为空的日期时间。如果存在一个为空且一个不为空的重复项,则应该首选非空的一个。

【问题讨论】:

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


    【解决方案1】:

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

    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)
    

    通过在您向我们展示的第二个查询中指定表名,优化器了解他必须与第一个表连接,因为第二个表名为“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 ...

    【讨论】:

    • 您不能在删除语句中使用别名。它给出了错误Msg 102, Level 15, State 1, Line 1 Incorrect syntax near 'v1'.
    • 但是我认为你在第一部分是对的,它是在与错误的表格进行比较。我只是一个可以给予确认而不是“我认为”的人。
    • Msg 156, Level 15, State 1, Line 1 Incorrect syntax near the keyword 'as'.
    • 在 SQL Server 中应该是delete v1 from vaccine_patient_details as v1
    【解决方案2】:

    您的代码的相关部分是(如您所述)这个...

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

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

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

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

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

    【讨论】:

      【解决方案3】:
      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
      

      【讨论】:

        【解决方案4】:

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

        我认为尝试基于这样的复杂查询进行删除有时会带来麻烦。

        【讨论】:

        • +1 用于提取 id。 Scott,您可能希望使用这些来审核删除,以防删除的行不是真正重复的。
        • 您能否提供一个示例,说明如何获取最新记录并将其提取到临时表中(我知道如何进行提取部分,但我在使用正确的选择语句时遇到了一点问题)
        【解决方案5】:

        试试这个(当然是在你的开发环境中)

        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)
        

        【讨论】:

          猜你喜欢
          • 2010-10-15
          • 1970-01-01
          • 2019-03-18
          • 1970-01-01
          • 1970-01-01
          • 2019-08-10
          • 2017-11-20
          • 1970-01-01
          相关资源
          最近更新 更多