it-swarm.com.de

'ANDs' und 'ORs' in einer komplexen WHERE-Abfrage kombinieren - Teil 2

Ich habe mir mit dieser Abfrage in den letzten 2 Tagen die Haare ausgezogen und die 2 anderen ähnlichen Beiträge ohne Glück gelesen und erneut gelesen.

Szenario: Ich sammle zwei Eingaben von einem Benutzer: Test-ID-Code und E-Mail-Adresse, die er beim Absenden des Tests verwendet hat. Der Testcode besteht aus Zahlen und kann am Anfang einen Buchstaben enthalten. Die Testeinrichtung lässt diese Nummer jedoch möglicherweise weg, sodass ich den Buchstaben zu einer Variablen in der Abfrage hinzufüge (Grund für "newtidcode" siehe unten). Sie können dem Tester beim Absenden auch bis zu 4 E-Mail-Adressen mitteilen (Grund für mich, 4 E-Mail-Möglichkeiten zu testen).

Hier ist meine Frage:

    $query->select($db->quoteName(array('tidcode', 'cdcode','email1', 'email2', 'email3', 'email4', 'status')))
        ->from($db->quoteName('#__tid_codes'))
        ->where($db->quoteName('tidcode').' = '.$db->quote($tidcode), 'OR')
        ->where($db->quoteName('tidcode').' = '.$db->quote($newtidcode), 'AND')
        ->where('('.$db->quoteName('email1').' = '.$db->quote($email).' OR '.$db->quoteName('email2').' = '.$db->quote($email).' OR '.$db->quoteName('email3').' = '.$db->quote($email).' OR '.$db->quoteName('email4').' = '.$db->quote($email).')');

Hier wurde die SQL-Anweisung erstellt:

SELECT `tidcode`,`cdcode`,`email1`,`email2`,`email3`,`email4`,`status` FROM `#__tid_codes` WHERE `tidcode` = '10348' OR `tidcode` = 'F10348' OR (`email1` = '[email protected]' OR `email2` = '[email protected]' OR `email3` = '[email protected]' OR `email4` = '[email protected]')

Wie Sie sehen können, sollte OR vor der E-Mail ein UND laut der zweiten "where" -Anweisung sein. Ich habe sogar versucht, Bedingungsarrays wie die folgenden zu verwenden, und bin trotzdem auf dasselbe gestoßen.

$conditions1 = array(
    $db->quoteName('tidcode')." = ".$db->quote($tidcode),
    $db->quoteName('tidcode')." = ".$db->quote($newtidcode)
);
$conditions2 = array (
    $db->quoteName('email1')." = ".$db->quote($email),
    $db->quoteName('email2')." = ".$db->quote($email),
    $db->quoteName('email3')." = ".$db->quote($email),
    $db->quoteName('email4')." = ".$db->quote($email)
);

Dies ist mein erster Versuch in JDatabase, diese Komplexität abzufragen. Ich habe diese Anwendung gut funktioniert in Standard-HTML und PHP, aber versuchen, auf Joomla zu portieren. Jede Hilfe wird sehr geschätzt.

6
TJM

Der zweite Parameter von where, genannt $glue, funktioniert nicht wie erwartet.

Dies ist der Quellcode der where-Funktion:

public function where($conditions, $glue = 'AND')
{
    if (is_null($this->where))
    {
        $glue = strtoupper($glue);
        $this->where = new JDatabaseQueryElement('WHERE', $conditions, " $glue ");
    }
    else
    {
        $this->where->append($conditions);
    }
    return $this;
}

Sie können sehen, dass nur der $ -Kleber des ersten "WO" benötigt wird, das Sie Ihrer Abfrage hinzufügen.

Ich habe weitere Informationen zu diesem Problem gefunden hier , aber die Informationen dort sind möglicherweise veraltet.

Lösung

Behalten Sie Ihre 2 Variablen $ conditions1 und $ conditions2 bei und erstellen Sie dann Ihre Abfrage wie folgt:

$query->select($db->quoteName(array('tidcode', 'cdcode','email1', 'email2', 'email3', 'email4', 'status')))
    ->from($db->quoteName('#__tid_codes'))
    ->where(implode(' OR ', $conditions1))
    ->where('(' . implode(' OR ', $conditions2) . ')');

Was wird zu dieser Abfrage führen:

SELECT `tidcode`,`cdcode`,`email1`,`email2`,`email3`,`email4`,`status` FROM `#__tid_codes` WHERE `tidcode` = '10348' OR `tidcode` = 'F10348' AND (`email1` = '[email protected]' OR `email2` = '[email protected]' OR `email3` = '[email protected]' OR `email4` = '[email protected]')
6
fruppel

Dies ist ein bisschen wortreich, aber wenn Sie jemals auf komplexe where() Ausdrücke stoßen oder nichts über Operator-Priorität ​​wissen, lesen Sie dies bitte mindestens einmal.

Ihre Frage ist nicht eindeutig, wie die Bedingungen der WHERE -Klausel zu bewerten sind. Diese Seite ist ein geeigneter Ort, um Operator-Rangfolge zu erwähnen. Sofern nicht anders angegeben, können wir alle davon ausgehen, dass der Vorrang nach Ihren Wünschen funktioniert.

Bevor ich jedoch die Auswirkungen dieser Regel erläutere, möchte ich zunächst die Logik des dritten/letzten Teils Ihrer WHERE -Klausel (der E-Mail-Übereinstimmung) zusammenfassen.

`email1` = '[email protected]'
OR `email2` = '[email protected]'
OR `email3` = '[email protected]'
OR `email4` = '[email protected]'

... kann viel prägnanter geschrieben werden (D.R.Y. Codierungspraxis) als:

'[email protected]' IN (`email1`, `email2`, `email3`, `email4`)

Jetzt werde ich zeigen, dass Operator-Priorität mit diesem komprimierten Ausdruck.

  • A wird der tidcode Vergleich sein
  • B wird der newtidcode Vergleich sein
  • C wird der email Vergleich sein

[~ # ~] und [~ # ~] werden ausgewertet, bevor [~ # ~] oder [~ # ~] s (siehe früherer Hyperlink)

A OR B AND C Ist dasselbe wie A OR (B AND C) ... und ich denke, das ist, was Sie wünschen.

Wenn Sie möchten, dass A OR B Vor AND C Ausgewertet wird, müssen Sie Klammern wie diese verwenden: (A OR B) AND C.


Trotzdem biete ich zwei verschiedene Joomla-Syntaxlösungen an.

Einzelner WHERE-Methodenaufruf : (viel Zeilenbreite, liest sich aber wie raw sql)

->where("tidcode = " . $db->q($tidcode) . " OR tidcode = " . $db->q($newtidcode) . " AND " . $db->q($email) . " IN (email1, email2, email3, email4)");

Zwei WHERE-Methodenaufrufe : (reduzierte Zeilenbreite, liest sich aber weniger wie raw sql)

->where("tidcode = " . $db->q($tidcode), "OR")
->where("tidcode = " . $db->q($newtidcode) . " AND " . $db->q($email) . " IN (email1, email2, email3, email4)");

Beide produzieren:

WHERE tidcode = '10348' OR tidcode = 'F10348' AND '[email protected]' IN (email1, email2, email3, email4)


Zum Vergleich werten die folgenden Ausschnitte zuerst das OR aus! :

->where("tidcode = " . $db->q($tidcode))
->extendWhere("OR", "tidcode = " . $db->q($newtidcode))
->extendWhere("AND", $db->q($email) . " IN (email1, email2, email3, email4)");

und

->where("tidcode = " . $db->q($tidcode))
->orWhere("tidcode = " . $db->q($newtidcode))
->andWhere($db->q($email) . " IN (email1, email2, email3, email4)");

produzieren (via $query->dump()):

WHERE 
(
(tidcode = '10348') OR 
(tidcode = 'F10348')) AND 
('[email protected]' IN (email1, email2, email3, email4))

... [~ # ~] aber [~ # ~] , wenn Sie [~ # ~] tun [~ # ~] zuerst den OR auswerten wollen, dann die ersten beiden Bedingungen der WHERE-Klausel mit IN neu packen.

->where(
    array(
        "tidcode IN (" . implode(", ", $db->q(array($tidcode, $newtidcode))) . ")",
        $db->q($email) . " IN (email1, email2, email3, email4)"
    )
);

welche produziert:

WHERE tidcode IN ('10348', 'F10348') AND '[email protected]' IN (email1, email2, email3, email4)
1
mickmackusa