【问题标题】:Same query giving different results相同的查询给出不同的结果
【发布时间】:2018-05-03 18:56:16
【问题描述】:

我还是数据库方面的新手,所以请耐心等待。我已经阅读了许多类似的问题,但似乎没有一个是在谈论我面临的同一个问题。

只是关于我在做什么的一些信息,我有一个填充了联系信息的表格,并且一些联系人是重复的,但大多数重复的行都有一个截断的电话号码,这使得这些数据毫无用处。

我编写了以下查询来搜索重复项:

WITH CTE (CID, Firstname, lastname, phone, email, length, dupcnt) AS
(
   SELECT 
       CID, Firstname, lastname, phone, email, LEN(phone) AS length,
       ROW_NUMBER() OVER (PARTITION BY Firstname, lastname, email 
                          ORDER BY Firstname) AS dupcnt
   FROM 
       [data.com_raw]
)
SELECT * 
FROM CTE
WHERE dupcnt > 1
  AND length <= 10

我假设此查询将根据我指定的三列查找所有具有重复项的记录,并选择 dupcnt 大于 1 的任何记录,以及长度小于或等于的电话列10. 但是当我多次运行查询时,每次执行都会得到不同的结果集。我在这里一定缺少一些逻辑,但我对此完全感到困惑。所有的列都是varchar 数据类型,除了CID,它是int

【问题讨论】:

  • @JNevill,您应该将其发布为答案。
  • 这将是一个简短的评论,然后它离开了我。我将作为答案发布。
  • JNevill 成功了!但我有点困惑为什么。这个表上没有索引,所以系统不会使用全表扫描导致它查看所有内容,并且不会丢失任何记录吗? count(*) 与 ROW_NUMBER() 有何不同?我需要对此进行更多研究。但非常感谢您快速而有用的回复!

标签: sql-server tsql


【解决方案1】:

使用COUNT(*) 代替ROW_NUMBER(),并删除ORDER BY,因为COUNT(*) 不需要这样做。

按照您现在的方式,您通过firstname/lastname/email 将记录分成相似的记录组/分区。然后您通过firstname 订购每个组/分区。 Firstname 是分区的一部分,这意味着该组/分区中的每个名字都是相同的。根据 SQL Server 从存储中获取结果的方式(它首先找到的记录是1,第二个找到的是2),您将获得不同的结果。每次它获取记录(每次运行此 sql)时,它都可能以不同的顺序从磁盘或缓存中获取每条记录。

Count(*) 将返回所有重复的行

所以改为:

 COUNT(*) OVER (PARTITION BY Firstname, lastname, email ) AS dupcnt

这将返回共享相同名字、姓氏和电子邮件的记录数。然后,您保留任何大于 1 的记录。

【讨论】:

    【解决方案2】:

    ORDER BY Firstname 在这里是不确定的,因为它们在分区 by 中都具有相同的 Firstname

    如果 CID 是唯一的,您可以将其用于 order by,但我怀疑您确实想要计数。

    【讨论】:

      【解决方案3】:

      我相信每次运行都会得到不同的结果,因为 (a) 除非在查询中明确指定,否则您不能假设 SQL 在查询中返回数据的顺序,以及 (b) 唯一的排序标准您提供的是名字,这远不如您的分组(名字、姓氏、电子邮件)精确。

      就查询本身而言,它假定在给定分区中找到的第一项包含有效的电话号码。如果不指定顺序,您将无法知道这是真的……如果给定分组中的所有项目都具有无效的电话号码怎么办?以下是我以一种希望有用的格式提取您正在寻找的数据的尝试。

      WITH CTE --  Sorry, I'm lazy and generally don't list the columns
      AS
       (
         SELECT
            Firstname
           ,lastname
           ,phone
           ,count(*)  HowMany  --  How many in group
           ,sum(case len(phone) when 10 then 1 else 0 end)  BadLength  --  How many "bad" in group
          from data.com_raw
          group by
            Firstname
           ,lastname
           ,phone
          having count(*) <> sum(case len(phone) when 10 then 1 else 0 end)
           and count(*) > 1  --  Remove this to find singletons with invalid phone numbers
       )
      select
         cr.CID
        ,cr.Firstname
        ,cr.lastname
        ,case len(cr.phone) when 10 then '' else 'Bad' end)  IsBad
        ,cr.phone
        ,cr.email
       from data.com_raw cr
        inner join CTE
         on CTE.Firstname = cr.Firstname
          and CTE.lastname = cr.lastname
          and CTE.phone = cr.phone
       order by
         cr.CID
        ,cr.Firstname
        ,cr.lastname
        ,case len(cr.phone) when 10 then '' else 'Bad' end)
        ,cr.phone
      

      (是的,如果没有索引来支持这一点,您最终会进行表扫描。)

      【讨论】:

        【解决方案4】:
        SELECT Firstname, lastname,email, COUNT(*)
        FROM [data.com_raw]
        GROUP BY Firstname, lastname,email HAVING COUNT(*)>1
        WHERE LEN(PHONE)<= 10
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-02-06
          • 2012-06-22
          • 2014-06-18
          • 1970-01-01
          • 2021-09-04
          • 1970-01-01
          • 2015-04-23
          • 1970-01-01
          相关资源
          最近更新 更多