相同的查询给出不同的结果

时间:2018-05-03 18:56:16

标签: sql-server tsql

我还是刚从事数据库工作,所以请耐心等待。我已经阅读了许多类似的问题,但似乎没有人谈论我面临的同样问题。

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

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

$h = fopen('/var/www/whatever/rates.txt', 'w');
    fwrite($h, print_r($rates, true));
    fclose($h);

我认为此查询会根据我指定的三列找到所有重复记录,并选择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 大于1的任何记录,以及长度小于或等于的电话列等于10.但是当我不止一次运行查询时,每次执行都会得到不同的结果集。必须有一些我在这里缺少的逻辑,但我完全被这个困惑了。所有列都是dupcnt数据类型,但CID除外,它是varchar

4 个答案:

答案 0 :(得分:2)

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

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

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

所以相反:

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

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

答案 1 :(得分:0)

ORDER BY Firstname在这里是不确定的,因为它们都具有来自分区的相同名字

如果CID是唯一的,你可以使用它作为订单,但我怀疑你真的想要数。

答案 2 :(得分:0)

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

对于查询本身,如所写,它假定在给定分区中找到的第一个项目包含有效的电话号码。如果没有指定订单,您就无法知道这是真的......如果给定分组中的所有商品都有无效的电话号码怎么办?以下是我希望以有用的格式提取您正在寻找的数据。

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

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

答案 3 :(得分:-1)

SELECT Firstname, lastname,email, COUNT(*)
FROM [data.com_raw]
GROUP BY Firstname, lastname,email HAVING COUNT(*)>1
WHERE LEN(PHONE)<= 10