[SQLite-Tutorial] Wie benutze ich LIKE mit IN

Zvoni

Erfahrenes Mitglied
Hallo zusammen,

wer kennt nicht das Problem, dass man eine Spalte mit mehreren Wildcard-Filtern vergleichen will?
Dies resultiert in der Regel in solchen Konstrukten:
SQL:
SELECT DISTINCT SomeTextField
FROM Table
WHERE
SomeTextField LIKE 'Wert1%' OR
SomeTextField LIKE '%Wert2' OR
SomeTextField LIKE '%Wert3%'
weil ein "SELECT ...... FROM ..... WHERE EineSpalte LIKE IN ("Wert1%", "%Wert2", "%Wert3%")" nicht funktioniert

Jetzt bin beim rumstöbern auf folgenden interessanten Sachverhalt gestossen:
Der LIKE-Operator kann auch auf eine Spalte angewendet werden.
Also in der Art:
SQL:
SELECT DISTINCT
t1.SomeTextField FROM tbl_test As T1
INNER JOIN tbl_test As t2
ON t1.SomeTextField LIKE t2.SomeOtherTextField
Bemerkung: Kann auf eine Spalte in derselben Tabelle gehen, oder auf eine Spalte in einer anderen Tabelle

Daraufhin bin ich auf folgende Idee gekommen:
SQL:
WITH cte(X) AS (
    SELECT 'Text%' UNION
    SELECT 'Hello%' UNION
    SELECT '%World%')
SELECT DISTINCT
t.SomeTextField
FROM tbl_test As t
INNER JOIN cte As c
ON t.SomeTextField LIKE c.x
Und.... es funktioniert.

Mir ist natürlich klar, dass dies mit Parametern dann nur schwer umzusetzen ist (wenn überhaupt),
aber dafür bleibt dann immer noch die "Lösung" mit einer temp. Tabelle:
1) Erzeuge temp. Tabelle mit einer (Text-) Spalte (oder die Tabelle ist einfach vorhanden, aber am Anfang immer leer)
2) Mache die INSERTS in die temp. Tabelle mit Parametern (Wahrscheinlich in einer Schleife)
3) Führe das Query wie im zweiten Codeblock aus
4) Lösche/Leere temp. Tabelle

In allen Varianten ist das "DISTINCT" wichtig. In meinem Beispiel würde es für "Hello World" zwei Ergebnisse geben ohne DISTINCT.

Viel Spass
 
Vor einigen Wochen gab es einen Thread zu dem gleichen Thema, allerdings nicht mit sqlite und dort wurde als Lösung vorgeschlagen, REGEX zu verwenden. Damit wird das Statement dann sehr einfach:
Code:
"select col1, col2 from tbl1 where col1 REGEXP '(abc|def|^ghi)'"
Getestet in Python hiermit:
Code:
    import sys
    import os
    import sqlite3
    import re

    scriptPath = os.path.dirname(os.path.abspath(__file__))
    dbLoc = scriptPath+r'\..\linphone\friends.db'
    con = sqlite3.connect(dbLoc)
    con.row_factory = sqlite3.Row
    con.create_function('regexp', 2, lambda x, y: 1 if re.search(x, y) else 0)
    cur = con.cursor()

    sqlSelect = "select id, sip_uri from friends where sip_uri REGEXP '(Swet|Ele|^Mül)'"
    cur.execute(sqlSelect)
    print(cur.description)
    rows = cur.fetchall()
    print(rows)
    for row in rows:
        print(str(row['id']), row['sip_uri'])
    con.close()
Geholfen hat mir dies:
How do I use regex in a SQLite query?
 
Semper,
ja, ich erinner mich auch an den Thread.
Aber am Ende läuft es trotzdem irgendwie auf Text-Verkettung hinaus um das "'(abc|def|^ghi)'"" zu bekommen
 
Liegen aber Welten dazwischen von der Komplexität der Abfrage her und der Performance - wenn ich davon ausgehe, dass eine komplexere Abfrage auch eine schlechtere Performance hat.
 
Zuletzt bearbeitet:
Liegen aber Welten dazwischen von der Komplexität der Abfrage her und der Performance - wenn ich davon ausgehe, dass eine komplexere Abfrage auch eine schlechtere Performance hat.
Schon klar, aber mein Themen-Betreff besagt ja auch [SQLite] :)
Und SQLite hat keinen REGEX-Support out-of-the Box (muss erst als Erweiterung installiert werden, und vor jedem Aufruf der Datenbank geladen werden), und in deinem Python-Beispiel erzeugst du ja auch erst eine "REGEXP"-Funktion

EDIT: Ich habe nochmal darüber nachgedacht, und an einer Stringverkettung kommt man nicht vorbei (egal ob jetzt REGEX oder "native")
In meiner CTE-Variante ist die "Variable" der SELECT des CTE (Zeile 2-4 oben).
Aus dem Frontend-Code ein Array füllen mit
Code:
MeinArray[0]="SELECT 'Text%'"  //Kein anhängendes Leerzeichen!
MeinArray[1]="SELECT 'Hello%'" //Kein anhängendes Leerzeichen!
MeinArray[2]="SELECT '%World%'" //Kein anhängendes Leerzeichen!
Und dann aus dem Array einen String bauen.
in PHP ist das glaube ich mit implode, in anderen gängigen Sprachen ein Join.
Als Delimiter dann das Wort " UNION " nehmen (auf führende/anhängende Leerzeichen achten!)
 
Zuletzt bearbeitet:
Zurück