2017-12-18 16 views
1

Dies ist der Suchdatensatz:Wie finden Sie fast ähnliche Datensätze in SQL?

A = { 
    field1: value1, 
    field2: value2, 
    ... 
    fieldN: valueN 
} 

ich in der Datenbank viele solcher Datensätze.

Der andere Datensatz (B) entspricht fast dem Datensatz A, wenn die N-M-Felder in diesen Datensätzen gleich sind. Dies ist das Beispiel, M = 2:

B = { 
    field1: OTHER_value1, 
    field2: OTHER_value2, 
    field3: value3, 
    ... 
    fieldN: valueN 
} 

Wenn Felder sein können, nicht nur die erste.

Ich kann die sehr große kombinatorische SQL-Abfrage machen, aber vielleicht gibt es eine schönere Lösung.

S.S .: Meine Datenbank ist PostgreSQL.

+1

Zwei Fragen: 1. Haben Sie die Kontrolle über die Datenstruktur? und 2. Gibt es eine Bedeutung in der Reihenfolge der Feldwerte in einem Datensatz? – Nick

+0

Was ist der Datentyp der Werte? – Nick

+0

1. Ja, das sind meine Daten, ich habe die Kontrolle. 2. Reihenfolge ist nicht wichtig. Aber - es sind Säulen! Ich sollte Indizes verwenden. 3. Saiten. –

Antwort

3

Eine solche Suchkriterien nicht in der Lage Verwendung von Indizes zu machen, aber es kann getan werden ...

SELECT 
    * 
FROM 
    yourTable 
WHERE 
    N-M <= CASE WHEN yourTable.field1 = searchValue1 THEN 1 ELSE 0 END 
     + CASE WHEN yourTable.field2 = searchValue2 THEN 1 ELSE 0 END 
     + CASE WHEN yourTable.field3 = searchValue3 THEN 1 ELSE 0 END 
     ... 
     + CASE WHEN yourTable.fieldN = searchValueN THEN 1 ELSE 0 END 

Und falls Sie Ihre Suchkriterien in einer anderen Tabelle ist ...

SELECT 
    * 
FROM 
    yourTable 
INNER JOIN 
    search 
    ON N-M <= CASE WHEN yourTable.field1 = search.field1 THEN 1 ELSE 0 END 
      + CASE WHEN yourTable.field2 = search.field2 THEN 1 ELSE 0 END 
      + CASE WHEN yourTable.field3 = search.field3 THEN 1 ELSE 0 END 
      ... 
      + CASE WHEN yourTable.fieldN = search.fieldN THEN 1 ELSE 0 END 

(Sie müssen den Wert von N-M selbst aufzufüllen)

EDIT:

Ein langatmiger Ansatz, dass einig Verwendung von Indizes machen ...

SELECT 
    id, -- your table would need to have a primary key/identity column 
    MAX(field1) AS field1, 
    MAX(field2) AS field2, 
    MAX(field3) AS field3, 
    ... 
    MAX(fieldN) AS fieldN 
FROM 
(
    SELECT * FROM yourTable WHERE field1 = searchValue1 
    UNION ALL 
    SELECT * FROM yourTable WHERE field2 = searchValue2 
    UNION ALL 
    SELECT * FROM yourTable WHERE field3 = searchValue3 
    ... 
    SELECT * FROM yourTable WHERE fieldN = searchValueN 
) 
    AS unioned_seeks 
GROUP BY 
    id 
HAVING 
    COUNT(*) >= N-M 

Wo Sie einen Index individuell auf jedes Feld haben, und wo erwarten Sie eine relativ niedrige Anzahl von Treffern für jedes Feld könnte übertreffen die erste Option, auf Kosten von sehr repetitiven Code.

3

Ich würde dies unter Verwendung is not distinct from zu NULL Werte behandeln.

Sie können auch Postgres short-hand verwenden, um die Logik zu vereinfachen. Eine Möglichkeit ist:

where ((a.field1 is not distinct from b.field1)::int + 
     (a.field2 is not distinct from b.field2)::int + 
     . . . 
     (a.fieldn is not distinct from b.fieldn)::int + 
    ) >= N - M 

Ich denke, das einfacher ist, nur in Bezug auf M auszudrücken. Also, schauen nur auf die Felder, die anders sind:

where ((a.field1 is distinct from b.field1)::int + 
     (a.field2 is distinct from b.field2)::int + 
     . . . 
     (a.fieldn is distinct from b.fieldn)::int + 
    ) <= M 

Tun Sie dies mit Daten erfordert eine cross join was recht teuer ist.

+0

Unter der Annahme, dass der Op * möchte, dass * 'NULL' mit 'NULL' gleichgesetzt wird, was wäre ein nicht standardmäßiges Verhalten in SQL? – MatBailie

+0

@MatBailie. . . Wenn ich nach ähnlichen Datensätzen in verschiedenen Tabellen suche, möchte ich normalerweise, dass NULL-Werte als gleichwertig betrachtet werden. –

Verwandte Themen