doppelte Einträge finden, jedoch nur Text bis zu bestimmten Zeichen vergleichen

  • Hi zusammen,

    ich würde gerne in meiner DB doppelte Einträge finden, was mit folgendem Code soweit funktioniert:

    SQL
    _SQLite_GetTable2d (-1, "Select a.title, a.oid, a.size from DB a, DB b where (a.title = b.title and a.oid <> b.oid) Order by a.title;", $aResult, $iRows, $iColumns)

    Leider tauchen hierbei nicht alle Einträge auf, da ich teilweise noch etwas, getrennt mit " - " im Namen erfasst habe. Logisch, dass die also nicht auftauchen.
    Kann ich per SQL mitgeben, dass er den a.title nur bis zu der Zeichenfolge " - " vergleichen soll?

    Darüber hinaus noch die Frage: Wenn ein Eintrag doppelt vorkommt, erscheinen natürlich beide Einträge als duplikate. Ist er sogar 3x enthalten, erscheinen jedoch direkt 6 Einträge (alle 3 Einträge doppelt). Kann man hier noch einbauen, dass immer nur 1 doppelter Eintrag angezeigt werden soll, sprich nur 1x jede OID?

    • Offizieller Beitrag

    Kann ich per SQL mitgeben, dass er den a.title nur bis zu der Zeichenfolge " - " vergleichen soll?


    Ja klar, deine Vergleichsmethode ist eigentlich einer SQL-DB unwürdig (mit "="). Damit findet man ja wirklich nur einen sehr fixen Datenbestand. Hast du schonmal was von LIKE gehört? ;) Damit kannst du die Suche wesentlich flexibler gestalten. LIKE und IN sind meine persönlich am Häufigsten genutzten Suchmethoden.

  • Hi, schonmal besten Dank. Leider komme ich jetzt erst dazu, an dem entsprechenden Punkt hier weiter zu machen. Like habe ich nun eingefügt, allerdings müsste ich nun noch gucken, dass er immer nur bis zum ersten Bindenstrich vergleicht.
    Aber in dem Zusammenhang habe ich noch folgendes Problem. Wie kann man folgende Abfrage verkürzen/ vereinfachen ... das sie auch schneller arbeitet?

    SQL
    Select a.title, a.oid, a.size, a.disk from DB a, DB b where (a.title like b.title and a.oid <> b.oid) And (a.disk = 'HD 1' or b.disk = 'HD 1') Or (a.disk = 'HD 2' or b.disk = 'HD 2')


    Im Grunde ist der hintere Teil variabel und es könnten noch mehr Disks dazu kommen. Mit einer Disk funktioniert es gut, mit 2 dauert es schon ewig und das Ergebnis ist auch 'Strange'. Allerdings sollte es doch auch leichter gehen, oder?

  • Vielleicht wäre es sinnvoll ein Testscript zu erstellen, welches eine vergleichbare Datenbank mit einigen Beispieldatensätzen anlegt. Außerdem wäre es hilfreich wenn du genauer beschreibst was du eigentlich bezwecken willst. Grundsätzlich bist du bei Stringvergleichen die auf Teiltreffern aufbauen auch sehr eingeschränkt, da bietet es sich eher an den Stringvergleich in Autoit zu machen und reguläre Ausdrücke zu verwenden.

    SQLITE bietet dir unter anderem diese Funktionen an, welche du in das Query einbauen könntest:

    http://sqlite.org/lang_corefunc.html

    Code
    rtrim(...)
    ltrim(...)
    replace(...)

    Sofern sich deine Strings die "gleich" sein sollen nur durch das Vorhanden sein eines Bindestriches unterscheiden, so würde ich die evtl. vorhandenen Bindestriche vor dem Vergleich einfach mit replace() entfernen. Somit sollten ansonsten identische Strings auch als solche erkannt werden.

  • thx schonmal, das mit In werde ich direkt mal testen.

    bzgl. dem Vergleich unterscheiden sich die Treffer nicht um den Bindestrich. Im groben geht es um eine Film-Datenbank und dort können die Einträge z. B. so aussehen.

    Terminator 2
    Terminator 2 - Tag der Abrechnung

    Je nachdem wie ich die Filme seinerzeit eingetragen habe. In jedem Fall habe ich aber den 2t Titel immer mit einem Bindestrich getrennt, aber nicht immer angegeben. Daher soll er eigentlich nur bis zum Bindestrich, bzw. -2, vergleichen, dass in beiden Fällen 'Terminator 2' rauskommt. Aber ich werde mir die genannten Funktionen auch mal anschauen ;)

  • Dann mach halt ein or rein, also so:

    SQL
    b.name LIKE a.name% OR a.name LIKE b.name%


    erscheinen jedoch direkt 6 Einträge (alle 3 Einträge doppelt).

    Und um keine Doubletten im Ergebnis zu haben kann man ggf. noch

    SQL
    DISTINCT

    verwenden.

  • werde ich gleich testen, derzeit bekomme ich noch nen Fehler, wenn ich einfach nur ein % an a.title hänge.
    allerdings versuche ich gerade a.disk Or b.disk In ('HD 1'), was aber nur bedingt geht.

    So sieht die Abfrage aus:

    SQL
    Select a.title, a.oid, a.size, a.disk from DB a, DB b where (a.title like b.title and a.oid <> b.oid) And (a.disk Or b.disk In ('HD 1')) Order by a.title;

    Es zeigt die doppelten Filme an, allerdings nur die, die NICHT auf HD 1 sind. Vorher war es ja so, dass er den doppelten auf HD 1 und HD X angezeigt hat. Wo ist mein Fehler?

  • Ich muss es nochmal besser erklären, deine Lösung scheint mMn schon das zu sein, was ich suche, allerdings funktioniert es nicht wie meine 'umständliche & langsame' Lösung. Es geht nicht darum, dass er 2 Platten miteinander vergleichen soll, vergessen wir das Beispiel mit HD 1 und HD 2. Wenn ich deine Lösung nehme, bekomme ich dies ohne Probleme erweitert. Gehen wir davon aus, dass nur HD 1 aktiv angeschlossen ist, HD 2-4 sind noch in der DB aber inaktiv.

    Nun möchte ich Dopplungen suchen, wo 1 Dopplung auf HD 1 ist, dazu dann die Dopplung auf den inaktiven HD 2-4.

    Das funktioniert z. B. mit folgender Abfrage so wie es soll:

    SQL
    Select a.title, a.oid, a.size, a.disk from DB a, DB b where (a.title like b.title and a.oid <> b.oid) And (a.disk = 'HD 1' or b.disk = 'HD 1')

    Ergebnis wenn HD 1 aktiv angeschlossen ist:

    Terminator 2 | HD 1
    Terminator 2 | HD 3
    Terminator 3 | HD 1
    Terminator 3 | HD 4

    Nicht gezeigt wird nun z. B. Terminator 1, welcher doppelt auf HD 3 und HD 4 liegt, weil ich ja nur HD 1 aktiv ist.

    Das gleiche Ergebnis möchte ich jetzt eigentlich mit deiner Version bekommen, denn diese könnte ich einfach erweitern, falls noch eine weitere HD aktiv ist.
    Und eigentlich verstehe ich es auch so, dass es gehen müsste. Was ja erst richtig 'strange' ist, dass er mir quasi folgendes als Ergebnis liefert, obwohl ja die Abfrage nach HD 1 ist:

    Terminator 2 | HD 3
    Terminator 3 | HD 4

    EDIT: er zeigt aber auch kein Terminator 1 an, also er sucht schon nur die raus, die doppelt und auf HD 1 sind, nur zeigt er die doppelten auf HD 1 nicht an.

    EDIT 2:

    mich wundert, warum folgende beiden Abfragen NICHT zum gleichen Ergebnis führen:

    Funktioniert richtig
    und zeigt bei doppelten Filme beide an (einer auf HD 1 und der zweite woaonders)

    SQL
    Select a.title, a.oid, a.size, a.disk from DB a, DB b where (a.title like b.title and a.oid <> b.oid) And (a.disk = 'HD 1' or b.disk = 'HD 1') Order by a.title;

    <>

    Funktioniert NICHT richtig und zeigt bei doppelten Filmen nur einen an, und zwar den, der NICHT auf HD 1 liegt.

    SQL
    Select a.title, a.oid, a.size, a.disk from DB a, DB b where (a.title like b.title and a.oid <> b.oid) And (a.disk Or b.disk In ('HD 1')) Order by a.title;

    EDIT 3:
    Folgende Abfrage funktioniert auch RICHTIG, vllt muss ich dann die nehmen, die lässt sich auch easy um mehrere erweitern:

    SQL
    Select a.title, a.oid, a.size, a.disk from DB a, DB b where (a.title like b.title and a.oid <> b.oid) And (a.disk IN ('HD 1') or b.disk IN ('HD 1')) Order by a.title;
  • Problem 1 habe ich nun gelöst, allerdings komme ich hier nicht weiter:

    SQL
    b.name LIKE a.name% OR a.name LIKE b.name%

    Hinter die variable einfach % anhängen funktioniert nicht, dann gibts nen Error.

    [autoit]

    ! SQLite.au3 Error
    --> Function: _SQLite_Query
    --> Query: Select DISTINCT a.title, a.oid, a.size, a.disk from DB a, DB b where (a.title like b.title% and a.oid <> b.oid) And (a.disk In ('HD 1') Or b.disk In ('HD 1')) Order by a.title;
    --> Error: near "and": syntax error

    [/autoit]
  • Problem 1 habe ich nun gelöst, allerdings komme ich hier nicht weiter:

    SQL
    b.name LIKE a.name% OR a.name LIKE b.name%

    Hinter die variable einfach % anhängen funktioniert nicht, dann gibts nen Error.

    [autoit]

    ! SQLite.au3 Error
    --> Function: _SQLite_Query
    --> Query: Select DISTINCT a.title, a.oid, a.size, a.disk from DB a, DB b where (a.title like b.title% and a.oid <> b.oid) And (a.disk In ('HD 1') Or b.disk In ('HD 1')) Order by a.title;
    --> Error: near "and": syntax error

    [/autoit]


    Du musst in diesem Fall vermutlich wie in Autoit auch eine Stringverkettung mit der Variable realisieren. Dafür gibt es in sqlite den concatenate Operator ||

    Ich kann es gerade nicht testen, sollte aber so funktionieren:

    SQL
    b.name LIKE (a.name || '%') OR a.name LIKE (b.name || '%')
  • Hi, danke, das scheint zu funktionieren, allerdings bringt mich das doch nicht weiter, weil er ja z. B. Terminator auch in Teil 2+3 etc findet, die dann entsprechend auch als doppelte rauswirft.
    Dann muss ich wirklich mit den oben genannten funktionen wie rtrim etc probieren ... dennoch besten dank, wieder was gelernt =)

    EDIT:

    ich erweitere gerade Stück für Stück die Abfrage, bekomme aber bei folgender Abfrage folgende Fehlermeldung: no such function: instr

    SQL
    Select a.title, a.oid, a.size, a.disk from DB a, DB b where (rtrim(a.title,length(a.title) - instr(a.title,' - ')) like rtrim(b.title,length(b.title)) and a.oid <> b.oid) Order by a.title;

    Liegt das an der sqlite.au3?

  • Hab mal auf die neuste AutoIt-Version upgedated und dann ging es. Die sqlite.dll wird wohl verwaltet gewesen sein.
    Aber dennoch funzt mein Beispiel oben nicht, ... was auch logisch ist. Wenn INSTR nichts findet, müsste ja LENGTH geTRIMt werden.

    Er dürfte das quasi nur ausführen, wenn ein Bindestrich im String vorhanden ist. Ich denke ich werde erstmal darauf verzichten und mich anderen Problemen/ Funktionen in meinem Script widmen, das scheint mich etwas zu überfordern ;)

    Dennoch danke für eure Hilfe, hat mich schon sehr viel weiter gebracht.