it-swarm.com.de

Wie kombiniere ich mehrere Sätze von 'ANDs' und 'ORs' in einem komplexen WHERE-Abfrageobjekt?

Ich möchte eine komplexe WHERE-Abfrage erstellen, die Folgendes überprüft:

If (condition1 = TRUE) AND (condition2 = TRUE) AND (condition3 = TRUE OR condition4 = TRUE)

Die ersten beiden Bedingungen MÜSSEN also immer wahr sein, und dann MÜSSEN entweder Bedingung 3 oder 4 wahr sein.

Ich versuche es mit dem Code:

->select ($db->quoteName(array('c.event','b.date','b.type','a.mob','a.joined','a.left')))
->from ($db->quoteName('app_mob_animal', 'a'))
->join('INNER', $db->quoteName('app_event_animal', 'b') . 'ON (' .$db->quoteName('a.mob'). '=' .$db->quoteName('b.mob').')')    
->join('INNER', $db->quoteName('app_events', 'c') . 'ON (' .$db->quoteName('b.event'). '=' .$db->quoteName('c.id').')') 
->join('INNER', $db->quoteName('app_mob', 'd') . 'ON (' .$db->quoteName('a.mob'). '=' .$db->quoteName('d.id').')')
->where (($db->quoteName('a.animal') . 'LIKE' . $db->quote($anid)), 'AND')
->where (($db->quoteName('a.joined') . '<=' . $db->quoteName('b.date')), 'AND') 
->where (($db->quoteName('a.left') . '>=' . $db->quoteName('b.date') .'OR'. ($db->quoteName('a.left') .'LIKE'. $db->quote($emptyDate))));

Aber wenn ich meine Antworten ausspucke, erhalte ich Ergebnisse, die eindeutig die zweite Bedingung brechen. Hier ist eine Ausnahme von meinen Ergebnissen, die zweite erfüllt nicht die Kriterien.

 [0]=>
  object(stdClass)#891 (6) {
    ["event"]=>
    string(7) "weighed"
    ["date"]=>
    string(19) "2015-04-19 00:00:00"
    ["type"]=>
    string(3) "mob"
    ["mob"]=>
    string(2) "11"
    ["joined"]=>
    string(19) "2015-04-18 11:39:14"
    ["left"]=>
    string(19) "0000-00-00 00:00:00"
  }
  [1]=>
  object(stdClass)#888 (6) {
    ["event"]=>
    string(9) "vet visit"
    ["date"]=>
    string(19) "2015-03-31 11:46:08"
    ["type"]=>
    string(3) "mob"
    ["mob"]=>
    string(2) "11"
    ["joined"]=>
    string(19) "2015-04-18 11:39:14"
    ["left"]=>
    string(19) "0000-00-00 00:00:00"
  }

Was ist die richtige Syntax für den WHERE-Teil dieser Abfrage?

2
Hannah Smith

Ihre OR Bedingung bricht es. Im Moment ist es so.

if condition1 = TRUE AND condition2 = TRUE AND condition3 = TRUE OR condition4 = TRUE

Sie haben also nicht () Um die Bedingungen 3 und 4. Dies gibt auch Ergebnisse, bei denen nur condition4true ist.

Versuchen

->select ($db->quoteName(array('c.event','b.date','b.type','a.mob','a.joined','a.left')))
->from ($db->quoteName('app_mob_animal', 'a'))
->join('INNER', $db->quoteName('app_event_animal', 'b') . ' ON (' .$db->quoteName('a.mob'). '=' .$db->quoteName('b.mob').')')    
->join('INNER', $db->quoteName('app_events', 'c') . ' ON (' .$db->quoteName('b.event'). '=' .$db->quoteName('c.id').')') 
->join('INNER', $db->quoteName('app_mob', 'd') . ' ON (' .$db->quoteName('a.mob'). '=' .$db->quoteName('d.id').')')
->where ($db->quoteName('a.animal') . ' LIKE ' . $db->quote($anid), 'AND')
->where ($db->quoteName('a.joined') . '<=' . $db->quoteName('b.date'), 'AND') 
->where ('('.$db->quoteName('a.left') . '>=' . $db->quoteName('b.date') .' OR '. $db->quoteName('a.left') .' LIKE '. $db->quote($emptyDate).')');

Sie können die Abfrage ausdrucken, um zu sehen, wie sie aufgebaut ist.

Wenn Ihre Abfragevariable beispielsweise $query Ist, tun Sie Folgendes

echo $query->dump(); // Thanks to @DmitryRekun

und es wird eine vollständige Abfrage ausgegeben, was ausgeführt wird. Auf diese Weise können Sie sehen, was daran falsch ist. Nur zum einfachen Debuggen.

2
Rene Korss

Nachdem eine funktionierende Lösung akzeptiert worden war, wollte ich meinen Wunsch nach Veröffentlichung einschränken. Später stellte ich jedoch fest, dass es sinnvoll ist, zu erläutern, wie der Abfrageerstellungsprozess geändert werden kann, um die Lesbarkeit, die Absicht, die Kürze und (in unmerklichem Maße) den Code zu verbessern. Leistung bei gleichzeitiger Wahrung der Sicherheit/Funktionalität. Ich werde auch ein paar Vorschläge einbringen, die ausschließlich der persönlichen Kodierungspräferenz unterliegen. Ich möchte nur im Voraus sagen, dass Renes Antwort sicher und vollständig funktionsfähig ist.

Hier ist, wie ich die Abfrage verschlüsseln könnte und warum:

$anid = "animal's string";  // hypothetical
$emptyDate = "2018-06-21";  // hypothetical
$db = JFactory::getDBO();
try {
    $query = $db->getQuery(true)
                ->select(
                    array(
                        "c.event",
                        "b.date",
                        "b.type",
                        "a.mob",
                        "a.joined",
                        $db->qn("a.left")
                    )
                )
                ->from("app_mob_animal a")
                ->innerJoin("app_event_animal b ON a.mob = b.mob")
                ->innerJoin("app_events c ON b.event = c.id")
                ->innerJoin("app_mob d ON a.mob = d.id")
                ->where(
                    array(
                        "a.joined <= b.date",
                        "a.animal = " . $db->q($anid)
                    )
                )
                ->andWhere(
                    array(
                        $db->qn("a.left") . " >= b.date",
                        $db->qn("a.left") . " = " . $db->q($emptyDate)
                    ),
                    "OR"
                );
    echo $query->dump();
    $db->setQuery($query);
    if (!$result = $db->loadAssocList()) {  // declare variable and check for empty array
        echo "<div>No Qualifying Rows</div>";
    } else {
        foreach ($result as $row) {
            // ... do what you like with $row['event'] etc.  (table names/alias are omitted from the resultset keys)
        }
    }
} catch (Exception $e) {
    echo "<div>Syntax error, please contact the developer</div>";
    // echo $e->getMessage();  // <-- not to be displayed publicly
}

Dies ist die gerenderte Abfrage (von ->dump()), die die beabsichtigte Abfragelogik liefert:

SELECT c.event, b.date, b.type, a.mob, a.joined, `a`.`left`
FROM app_mob_animal a
INNER JOIN app_event_animal b ON a.mob = b.mob
INNER JOIN app_events c ON b.event = c.id
INNER JOIN app_mob d ON a.mob = d.id
WOHER
(a.joined <= b.date AND a.animal = 'animal's string') AND
(`a`.`left`> = b.date OR` a`.`left` = '2018-06-19')

Erklärungen:

1
mickmackusa