2017-05-08 3 views
5

In meiner Datenbank eine Tabelle author genannt wird, die 4 Säulen:Suche für alle Kombinationen von ersten, mittleren und Nachnamen

  • authorID
  • vorName
  • Middle
  • nachName

Ein Benutzer zum Beispiel sucht nach Edgar Allan Poe. In unserer Tabelle ist Edgar Allan Poe gespeichert als: vorName - Edgar, Middle - Allan und nachName - Poe. Diese Abfrage ist ziemlich einfach. Aber wie schreibt man eine Anfrage, die nicht nur Edgar Allan Poe, sondern auch Poe Allan Edgar, Edgar Poe, Allan Poe, Edgar Allan, Allan Edgar Poe entspricht, ohne all diese möglichen Kombinationen selbst zu schreiben? Auch wenn der Benutzer sucht, sucht er/sie als "Edgar Allan Poe" oder "Poe Allan Edgar" zusammen, nicht in einem separaten Bereich.

+0

Bearbeiten Sie Ihre Frage und markieren Sie die Datenbank, mit welcher Datenbank Sie verwenden. –

+0

Sind _alle_ Kombinationen akzeptabel? – Manngo

+0

@Manngo Ja, alle Kombinationen sind akzeptabel. – Xty83a

Antwort

2

Bitte versuchen Sie folgende ...

DROP PROCEDURE IF EXISTS SimilarNames; 
DELIMITER // 
    CREATE PROCEDURE SimilarNames(authorFullName VARCHAR(250)) 
    BEGIN 
     SET @authorFullNameCommad = CONCAT('\'', 
              REPLACE(authorFullName, 
                ' ', 
                '\', \''), 
              '\''); 

     SET @selectStatementString := CONCAT("SELECT authorID,", 
               "  firstName,", 
               "  middleName,", 
               "  lastName ", 
               "FROM author ", 
               "WHERE ((firstName IN (", 
               @authorFullNameCommad, 
               ")) + (middleName IN (", 
               @authorFullNameCommad, 
               ")) + (lastName IN (", 
               @authorFullNameCommad, 
               "))) >=2;"); 

     PREPARE selectStatement FROM @selectStatementString; 
     EXECUTE selectStatement; 
     DEALLOCATE PREPARE selectStatement; 
    END // 
DELIMITER ; 
CALL SimilarNames('Edgar Allan Poe'); 

Diese Lösung beginnt mit einer PROCEDURE genannt SimilarNames (nach DROP ping alle vorhandenen Versionen der PROCEDURE) zu schaffen. Dieser PROCEDURE speichert den übergebenen Namen (zB 'Edgar Allan Poe') in der Parametervariable authorFullName.

Einmal gestartet, beginnt die PROCEDURE mit der Umwandlung einer Zeichenfolge wie Edgar Allan Poe in 'Edgar', 'Allan', 'Poe' und speichert sie in der Variablen @authorFullNameCommad.

Die CONCAT()-Funktion wird dann verwendet, um den Text der SQL-Anweisung zu bilden, die unsere Ergebnisse erzeugt. Wobei authorFullNameEdgar Allan Poe ist, wird die folgende Aussage erzeugt und gespeichert in @selectStatementString ...

SELECT authorID, 
     firstName, 
     middleName, 
     lastName 
FROM author 
WHERE ((firstName IN ('Edgar', 'Allan', 'Poe')) + (middleName IN ('Edgar', 'Allan', 'Poe')) + (lastName IN ('Edgar', 'Allan', 'Poe'))) >=2; 

Die SQL-Anweisung ist dann PREPARE d und EXECUTE d, wodurch die gewünschte Liste zu erzeugen, wenn die PROCEDURE genannt wird, die unter Verwendung von getan werden kann ...

CALL SimilarNames('Edgar Allan Poe'); 

Bitte beachten Sie, dass Sie dies nicht tun muss das PROCEDURE nach dem ersten Mal deklarieren. d Im Folgenden wird gut funktionieren ...

CALL SimilarNames('Edgar Allan Poe'); 
CALL SimilarNames('James Tiberius Kirk'); 

auch zu beachten, dass diese spezielle Methode anfällig für SQL-Injection ist. Ich kann eine Version entwickeln, die davor geschützt ist, wenn Sie es wünschen - es ist gerade zu spät und ich werde bald ins Bett gehen.

Meine Aussage gegen einen Beispieldatensatz getestet wurde mit dem folgenden Skript erstellt ...

CREATE TABLE author 
(
    authorID  INT NOT NULL AUTO_INCREMENT, 
    firstName VARCHAR(50), 
    middleName VARCHAR(50), 
    lastName  VARCHAR(50), 
    PRIMARY KEY (authorID) 
); 
INSERT INTO author (firstName, 
        middleName, 
        lastName) 
VALUES ('Edgar', 'Allan', 'Poe'), 
     ('Poe', 'Allan', 'Edgar'), 
     ('Edgar', 'Poe', ''), 
     ('Edgar', '', 'Poe'), 
     ('', 'Edgar', 'Poe'), 
     ('Allan', 'Poe', ''), 
     ('Edgar', 'Allan', ''), 
     ('Allan', 'Edgar', 'Poe'), 
     ('Edgar', 'Allan', 'Allan'), 
     ('James', 'Tiberius', 'Kirk'), 
     ('Karl', 'Ignatius', 'von Bach'), 
     ('Edgar', 'Poe', 'xyz'), 
     ('Allanah', 'Poelsen', ''); 

Die Ergebnisse waren wie ich erwartet hatte.

Wenn Sie irgendwelche Fragen oder Kommentare haben, dann zögern Sie nicht, einen Kommentar entsprechend zu posten.

Weiterführende Literatur

https://dev.mysql.com/doc/refman/5.7/en/call.html (auf CALL Aussage des MySQL)

https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_concat (auf CONCAT() Funktion des MySQL)

https://dev.mysql.com/doc/refman/5.7/en/create-procedure.html (auf CREATE PROCEDURE Aussage des MySQL)

https://dev.mysql.com/doc/refman/5.7/en/deallocate-prepare.html (auf MySQL DEALLOCATE sta Tement)

https://dev.mysql.com/doc/refman/5.7/en/stored-programs-defining.html (auf DELIMITER Befehl MySQL)

https://dev.mysql.com/doc/refman/5.7/en/drop-procedure.html (auf DROP PROCEDURE Aussage des MySQL)

https://dev.mysql.com/doc/refman/5.7/en/execute.html (auf EXECUTE Aussage des MySQL)

https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_in (auf IN Betreiber MySQL)

https://dev.mysql.com/doc/refman/5.7/en/prepare.html (auf MySQL PREPARE sta Tement)

https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_replace (auf der MySQL REPLACE() Funktion)

https://dev.mysql.com/doc/refman/5.7/en/set-statement.html (auf SET Aussage des MySQL)

+0

Vielen Dank. Absolut wunderbare Lösung und sehr klare Erklärung. Aber wenn ich den Code in mysql setze, heißt es: Unerwarteter Charakter (nahe;). – Xty83a

+0

Bitte geben Sie den vollständigen Text der Fehlermeldung wieder - ich interessiere mich besonders für andere Hinweise, wie z. B. Zeilennummern. – toonice

+0

Nummer Zeilen sind 9, 22, 24, 25, 26. Ich benutze phpmyadmin und ich dort ist ein rotes kleines Symbol von der Codezeile, und es sagt nur: 'Unerwartetes Zeichen. (in der Nähe;) – Xty83a

3

In jeder Datenbank, können Sie etwas tun:

where firstName in ('Edgar', 'Allan', 'Poe') and 
     middleName in ('Edgar', 'Allan', 'Poe') and 
     middleName <> firstName and 
     lastname in ('Edgar', 'Allan', 'Poe') and 
     lastname not in (firstname, middleName) 

Dies ist eigentlich recht einfach zu mehr Namen zu erweitern, wenn Sie so wollen - die Namen wie in Ihrem Beispiel verschieden sind unter der Annahme, (wenn Sie Autoren mit doppelten Namen zulassen wollen, entfernen Sie einfach die Zeilen 3 und 5 aus der obigen Abfrage).

Abhängig von Ihrer Datenbank sollten Sie jedoch stattdessen reguläre Ausdrücke oder Volltextsuche verwenden.

+1

https://en.wikipedia.org/wiki/Helle_Helle, https://en.wikipedia.org/wiki/Holling_C._Holling :-) – paxdiablo

+0

@paxdiablo. . . Ihr Beispiel ist schöner als Sirhan Sirhan. –

0

Für ein generisches DBMS, vorausgesetzt, Ihre Absicht besteht nur darin, Ihre Abfragen zu vereinfachen, wäre eine Möglichkeit, eine separate berechnete Spalte zur Tabelle author hinzuzufügen, die beim Einfügen und Aktualisieren ausgelöst wird.

Mit anderen Worten, ein clumn searchFullName genannt und haben es auf:

<space><firstName><space><secondName><space><lastName><space> 

Dann Sie Abfrage wird eine (relativ) einfach:

select something from author 
where searchFullName like '% Poe %' 
    and searchFullName like '% Edgar %' 

Es wird nicht blendend schnell sein für große Tische, aber es sollte erreichen, was Sie wollen.

Verwandte Themen