Тот же запрос дает разные результаты - PullRequest
0 голосов
/ 03 мая 2018

Я все еще новичок в работе с базами данных, поэтому, пожалуйста, наберитесь терпения. Я прочитал несколько похожих вопросов, но ни один из них, похоже, не говорит о той же проблеме, с которой я сталкиваюсь.

Немного информации о том, что я делаю, у меня есть таблица, заполненная контактной информацией, и некоторые контакты дублируются, но большинство дублированных строк имеют сокращенный номер телефона, что делает эти данные бесполезными.

Я написал следующий запрос для поиска дубликатов:

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.

Ответы [ 4 ]

0 голосов
/ 03 мая 2018

Я полагаю, что вы получаете разные результаты при каждом запуске, потому что (а) если явно не указано в запросе, вы ничего не можете предположить о порядке, в котором SQL возвращает данные в запросе, и (б) единственные критерии порядка вы предоставляете это по имени, которое гораздо менее точно, чем ваша группа (имя, фамилия, адрес электронной почты).

Что касается самого запроса, то, как написано, предполагается, что первый элемент, найденный в данном разделе, содержит действительный номер телефона. Без указания порядка вы не можете знать, что это будет правдой ... а что если все элементы в данной группе имеют недопустимые номера телефонов? Ниже приведен мой пример извлечения данных, которые вы ищете, в, надеюсь, полезном формате.

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

(Да, если нет индексов, поддерживающих это, вы закончите сканирование таблицы.)

0 голосов
/ 03 мая 2018

ORDER BY Firstname здесь недетерминировано, так как все они имеют одинаковое имя из раздела на

Если CID уникален, вы можете использовать его для заказа, но я подозреваю, что вы действительно хотите считать.

0 голосов
/ 03 мая 2018
SELECT Firstname, lastname,email, COUNT(*)
FROM [data.com_raw]
GROUP BY Firstname, lastname,email HAVING COUNT(*)>1
WHERE LEN(PHONE)<= 10
0 голосов
/ 03 мая 2018

Вместо 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...