Як знайти дублікати у кількох стовпцях?


98

Тому я хочу зробити щось на зразок цього коду sql нижче:

select s.id, s.name,s.city 
from stuff s
group by s.name having count(where city and name are identical) > 1

Щоб отримати наступне, (але ігнорувати, де збігається лише назва чи лише місто, воно має бути в обох стовпцях):

id      name  city   
904834  jim   London  
904835  jim   London  
90145   Fred  Paris   
90132   Fred  Paris
90133   Fred  Paris

Відповіді:


137

Дублюється idдля пар nameі city:

select s.id, t.* 
from [stuff] s
join (
    select name, city, count(*) as qty
    from [stuff]
    group by name, city
    having count(*) > 1
) t on s.name = t.name and s.city = t.city

Зверніть увагу, що якщо вони містять nameабо cityмістять null, то вони не будуть повідомлятися у зовнішньому запиті, але будуть відповідати у внутрішньому запиті.
Адам Паркін

3
Якщо тоді ці значення можуть містити null(якщо я чогось не пропускаю), вам потрібно змінити його на CROSS JOIN(повний декартовий продукт), а потім додати такий WHEREпункт, як:WHERE ((s.name = t.name) OR (s.name is null and t.name is null)) AND ((s.city = t.city) OR (s.city is null and t.city is null))
Адам Паркін


10

Щось подібне зробить свою справу. Не знаєте про продуктивність, тому зробіть кілька тестів.

select
  id, name, city
from
  [stuff] s
where
1 < (select count(*) from [stuff] i where i.city = s.city and i.name = s.name)

6

Використання count(*) over(partition by...)надає прості та ефективні засоби для виявлення небажаного повторення, а також перераховує всі зазначені рядки та всі потрібні стовпці:

SELECT
    t.*
FROM (
    SELECT
        s.*
      , COUNT(*) OVER (PARTITION BY s.name, s.city) AS qty
    FROM stuff s
    ) t
WHERE t.qty > 1
ORDER BY t.name, t.city

Хоча найновіші версії СУБД підтримують count(*) over(partition by...) MySQL V 8.0, представлені "віконні функції", як показано нижче (у MySQL 8.0)

CREATE TABLE stuff(
   id   INTEGER  NOT NULL
  ,name VARCHAR(60) NOT NULL
  ,city VARCHAR(60) NOT NULL
);
INSERT INTO stuff(id,name,city) VALUES 
  (904834,'jim','London')
, (904835,'jim','London')
, (90145,'Fred','Paris')
, (90132,'Fred','Paris')
, (90133,'Fred','Paris')

, (923457,'Barney','New York') # not expected in result
;
SELECT
    t.*
FROM (
    SELECT
        s.*
      , COUNT(*) OVER (PARTITION BY s.name, s.city) AS qty
    FROM stuff s
    ) t
WHERE t.qty > 1
ORDER BY t.name, t.city
    ідентифікатор | назва | місто | кількість
-----: | : --- | : ----- | -:
 90145 | Фред | Париж | 3
 90132 | Фред | Париж | 3
 90133 | Фред | Париж | 3
904834 | джим | Лондон | 2
904835 | джим | Лондон | 2

db <> скрипка тут

Функції вікна. MySQL тепер підтримує віконні функції, які для кожного рядка із запиту виконують обчислення, використовуючи рядки, пов'язані з цим рядком. До них належать такі функції, як RANK (), LAG () та NTILE (). Крім того, декілька існуючих функцій сукупності зараз можуть використовуватися як функції вікон; наприклад, SUM () і AVG (). Для отримання додаткової інформації див. Розділ 12.21, “Віконні функції” .


3

Трохи пізно з грою на цій посаді, але я знайшов цей спосіб досить гнучким / ефективним

select 
    s1.id
    ,s1.name
    ,s1.city 
from 
    stuff s1
    ,stuff s2
Where
    s1.id <> s2.id
    and s1.name = s2.name
    and s1.city = s2.city

2

Ви повинні самостійно приєднатись до речей та відповідати імені та місту. Потім групуйте за підрахунком.

select 
   s.id, s.name, s.city 
from stuff s join stuff p ON (
   s.name = p.city OR s.city = p.name
)
group by s.name having count(s.name) > 1

Помилки в SQL Server: усі
неагреговані

0

Враховуючи проміжну таблицю з 70 стовпцями та лише 4, що представляють дублікати, цей код поверне порушувальні стовпці:

SELECT 
    COUNT(*)
    ,LTRIM(RTRIM(S.TransactionDate)) 
    ,LTRIM(RTRIM(S.TransactionTime))
    ,LTRIM(RTRIM(S.TransactionTicketNumber)) 
    ,LTRIM(RTRIM(GrossCost)) 
FROM Staging.dbo.Stage S
GROUP BY 
    LTRIM(RTRIM(S.TransactionDate)) 
    ,LTRIM(RTRIM(S.TransactionTime))
    ,LTRIM(RTRIM(S.TransactionTicketNumber)) 
    ,LTRIM(RTRIM(GrossCost)) 
HAVING COUNT(*) > 1

.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.