web-dev-qa-db-fra.com

Comment interroger certaines lignes d'une table en fonction d'autres lignes associées dans la même table?

J'essaie d'interroger mon jos_rsform_submission_values table pour FieldValue données en lignes avec un FieldName de Container# qui partage un SubmissionId avec une autre ligne où FieldValue est "en attente" et FieldName est "Status #" et le # après "Statut" = le # après "Conteneur".

Voici quelques exemples de données de table, afin que je puisse mieux exprimer ce que je recherche:

CREATE TABLE `jos_rsform_submission_values` (
  `SubmissionValueId` int(11) NOT NULL,
  `FormId` int(11) NOT NULL,
  `SubmissionId` int(11) NOT NULL DEFAULT '0',
  `FieldName` text NOT NULL,
  `FieldValue` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `jos_rsform_submission_values` (`SubmissionValueId`, `FormId`, `SubmissionId`, `FieldName`, `FieldValue`) VALUES
(129862, 28, 548, 'creationdate', '27-08-2018 10:30 AM'),
(129863, 28, 548, 'CustomerAccount', 'TEST'),
(129864, 28, 548, 'otheraccount', ''),
(129865, 28, 548, 'salesorderno', 'SO-00006296'),
(129866, 28, 548, 'DocumentUpload', '-'),
(129867, 28, 548, 'numberofbayan', '1'),
(129868, 28, 548, 'BayanNo', '189426'),
(129869, 28, 548, 'portofloading', 'Seaport'),
(129870, 28, 548, 'containers', '3'),
(129871, 28, 548, 'Container1', 'TTNU8517512'),
(129872, 28, 548, 'CargoDescription1', 'Chocolate'),
(129873, 28, 548, 'containertype1', 'Reefer'),
(129874, 28, 548, 'purchaseorder1', ''),
(129875, 28, 548, 'Location1', 'Jeddah'),
(129876, 28, 548, 'Status1', 'Return Empty'),
(129877, 28, 548, 'requesteddate1', '18-08-2018 07:00 AM'),
(129878, 28, 548, 'Container2', 'TCLU1256192'),
(129879, 28, 548, 'CargoDescription2', 'Chocolate'),
(129880, 28, 548, 'containertype2', 'Reefer'),
(129881, 28, 548, 'purchaseorder2', ''),
(129882, 28, 548, 'Location2', 'Jeddah'),
(129883, 28, 548, 'Status2', 'Return Empty'),
(129884, 28, 548, 'requesteddate2', '18-08-2018 07:00 AM'),
(129885, 28, 548, 'Container3', 'KKFU6780793'),
(129886, 28, 548, 'CargoDescription3', 'Chocolate'),
(129887, 28, 548, 'containertype3', 'Reefer'),
(129888, 28, 548, 'purchaseorder3', ''),
(129889, 28, 548, 'Location3', 'Jeddah'),
(129890, 28, 548, 'Status3', 'Pending'),
(129891, 28, 548, 'requesteddate3', '18-08-2018 07:00 AM'),
(129892, 28, 548, 'Container4', ''),
(129893, 28, 548, 'CargoDescription4', ''),
(129894, 28, 548, 'containertype4', ' '),
(129895, 28, 548, 'purchaseorder4', ''),
(129896, 28, 548, 'Location4', '-'),
(129897, 28, 548, 'Status4', ' '),
(129898, 28, 548, 'requesteddate4', ''),
(129899, 28, 548, 'Container5', ''),
(129900, 28, 548, 'CargoDescription5', ''),
(129901, 28, 548, 'containertype5', ' '),
(129902, 28, 548, 'purchaseorder5', ''),
(129903, 28, 548, 'Location5', '-'),
(129904, 28, 548, 'Status5', ' '),
(129905, 28, 548, 'requesteddate5', '')

ALTER TABLE `jos_rsform_submission_values`
  ADD PRIMARY KEY (`SubmissionValueId`),
  ADD KEY `FormId` (`FormId`),
  ADD KEY `SubmissionId` (`SubmissionId`),
  ADD KEY `SubmissionId_2` (`SubmissionId`),
  ADD KEY `SubmissionId_3` (`SubmissionId`);

ALTER TABLE `jos_rsform_submission_values`
  MODIFY `SubmissionValueId` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=133092;

De ce qui précède, seul SubmissionId548 a une valeur Status de en attente.

## SubmissionId    FieldName    FieldValue
## -----------------------------------------
##     548         Status1      Return Empty
##     548         Status2      Return Empty
##     548         Status3      Pending
##     548         Status4      
##     548         Status5

J'ai besoin de trouver la valeur Container # correspondante:

## SubmissionId    FieldName    FieldValue
## ----------------------------------------
##     548         Container3   KKFU6780793

Détails supplémentaires:

En ce qui concerne les données que j'ai soumises, les valeurs FieldName commencent par l'une des cinq chaînes suivantes: "Status", "Container", "ContainerType", "ExpDate" et "Commodity", suivies d'un nombre commençant par 1 mais peut atteindre 10.

Ma tentative de codage:

<?php 
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->select($db->quoteName(array('FieldName')));
$query->from($db->quoteName('#__rsform_submission_values'));
$query->where($db->quoteName('FieldName') . ' IN ("Status1","Status2","Status3","Status4" ,"Status5")');
$query->where($db->quoteName('FieldValue') . ' = "Pending"');

$db->setQuery($query);
$result = $db->loadColumn();

foreach($result as $value) {
        foreach($value as $key => $data) {
         $cut = substr($data, 6);
         $cut = "Container".$cut;
     }
}
?>

Vous remarquerez que j'ai utilisé substr pour supprimer les 6 premières lettres (Status) de chaque résultat. Cela permet d’obtenir uniquement le nombre restant (1, 2, 3, 4, etc., en fonction du statut "En attente"). J'ai aussi ajouté ensuite "Container" au début de chacun des nombres restants, puisque la "FieldValue" que je cherche est "Container1 à Container10" (selon le champ choisi). Rappelez-vous qu’il n’affiche que le statut "En attente", il peut donc s'agir d’un résultat ou de 10 résultats récupérés.

J'ai donc pensé que le moyen le plus simple consistait simplement à ajouter le préfixe requis à chaque élément du tableau; Ensuite, je sélectionne la valeur "FieldValue" dans la colonne "SubmissionValue", la valeur "FieldValue" étant égale à "FieldName" de l'un des résultats obtenus dans la requête précédente.

Voici le code pour ceci:

<?php
$query = $db->getQuery(true);
$query->select($db->quoteName(array('FieldValue')));
$query->from($db->quoteName('#__rsform_submission_values'));
$query->where($db->quoteName('FieldName') . ' IN ' . '(' . implode(',', $cut) . ')');

$db->setQuery($query);
$results = $db->loadObjectList();

foreach($results as $value) {
        foreach($value as $key => $data) {
        echo $data."<br />";
     }
}
?>

J'ai essayé d'utiliser "loadRow, loadColumn, loadResult", etc., et aucun d'entre eux ne fonctionne. Cela signifie que j'ai une erreur de syntaxe (1064) lorsque je charge la page.

Je ne suis pas sûr s'il s'agit d'un problème de "SubmissionId". Cependant, je ne sais pas comment incorporer le SubmissionId dans cette requête, car substr le supprimera simplement dans la première requête, puis ajoutera le préfixe devant lui, ce qu’il ne devrait pas faire.

En d'autres termes:

  • La requête 1 récupère tous les champs "Status" où la valeur est "En attente".
  • Je supprime le "Statut" de ces champs pour ne garder que le nombre restant.
  • J'ajoute ensuite un préfixe à ces numéros, en fonction du champ (énumérés ci-dessus dans un paragraphe)
  • J'ai maintenant "Container1" à la suite (en fonction de quel numéro il est; 1 - 10).
  • J'ai ensuite besoin de trouver la "FieldValue" pour chacun des résultats.
  • J'essaie d'utiliser la valeur $ cut dans un tableau implode, mais cela ne fonctionne pas.
2
MailBlade

Il est recommandé de minimiser le nombre d'appels à la base de données.

Votre logique dans vos deux requêtes peut être fusionnée en une comme celle-ci:

try {
    $db = JFactory::getDbo();
    $query = $db->getQuery(true)
                ->select("a.FieldName, a.FieldValue")
                ->from("#__rsform_submission_values a")
                ->innerJoin("#__rsform_submission_values b ON a.SubmissionId = b.SubmissionId AND a.FieldName = REPLACE(b.FieldName, 'Status', 'Container')")
                ->where(["b.FieldValue = 'Pending'", "b.FieldName LIKE 'Status%'"]);
    $db->setQuery($query);
    echo $query->dump();    // never show to public
    if (!$result = $db->loadAssocList()) {
        echo "No rows found";
    } else {
        echo "<pre>";
            var_export($result);
        echo "</pre>";
    }
} catch (Exception $e) {
    JFactory::getApplication()->enqueueMessage("Query Syntax Error: " . $e->getMessage(), 'error');    // never show to public
}

Sortie:

SELECT a.FieldName, a.FieldValue
FROM jos_rsform_submission_values a
INNER JOIN jos_rsform_submission_values b ON a.SubmissionId = b.SubmissionId AND a.FieldName = REPLACE(b.FieldName, 'Status', 'Container')
WHERE b.FieldValue = 'Pending' AND b.FieldName LIKE 'Status%'

array (
  0 => 
  array (
    'FieldName' => 'Container3',
    'FieldValue' => 'KKFU6780793',
  ),
)

En joignant la table à elle-même et en stipulant que vous n'êtes intéressé que par les données SubmissionId associées à "Statut # = 'En attente'", vous pouvez éviter deux accès à la base de données.


En ce qui concerne vos extraits originaux ... (que je ne vous recommande pas d'essayer de sauver)

Vous écrasiez votre $cut variable dans la boucle (ne pas insérer d’éléments dans un $cut tableau. Cela aurait dû être quelque chose comme:

foreach($result as $value) {
     $cut[] = "Container" . substr($value, 6);
}

Ensuite, dans la requête suivante, vous devez utiliser un guillemet simple pour envelopper vos éléments dans IN.

"... IN ('" . implode("','", $cut) . "')"

En ce qui concerne les performances, il existe différentes façons d’écrire la requête qui donnera le résultat souhaité, mais je ne sais pas combien de lignes vous avez dans votre projet pour démarrer un test d’analyse comparative précis. (et je n'ai pas le temps d'offrir ce service de toute façon)

Voici une autre requête qui devrait bien fonctionner:

SELECT a.SubmissionId, a.FieldName AS ContainerName, a.FieldValue AS ContainerValue
FROM jos_rsform_submission_values a
INNER JOIN (
    SELECT SubmissionId, SUBSTRING(FieldName, 7) AS StatusNum
    FROM jos_rsform_submission_values
    WHERE FieldValue = 'Pending'
      AND FieldName LIKE 'Status%'
) b ON a.SubmissionId = b.SubmissionId AND a.FieldName = CONCAT('Container', b.StatusNum)
2
mickmackusa

En supposant que ceci soit le code complet et que le deuxième extrait de code aille juste après le premier:

$db->loadColumn() renvoie un tableau simple mais vous exécutez des boucles imbriquées foreach qui, si le rapport d'erreurs strict était activé, générerait un avertissement:

Warning: Invalid argument supplied for foreach()

Pour cette raison, la variable $cut Est NULL. Vous devez également échapper des chaînes avec $db->quote().

Dans votre premier extrait, remplacez les boucles foreach par ceci:

foreach($result as $key => $value) {
    $result[$key] = $db->quote('Container' . substr($value, 6));
}

Et passez ensuite $result Au lieu de $cut À implode() dans le deuxième extrait.

0
Sharky