web-dev-qa-db-fra.com

Confusion sur l'utilisation de deux appels de méthode select () dans une requête

J'utilise les méthodes JDatabaseQuery de Joomla pour sélectionner des colonnes de deux tables jointes, mais je ne comprends rien à l'extrait de code suivant.

//Initialize variables.
$db = JFactory::getDbo();
$query = $db->getQuery(true);

//Create the base select statement.
$query->select('a.id as id, a.greeting as greeting, a.published as published')
      ->from($db->quoteName('#__diolegend','a'));

//Join over the categories.
$query->select($db->quoteName('c.title' ,'category_title'))
      ->join('LEFT',$db->quoteName('#__categories','c') . ' ON c.id =a.catid');

Voir dans la 2ème select(), il n'y a aucune mention de a.catid?

Comment peut-il être possible de récupérer a.catid? Nous ne l'avons pas sélectionné de nulle part.

2
William Zhao

Je pense que la méthode de requête de Joomla select() vous a dérouté. C’est une bonne raison pour laquelle je n’aime pas faire plusieurs appels select() - car seulement UN SELECT La clause est réellement générée.

Si vous appelez echo $query->dump(); immédiatement après la construction de votre requête, vous verrez la chaîne de requête suivante (avec votre préfixe de base de données à la place de #_):

SÉLECTIONNEZ a.id en tant qu'id, une salutation en tant que salutation, une.publiée telle que publiée, `c`.`title` AS` category_title`

DE `lmnop_diolegend` AS` a`

LEFT JOIN `lmnop_categories` AS` c` ON c.id = a.catid

Je veux dire, vous pouvez obtenir la même requête générée en appelant select() sur chaque nom de colonne.

->select('a.id AS id')
->select('a.greeting AS greeting')
->select('a.published AS published')
->select('c.title AS category_title')

Bien entendu, il est parfaitement correct de joindre deux tables de base de données à l’aide de colonnes que vous n’avez pas l’intention de renvoyer dans le jeu de résultats.

En joignant les deux tables, vous avez la possibilité de nommer une ou toutes les colonnes des deux tables impliquées dans la requête. En fait, il est préférable de NE PAS inclure de colonnes à moins que vous ne les utilisiez dans votre script. Utiliser * Est le moyen simple/bref de sélectionner toutes les colonnes d'une table interrogée, mais cela n'a pas de sens de demander à la base de données de renvoyer des données dont vous n'avez pas besoin.

Parfois, vous pouvez voir une erreur qui se plaint d'une colonne ne figurant pas dans la clause SELECT lorsque vous utilisez GROUP BY, Mais JOINs ne déposera pas cette réclamation.


Quelques remarques sur le code de bâtiment de votre requête:

  • En "chaînant" les méthodes à la déclaration initiale $query, Vous évitez de taper $query Plusieurs fois de plus pour chaque nouvel appel de méthode.
  • Lorsque vous utilisez des alias sur vos colonnes dans la clause SELECT, il est inutile de déclarer un alias s'il est identique à votre nom de colonne. * Les alias de table (a. Et c.) Ne sont pas utilisés lors de l'accès aux éléments du jeu de résultats.)
  • Pour éviter toute confusion entre le code de construction de la requête et la requête générée, je préfère utiliser select() une seule fois et lui donner une chaîne de colonnes unique de sorte que toutes les colonnes soient au même endroit dans le code.
  • Comme aucun de vos noms de colonne ou de table ne contient de caractères susceptibles de causer un problème/une erreur en SQL, vous pouvez omettre les appels quoteName() - cela ne signifie pas qu'il est dangereux de les conserver, mais simplement qu'ils sont inutiles.
  • Le mot clé AS n'est pas nécessaire dans l'extrait ci-dessous, mais je pense qu'il améliore la lisibilité.
  • Pour proposer des fonctionnalités de débogage simples/utiles à ma réponse, je vais inclure un bloc try{}catch{}, Un vidage de la requête rendue et une vérification de l'absence de lignes renvoyées.

Voici un extrait que j'ai testé pour réussir sur mon hôte local:

$db = JFactory::getDbo();
try {
    $query = $db->getQuery(true)
                ->select('a.id, a.greeting, a.published, c.title AS category_title')
                ->from("#__diolegend AS a")
                ->leftJoin("#__categories AS c ON c.id = a.catid");
    echo $query->dump();
    $db->setQuery($query);
    $resultset = $db->loadAssocList();
    if (!$resultset) {
        echo "No Rows In Resultset";
    } else {
        foreach ($resultset as $row) {
            echo "<div>";
                echo "<div>ID: {$row['id']}</div>";
                echo "<div>Greeting: {$row['greeting']}</div>";
                echo "<div>Published: {$row['published']}</div>";
                echo "<div>Category Title: {$row['category_title']}</div>";
            echo "</div>";
        }
    }
} catch (Exception $e) {
    echo "Syntax Error " , $e->getMessage();  // never show `$e->getMessage()` on a public site (only use privately / before your site is live)
}

Cela produira:

SELECT a.id, a.greeting, a.published, c.title AS category_title

FROM lmnop_diolegend EN TANT QUE

LEFT JOIN lmnop_categories AS c ON c.id = a.catid

puis un résultat défini comme:

ID: 1
Greeting: Hello
Published: 1
Category Title: English

ID: 2
Greeting: Bonjour
Published: 1
Category Title: French
1
mickmackusa

C’est simple, l’objet $ query utilisé pour sélectionner les données de la table #__deolegend puis, une fois encore sur le même objet $ query, un select () est appelé, ce qui les ajoutera aux champs à sélectionner, puis une jointure sur le #. Table __categories sur c.id et a.catid, ce qui signifie que le #__deolegend doit contenir un catid de colonne. Peu importe que vous deviez sélectionner la colonne pour appliquer la jointure. Aussi, je vous suggère d'imprimer l'objet $ query en utilisant:

echo $query;

Vous pouvez ainsi avoir une meilleure idée de la requête finale. Vérifiez également d’abord la structure des tables. Si vous pouvez partager vos découvertes à ce sujet ici, nous pourrons peut-être mieux vous aider. J'espère que cela t'aides

1
Pratyush

Je ne sais pas quelle est votre préoccupation réelle, ... mais maintenant, après avoir regardé un peu plus près de cette requête, je ne suis pas aussi certain de la nature de cette requête.

Je veux dire que...

La requête ci-dessus voulait être un SELECT avec un JOIN - mais la jointure se produit sur la même table: #__diolegend et cela n'a vraiment aucun sens.

Est-ce une erreur de copier/coller/typo, ou d'où avez-vous obtenu cette requête?


Hypothétiquement, la deuxième table devrait être quelque chose comme #__diolegend_categories ou juste #__categories et dans ce cas, Query aurait tenté de récupérer les données id, greeting et published de #__diolegend table avec la catégorie associée title à partir du #__categories table -
Joined sur l'ID de la catégorie existant dans les deux tables, en tant que clé primaire dans le #__categories table et en tant que clé étrangère dans le #__diolegend.

0
FFrewin