2010-12-05 19 views
0

Je les tableaux suivants:Besoin d'aide avec MySQL que je crois implique une jointure réflexive

TABLE: Catégorie

catid catfatherid catname 
1   0 United States 
2   1 Arizona 
3   1 Arkansas 
4   1 California 

et TABLE: ad

adid catid  title 
1 2   Arizona Item 
2 3   Arkansas Item 
3 4   California Item 

Je peux les rejoindre sans aucun problème et trouver l'article que je cherche, par exemple:

SELECT category.catid, category.catfatherid, category.catname, A.adid, A.title 
FROM ad A 
LEFT JOIN category AS category ON A.catid = category.catid 
where category.catname LIKE '%%Arizona%%' 

Cependant, je dois également être en mesure de rechercher par "États-Unis" et avoir toutes les entrées dans la table d'annonces qui ont un Catid qui a également un catfatherid de cet élément apparaît également.

Des idées sur comment faire cela?

Table SQL ci-dessous ...

CREATE TABLE `ad` (
    `adid` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `catid` int(11) NOT NULL, 
    `title` varchar(50) NOT NULL DEFAULT '', 
    PRIMARY KEY (`adid`) 
); 

INSERT INTO `ad` (`adid`, `catid`, `title`) 
VALUES 
(1,2,'Arizona Item'), 
(2,3,'Arkansas Item'), 
(3,4,'California Item'); 

CREATE TABLE `category` (
    `catid` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `catfatherid` int(11) DEFAULT NULL, 
    `catname` varchar(50) NOT NULL DEFAULT '', 
    PRIMARY KEY (`catid`) 
); 

INSERT INTO `category` (`catid`, `catfatherid`, `catname`) 
VALUES 
(1,0,'United States'), 
(2,1,'Arizona'), 
(3,1,'Arkansas'), 
(4,1,'California'); 
+0

Votre hiérarchie comporte-t-elle un maximum de 2 niveaux? Sinon, vous pourriez envisager une représentation alternative. MySQL n'a pas de CTE récursif. –

+0

Oui. Idéalement, le pays aurait été dans sa propre table, mais le créateur de cette pensée ayant des pays, des États/provinces dans le même tableau la voie à suivre. – TWLATL

Répondre

1

* EDIT J'ai trouvé un moyen plus rapide et beaucoup mieux .. une requête .. Nécessite

Pour clarifier ce que la demande qu'il avait au-dessus: « Cependant, je dois aussi être en mesure pour rechercher par "États-Unis" et afficher toutes les entrées dans la table d'annonces qui ont un Catid qui a également un catfatherid de cet article. "

Donc, à la fois catid et catfatherid doivent être examinés pour trouver des enfants possibles.

SELECT search.catid search_father_id, search.catname search_father_name, 
     ad_cat.catid child_id, ad_cat.catname child_name, count(*) total 
     FROM ad 
       RIGHT JOIN category ad_cat ON ad_cat.catid = ad.catid, 
        category search 
      WHERE search.catname LIKE '%United States%' AND (ad.catid = search.catid OR ad_cat.catfatherid = search.catid) 
     GROUP BY ad.catid

La méthode ci-dessus est beaucoup mieux que ma tentative initiale. Il s'exécute et ne parcourt pas plusieurs fois, mais à la place il passe à travers et obtient tous les comptes sans avoir besoin de faire des requêtes supplémentaires. Cela permettra également de renvoyer les enfants des États-Unis ou si la recherche d'un État ne fera que renvoyer ces informations.

originale réponse ci-dessous:

SELECT ad.title, 
     p1.catid search_id, p1.catfatherid search_father_id, fc.catname search_fathername, p1.catname search_name, 
     p2.catname child_cat, p2.catid child_catid, count(*) total 
     FROM category p1, 
       category p2 RIGHT JOIN ad ON ad.catid = p2.catid, 
       category f RIGHT JOIN category fc ON fc.catfatherid = f.catid 
WHERE p1.catname LIKE '%United States%' AND 
     p2.catid=(SELECT catid FROM category WHERE catid=if(p1.catfatherid=0, p2.catid, p1.catid)) 
GROUP BY ad.catid ORDER BY search_name 

Le total dans cette requête est évidemment hors tension. Et vous demandera de faire une requête supplémentaire par résultat.

PHP CODE: 
    while($f=mysql_fetch_assoc($sql1)){ 
    $tq = mysql_query("select count(*) total from ad where catid='{$f['child_cat']}'"); 
    $t = mysql_fetch_assoc($tq); 
    echo $t['total']; //Gives you total per result; 
    } 

Je ne peux pas guarentee c'est la meilleure méthode car il ne semble être lourd car il semble tirer environ 8 + 4 + 4 rangs regardant le total et prend environ 0.9ms sur ce petit peu de Les données. (J'ai ajouté quelques lignes supplémentaires dans la catégorie 'ad table' de l'Arizona)

J'espère que quelqu'un d'autre ici peut prendre cela et optimiser cela. Je ne peux pas penser à un autre moyen en ce moment de le faire.

+0

Autre que le total, cela semble me donner ce dont j'ai besoin. Merci! – TWLATL

+0

Ma modification récente devrait résoudre ce problème. – Shauncs

0
SELECT category.catid, category.catfatherid, category.catname, A.adid, A.title 
FROM ad A 
LEFT JOIN category AS category ON A.catid = category.catid 
WHERE 
category.catfatherid = (select catfatherid 
FROM category WHERE catname LIKE '%United States%' limit 1) 

pourrait fonctionner avec une sous-sélection ou être à la peine de faire deux requêtes que serait plus léger sur le système.

+0

Votre requête ne semble renvoyer aucun résultat pour moi. – TWLATL

0
  1. Vous voulez donc inclure une annonce comme celle-ci?

    adid catid  title 
        4 1   USA Item1 
        5 1   USA Item2 
    

    utilisez cette requête:

    SELECT category.catid, 
         category.catfatherid, 
         category.catname, 
         a.adid, 
         a.title 
    FROM ad a 
         LEFT JOIN category AS category 
         ON a.catid = category.catid 
    WHERE category.catname LIKE '%%Arizona%%' 
         OR category.catid IN (SELECT catfatherid 
               FROM category 
               WHERE catname LIKE '%%Arizona%%') 
    
  2. Ou vous voulez inclure également les annonces de Arkansas Item et California Item qui appartiennent à la catégorie United States, catégorie donnée par LIKE?

    SELECT category.catid, 
         category.catfatherid, 
         category.catname, 
         a.adid, 
         a.title 
    FROM ad a 
         LEFT JOIN category AS category 
         ON a.catid = category.catid 
    WHERE category.catfatherid IN (SELECT catfatherid 
               FROM category 
               WHERE catname LIKE '%%Arizona%%')