Je veux créer une requête complexe WHERE qui vérifie:
Si (condition1 = TRUE) ET (condition2 = TRUE) ET (condition3 = TRUE OR condition4 = TRUE)
Donc, les deux premières conditions DOIVENT toujours être vraies et ensuite, la condition 3 ou 4 DOIT être vraie.
J'essaie avec le 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))));
Mais lorsque je crache mes réponses, j'obtiens des résultats qui vont clairement à l'encontre de la deuxième condition. Voici une exception de mes résultats, le second ne remplit pas les critères.
[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"
}
Quelle est la syntaxe correcte pour la partie WHERE de cette requête?
Votre condition OR
la casse. En ce moment c'est.
if condition1 = TRUE AND condition2 = TRUE AND condition3 = TRUE OR condition4 = TRUE
Donc vous n'avez pas ()
autour des conditions 3 et 4. Cela donnera également des résultats là où seulement condition4
est true
.
Essayer
->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).')');
Vous pouvez imprimer une requête pour voir comment elle est construite.
Par exemple, si votre variable de requête est $query
, alors fais
echo $query->dump(); // Thanks to @DmitryRekun
et il va imprimer la requête complète ce qui est exécuté. De cette façon, vous pouvez voir ce qui ne va pas. Juste pour le débogage simple.
J'allais limiter mon envie de poster après l'acceptation d'une solution de travail, mais j'ai par la suite décidé qu'il était utile d'expliquer comment le processus de création de requêtes pouvait être modifié pour améliorer la lisibilité du code, les intentions, la brièveté et (à un degré imperceptible). performances tout en maintenant la sécurité/fonctionnalité. Je vais également faire quelques suggestions qui concernent uniquement les préférences personnelles en matière de codage. Je veux juste dire, à l'avance, que la réponse de René est sûre et complètement fonctionnelle.
Voici comment je peux coder la requête et ensuite pourquoi:
$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
}
C'est la requête rendue (à partir de ->dump()
) qui fournit la logique de requête prévue:
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
OÙ
(a.joined <= b.date AND a.animal = 'chaîne de l'animal') AND
(`a`.`left`> = b.date OR` a`.`left` = '2018-06-19')
Explications:
SELECT
se présentent sous la forme d'un tableau, mais peuvent tout aussi bien être écrites sous la forme d'une chaîne unique de valeurs séparées par des virgules. Seul le nom de la colonne left
[~ # ~] a besoin de [~ # ~] pour être encapsulé en arrière - cela peut être fait en toute sécurité avec des backticks codés en dur ou avec un qn()
appel.left
est un mot réservé. event
, date
et type
sont des mots-clés MySQL, mais pas réservés. OMI, éliminer les appels de fonction qui ne fournissent aucun avantage est une bonne habitude de codage.qn()
comme raccourci pour quoteName()
, q()
pour quote()
et innerJoin()
pour join("INNER",...)
pour la brièveté.where()
dans une seule requête, car cela s'écarte trop de la construction de requête brute. Vous voyez, chaque nouveau innerJoin()
écrit une nouvelle ligne INNER JOIN
, Mais les appels répétés where()
ne font que prolonger la clause unique. J'utilise andWhere () non seulement pour le paramètre "glue interne" (OR
) mais aussi parce qu'il enveloppe ses expressions entre parenthèses et force la valeur initiale where()
expressions à mettre entre parenthèses pour isoler le regroupement logique. Si vous souhaitez écrire plusieurs expressions dans un appel where()
(ou select()
), je vous recommande de lui fournir un array()
de conditions.LIKE
dans la requête d'origine, mais elles ne sont pas utilisées. utilisé pour effectuer une correspondance partielle. Je ne sais pas s'il s'agissait d'une coïncidence ou d'une idée fausse sur la façon de comparer une colonne et une chaîne, mais ce n'est pas une bonne pratique et cela risque de semer la confusion dans l'esprit des futurs chercheurs. Si votre logique est de faire correspondre une chaîne complète, utilisez l'opérateur de comparaison =
. Si votre logique est de faire une correspondance partielle, utilisez LIKE
avec une chaîne incluant _
Ou %
. Consultez ce guide de la documentation Joomla syntaxe recommandée pour citer une variable dans votre expression LIKE
.AS
entre les tables/colonnes et leurs alias respectifs, utilisez-le.