Frage

Diese Abfrage eine Liste in Frage kommender Duplikate für die Erstellung ist einfach genug:

SELECT Count(*), Can_FName, Can_HPhone, Can_EMail
FROM Can 
GROUP BY Can_FName, Can_HPhone, Can_EMail
HAVING Count(*) > 1

Aber wenn die tatsächliche Regel, die ich gegen überprüfen möge FName und (HPhone ODER E-Mail) ist - wie kann ich die GROUP BY einstellen damit arbeiten

Ich bin ziemlich sicher, ich werde mit einem UNION am Ende SELECT hier (dh tun FName, HPhone auf der einen und FName, EMail auf der anderen Seite und die Ergebnisse zusammenführen) - aber ich würde gerne wissen, ob jemand kennt einen einfacheren Weg, es zu tun.

Vielen Dank im Voraus für jede Hilfe.

Scott in Maine

War es hilfreich?

Lösung

Keine dieser Antworten ist richtig. Quassnoi der ist ein anständiger Ansatz, aber Sie werden in der Ausdrücken „qo.id> dup.id“ und „di.chainid

Das wesentliche Problem ist ein disjunctive Zustand mit einer Gruppierung, die auf die Möglichkeit, zwei Aufzeichnungen führt über einen Zwischen bezogen ist, obwohl sie nicht direkt zuordenbar.

.

z erklärten Sie, diese Aufzeichnungen sollten alle gruppiert werden:

(1) John 555-00-00 john@example.com

(2) John 555-00-01 john@example.com

(3) John 555-00-01 john-other@example.com

Sie sehen, dass # 1 und # 2 zuordenbar sind, als # 2 und # 3, sind aber eindeutig # 1 und # 3 sind nicht direkt zuordenbar als Gruppe.

Dies legt fest, dass eine rekursive oder iterative Lösung die einzig mögliche Lösung ist.

Also, Rekursion ist nicht praktikabel, da Sie leicht in einer Looping-Situation enden können. Dies ist, was Quassnoi versucht, mit seiner ID Vergleichen zu vermeiden, aber er brach so den Algorithmus zu tun. Sie könnten versuchen, die Ebenen der Rekursion zu begrenzen, aber Sie können dann nicht alle Beziehungen vervollständigen, und Sie werden Schleifen noch potenziell auf sich selbst werden folgende zurück, um zu hohe Datengröße und unerschwinglich Ineffizienz führt.

Die beste Lösung ist ITERATIVE: Starten Sie ein Ergebnis gesetzt, indem jede ID als eindeutige Gruppen-ID-Tagging, und dann drehen durch das Ergebnis eingestellt und aktualisieren Sie es, IDs in die gleiche einzigartige Gruppe kombiniert ID, wie sie auf dem disjunktiven Zustand entsprechen. Wiederholen Sie den Vorgang auf dem aktualisierten Satz jedes Mal, bis keine weiteren Aktualisierungen vorgenommen werden.

Ich werde Beispielcode für diese erstellen bald.

Andere Tipps

Bevor ich etwas raten kann, muss ich die Antwort auf diese Frage wissen:

name  phone      email

John  555-00-00  john@example.com
John  555-00-01  john@example.com
John  555-00-01  john-other@example.com

Was COUNT(*) Sie für diese Daten wollen?

Update:

Wenn Sie nur wissen wollen, dass ein Datensatz hat alle Duplikate, verwenden Sie diese:

WITH    q AS (
        SELECT  1 AS id, 'John' AS name, '555-00-00' AS phone, 'john@example.com' AS email
        UNION ALL
        SELECT  2 AS id, 'John', '555-00-01', 'john@example.com'
        UNION ALL
        SELECT  3 AS id, 'John', '555-00-01', 'john-other@example.com'
        UNION ALL
        SELECT  4 AS id, 'James', '555-00-00', 'james@example.com'
        UNION ALL
        SELECT  5 AS id, 'James', '555-00-01', 'james-other@example.com'
        )
SELECT  *
FROM    q qo
WHERE   EXISTS
        (
        SELECT  NULL
        FROM    q qi
        WHERE   qi.id <> qo.id
                AND qi.name = qo.name
                AND (qi.phone = qo.phone OR qi.email = qo.email)
        )

Es ist effizienter, aber nicht sagen, wo die doppelte Kette gestartet.

Diese Abfrage wählen Sie alle Einträge zusammen mit dem Spezialgebiet, chainid, dass die doppelte Kette gestartet zeigt an, wo.

WITH    q AS (
        SELECT  1 AS id, 'John' AS name, '555-00-00' AS phone, 'john@example.com' AS email
        UNION ALL
        SELECT  2 AS id, 'John', '555-00-01', 'john@example.com'
        UNION ALL
        SELECT  3 AS id, 'John', '555-00-01', 'john-other@example.com'
        UNION ALL
        SELECT  4 AS id, 'James', '555-00-00', 'james@example.com'
        UNION ALL
        SELECT  5 AS id, 'James', '555-00-01', 'james-other@example.com'
        ),
        dup AS (
        SELECT  id AS chainid, id, name, phone, email, 1 as d
        FROM    q
        UNION ALL
        SELECT  chainid, qo.id, qo.name, qo.phone, qo.email, d + 1
        FROM    dup
        JOIN    q qo
        ON      qo.name = dup.name
                AND (qo.phone = dup.phone OR qo.email = dup.email)
                AND qo.id > dup.id
        ),
        chains AS 
        (
        SELECT  *
        FROM    dup do
        WHERE   chainid NOT IN
                (
                SELECT  id
                FROM    dup di
                WHERE   di.chainid < do.chainid
                )
        )
SELECT  *
FROM    chains
ORDER BY
        chainid

GROUP BY nicht unterstützt oder - es ist implizit AND und muß jede nicht-Aggregator in der Auswahlliste enthält

.

Ich nehme an, Sie auch eine eindeutige ID integer als Primärschlüssel für diese Tabelle haben. Wenn Sie dies nicht tun, ist es eine gute Idee, einen zu haben, für diesen Zweck und viele andere.

Finden diese Duplikate durch eine Selbstverknüpfung:

select
  c1.ID 
, c1.Can_FName
, c1.Can_HPhone
, c1.Can_Email
, c2.ID 
, c2.Can_FName
, c2.Can_HPhone
, c2.Can_Email
from
(
  select 
      min(ID), 
      Can_FName, 
      Can_HPhone, 
      Can_Email 
  from Can 
  group by 
      Can_FName, 
      Can_HPhone, 
      Can_Email
) c1
inner join Can c2 on c1.ID < c2.ID 
where
    c1.Can_FName = c2.Can_FName 
and (c1.Can_HPhone = c2.Can_HPhone OR c1.Can_Email = c2.Can_Email)
order by
  c1.ID

Die Abfrage gibt Ihnen N-1 Zeilen für jede N doppelter Kombinationen - wenn Sie nur eine Zählung wollen zusammen mit jeder einzigartigen Kombination, zählt die Zeilen von der „linken“ Seite gruppiert:

select count(1) + 1,
, c1.Can_FName
, c1.Can_HPhone
, c1.Can_Email
from 
(
  select 
      min(ID), 
      Can_FName, 
      Can_HPhone, 
      Can_Email 
  from Can 
  group by 
      Can_FName, 
      Can_HPhone, 
      Can_Email
) c1
inner join Can c2 on c1.ID < c2.ID 
where
    c1.Can_FName = c2.Can_FName 
and (c1.Can_HPhone = c2.Can_HPhone OR c1.Can_Email = c2.Can_Email)
group by 
  c1.Can_FName
, c1.Can_HPhone
, c1.Can_Email

Zugegeben, das ist komplizierter als ein Union -. Aber ich denke, es ist eine gute Art und Weise veranschaulicht über Duplikate des Denkens

Projekt der gewünschte Transformation zuerst aus einer Tabelle abgeleitet, haben dann die Aggregation:

SELECT COUNT(*) 
    , CAN_FName
    , Can_HPhoneOrEMail
    FROM (
        SELECT Can_FName 
            , ISNULL(Can_HPhone,'') +  ISNULL(Can_EMail,'')  AS Can_HPhoneOrEMail
        FROM Can) AS Can_Transformed
    GROUP BY Can_FName, Can_HPhoneOrEMail
    HAVING Count(*) > 1

Stellen Sie Ihre ‚ODER‘ Operation wie in der abgeleiteten Tabelle Projekt-Liste benötigt wird.

Ich weiß, diese Antwort wird für die Verwendung der temporären Tabelle kritisiert werden, aber es wird funktionieren trotzdem:

-- create temp table to give the table a unique key
create table #tmp(
ID int identity,
can_Fname varchar(200) null, -- real type and len here
can_HPhone varchar(200) null, -- real type and len here
can_Email varchar(200) null, -- real type and len here
)

-- just copy the rows where a duplicate fname exits 
-- (better performance specially for a big table)
insert into #tmp 
select can_fname,can_hphone,can_email
from Can 
where can_fname exists in (select can_fname from Can 
group by can_fname having count(*)>1)

-- select the rows that have the same fname and 
-- at least the same phone or email
select can_Fname, can_Hphone, can_Email  
from #tmp a where exists
(select * from #tmp b where
a.ID<>b.ID and A.can_fname = b.can_fname
and (isnull(a.can_HPhone,'')=isnull(b.can_HPhone,'')
or  (isnull(a.can_email,'')=isnull(b.can_email,'') )

Versuchen Sie folgendes:

SELECT Can_FName, COUNT(*)
FROM (
SELECT 
rank() over(partition by Can_FName order by  Can_FName,Can_HPhone) rnk_p,
rank() over(partition by Can_FName order by  Can_FName,Can_EMail) rnk_m,
Can_FName
FROM Can
) X
WHERE rnk_p=1 or rnk_m =1
GROUP BY Can_FName
HAVING COUNT(*)>1
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top