web-dev-qa-db-fra.com

Comment réécrire une requête SQL avec CASE / WHEN au "format" basé sur Joomla

J'ai la requête SQL suivante à la base de données:

$jinput = JFactory::getApplication()->input;
$category_id = $jinput->get('virtuemart_category_id');
$db = JFactory::getDBO();
$query = $db->getQuery(true);
$query = 'SELECT b.`virtuemart_product_id`,
    (CASE 
        WHEN b.`product_override_price` > 0 THEN b.`product_override_price`
        WHEN b.`product_discount_id` > 0 THEN  b.`product_price` - (b.`product_discount_id` * b.`product_price` / 100)
        WHEN b.`product_price` < 1 THEN 1
        ELSE b.`product_price` 
        END) as final_price
    FROM #__virtuemart_product_categories as a
    LEFT JOIN #__virtuemart_product_prices as b ON b.`virtuemart_product_id` = a.`virtuemart_product_id`
    AND `virtuemart_category_id` = '.$category_id.'
    ORDER BY final_price ASC';
$db->setQuery($query);
$rows = $db->loadObjectList();

Comment réécrire les lignes avec CASE, WHEN ... THEN ... au "format" basé sur Joomla avec un filtrage comme:

$query->select('a.virtuemart_product_id');
$query->from('#__virtuemart_product_categories AS a');
$query->where($db->quoteName('virtuemart_category_id')." = ".$db->quote($category_id));
... // ???
$query->join('LEFT', '#__virtuemart_...');
$query->order('final_price ASC');
4
stckvrw

Je vais recommander cette syntaxe:

$db = JFactory::getDBO();
try {
    $query = $db->getQuery(true)
                ->select(
                    array(
                        $db->qn('b.virtuemart_product_id'),
                        "CASE WHEN " . $db->qn('b.product_override_price') . " > 0" .
                            " THEN " . $db->qn('b.product_override_price') .
                            " WHEN " . $db->qn('b.product_discount_id') . " > 0" .
                            " THEN " . $db->qn('b.product_price') . " - (" . $db->qn('b.product_discount_id') . " * " . $db->qn('b.product_price') . " / 100)" .
                            " WHEN " . $db->qn('b.product_price') . " < 1" .
                            " THEN 1" .
                            " ELSE " . $db->qn('b.product_price') .
                            " END AS " . $db->qn('final_price')
                    )
                )
                ->from($db->qn('#__virtuemart_product_categories', 'a'))
                ->innerJoin($db->qn('#__virtuemart_product_prices', 'b') . " ON " . $db->qn('b.virtuemart_product_id') . " = " . $db->qn('a.virtuemart_product_id'))
                ->where($db->qn('a.virtuemart_category_id') . " = " . (int)$category_id)
                ->order($db->qn('final_price'));
    echo $query->dump();    // of course, don't do this on your live/public site
    $db->setQuery($query);
    echo "<pre>";
        var_export($db->loadObjectList());
    echo "</pre>";
} catch (Exception $e) {
    echo "<div>", $e->getMessage(), "</div>";  // of course, don't do this on your live/public site
}
  • qn() est l'alias de quoteName() et est utilisé pour encapsuler les noms de tables, les noms de colonnes et leurs alias. Lorsque vous affectez un alias de table, écrivez-le simplement en tant que deuxième paramètre dans qn()
  • J'ai légèrement modifié la structure de votre requête et écrit votre $category_id Dans une clause WHERE, car j'estime qu'elle est plus appropriée et plus facile à lire.
  • Je préfère enchaîner les méthodes de getQuery() - parce que cela peut être fait.
  • Visuellement, la syntaxe CASE est rugueuse. J'ai essayé d'améliorer la lisibilité en alignant les mots-clés, mais d'autres développeurs peuvent préférer un style différent.
  • (int) Est appliqué à $category_id Par mesure de sécurité.
  • Les blocs try-catch() sont pratiques lors du débogage, il suffit de ne jamais afficher les requêtes ou les erreurs sur votre site actif.

Avec un category_id de 1, la requête rendue ressemble à ceci: (J'ai mis la valeur dump() en onglet)

SELECT `b`.`virtuemart_product_id`,
       CASE WHEN `b`.`product_override_price` > 0 THEN `b`.`product_override_price`
            WHEN `b`.`product_discount_id` > 0 THEN `b`.`product_price` - (`b`.`product_discount_id` * `b`.`product_price` / 100)
            WHEN `b`.`product_price` < 1 THEN 1 ELSE `b`.`product_price`
            END AS `final_price`
FROM `vwxyz_virtuemart_product_categories` AS `a`
INNER JOIN `vwxyz_virtuemart_product_prices` AS `b` ON `b`.`virtuemart_product_id` = `a`.`virtuemart_product_id`
WHERE `a`.`virtuemart_category_id` = 1
ORDER BY `final_price`

Et enfin, voici le db-fiddle pour prouver que cela fonctionne.

2
mickmackusa
$query->select('a.virtuemart_product_id')
->from('#__virtuemart_product_categories AS a')
->select('(CASE WHEN '.$db->qn('b.product_override_price').' > 0 
THEN '.$db->qn('b.product_override_price').
' WHEN '.$db->qn('b.product_discount_id').' > 0 
THEN '.$db->qn('b.product_price').' - ('.$db->qn('b.product_discount_id').' * '.$db->qn('b.product_price').' / 100) 
WHEN '.$db->qn('b.product_price').' < 1 
THEN 1 ELSE '.$db->qn('b.product_price').' END)
as '.$db->qn('final_price'));
2
Alexandr

Il n'y a pas de fonction basée sur Joomla pour la construction cas/when/then , vous devez utiliser une sélection simple avec mysql déclarations de cas en elle.

$query->select("(CASE ...) as final_price");

Jetez un œil à API JDatabaseQuery pour obtenir la liste complète des fonctions Joomla disponibles dans la base de données.

1
Kitase88