[mySQL] WHERE (c1 OR c2) in [4, 7, 9]

DelphiKing

King with a crown
ID: 46719
L
20 April 2006
6.553
729
Aloha,

sorry für den doofen Titel, wusste es nicht besser auszudrücken :ugly:

Ich habe eine Tabelle mit u.a. drei (im einfachen Fall, könnten auch mehr sein) Spalten "c1", "c2" und "c3" (int), die alle so eine Art Tag oder Kategorie repräsentieren. Eine Zeile hat also immer bis zu drei (gleichwertige) Kategorien.

Nun habe ich so ein Tripel (z.B. $v1, $v2, $v3) gegeben und möchte mit einer möglichst übersichtlichen MySQL-Anfrage alle items haben, bei denen mindestens zwei der drei Kategorien übereinstimmen.
Die naheliegendste und stupide Lösung wäre ja, alle möglichen Kombinationen durchzutesten, aber die resultierende Anfrage wäre wohl eine ganze DinA4-Seite lang :ugly:
Kann ich in MySQL wenigstens testen, ob ein Elementwert in einer Menge liegt?
Also sowas wie
Code:
WHERE 
  ( (c1 IN [$v1, $v2, $v3]) AND (c2 IN [$v1, $v2, $v3]) ) OR
  ( (c2 IN [$v1, $v2, $v3]) AND (c3 IN [$v1, $v2, $v3]) ) OR
  ( (c1 IN [$v1, $v2, $v3]) AND (c3 IN [$v1, $v2, $v3]) )

Weiß leider nicht, nach was ich suchen muss resp. wie das heißt ...

lg,dk

Edit/PS: Keine Kommentare zur bestehenden DB-Struktur, ist nicht mein Projekt, lässt sich nicht ändern und ist bisher aber aus Performancegründen auch ganz OK+sinnvoll.
 
Hat MySQL nicht sowas wie Boolsche Werte ? Dann könnte ein

WHERE
( c1 in ($V1,$V2,$V3) ) + ( c2 in ($V1,$V2,$V3) ) + ( c3 in ($V1,$V2,$V3) ) >= 2

gegebenenfalls weiterhelfen

wenn nicht, dann müsste man die CASE - Klausel anwenden können


WHERE
CASE WHEN ( c1 in ($V1,$V2,$V3) ) THEN 1 ELSE 0 ENDCASE +
CASE WHEN ( c2 in ($V1,$V2,$V3) ) THEN 1 ELSE 0 ENDCASE +
CASE WHEN ( c3 in ($V1,$V2,$V3) ) THEN 1 ELSE 0 ENDCASE >= 2
 
das würde aber jeweils zu einem Full-Table-Scan führen

Code:
WHERE 
  ( (c1 IN [$v1, $v2, $v3]) AND (c2 IN [$v1, $v2, $v3]) ) OR
  ( (c2 IN [$v1, $v2, $v3]) AND (c3 IN [$v1, $v2, $v3]) ) OR
  ( (c1 IN [$v1, $v2, $v3]) AND (c3 IN [$v1, $v2, $v3]) )

also das habe ich eben mit KV-Diagrammen auch als die minimalste logische Funktion errechnet, und das würde ich auch nehmen, das wird wohl die performanteste Lösung sein. Du müsstest eben nur 3 partielle Indexe erstellen:
Code:
ALTER TABLE tab ADD INDEX (c1, c2);
ALTER TABLE tab ADD INDEX (c1, c3);
ALTER TABLE tab ADD INDEX (c2, c3);
 
das würde aber jeweils zu einem Full-Table-Scan führen

Mag sein, aber ob das in diesem Fall nicht sowieso der performantere Zugriffsweg ist, ist eine ganz andere Frage.
Spätestens, wenn eine vierte und fünfte Spalte dazukommt, kommst Du mit der Kombinatorik nicht mehr weiter.

Bedenke ausserdem, dass jeder Index Platz braucht und bei jedem Insert / Update und Delete modifiziert werden muss, was jedesmal zusätzlich Performance kostet.
 
Ob das in diesem Fall nicht sowieso der performantere Zugriffsweg ist, ist eine ganz andere Frage.
Spätestens, wenn eine vierte und fünfte Spalte dazukommt, kommst Du mit der Kombinatorik nicht mehr weiter.
stimmt

Bedenke ausserdem, dass jeder Index Platz braucht und bei jedem Insert / Update und Delete modifiziert werden muss, was jedesmal zusätzlich Performance kostet.
das ist klar, aber ich vermute mal das weniger geschrieben als gelesen wird :mrgreen:
 
das ist klar, aber ich vermute mal das weniger geschrieben als gelesen wird :mrgreen:

Geupdated oder eingefügt wird da in der Tat nur sehr wenig .. danke euch beiden für die Hilfe :)

Aber da fällt mir grad noch was ein, was ich mich vor ein paar Wochen (nicht in diesem Zshg) gefragt habe: ist MySQL so schlau und aktuallisiert einen Tabellenindex nur dann, wenn ein betroffenes (=indiziertes) Feld geändert wird, oder grundsätzlich immer?