2013-03-25 10 views
5

Ho creare un semplice tavolo di analoghi:Come ottenere in modo ricorsivo tutti gli analoghi dal tavolo di un articolo?

+----+-------+-------+ 
| id | sku_1 | sku_2 | 
+----+-------+-------+ 
| 1 | a1 | abcd | 
| 2 | a2 | a3 | 
| 3 | a3 | a1 | 
+----+-------+-------+ 
3 rows in set (0.00 sec) 

Cosa significa? Significa che il prodotto con l'articolo abcd ha un analogo all'articolo a1, altrimenti per esempio il prodotto con l'articolo a3 ha un analogo all'articolo a1.

Come ottenere in modo ricorsivo tutti i prodotti da questa tabella con un singolo articolo?

mie soluzioni è sbagliato:

// Small Class to get analogs of products 
class Analogs { 

    public function get_analogs($sku) 
    { 
     if (!$sku) return false; 

     $link = mysql_connect('localhost','',''); 
     mysql_select_db('test'); 

     $sku = mysql_real_escape_string($sku,$link); 

     $query = mysql_query("SELECT * FROM analogs WHERE sku_1='".$sku."' OR sku_2='".$sku."'"); 

     while($analogs[]=mysql_fetch_assoc($query)) 
     continue; 

     return $analogs;  
    } 


    public function MixedAnalogs($sku) 
    { 
     if (!$sku) return false; 

     $link = mysql_connect('localhost','',''); 
     mysql_select_db('test'); 

     $sku = mysql_real_escape_string($sku,$link); 

     $query = mysql_query("select sku_1 sku from analogs where sku_2 = '$sku' UNION 
           select sku_2 sku from analogs where sku_1 = '$sku'"); 

     while($analogs[]=mysql_fetch_assoc($query)) 
     continue; 

     return $analogs; 
    } 


} 

$mixed_analogs = AnalogsMix('abcd',$ids=array()); 

echo "<pre>"; 
print_r($mixed_analogs); 
echo "</pre>"; 

// Recursive function to get analogs of analog 
function AnalogsMix($sku,$ids=array()) 
{ 
    $class_analogs = new Analogs(); 
    $analogs = $class_analogs->get_analogs($sku); 

    foreach ($analogs as $analog) 
    { 
     $cross = null; 

     if ($analog['sku_1']==$sku) 
     { 
      $cross->sku = $analog['sku_2']; 
     } 
     else 
     { 
      $cross->sku = $analog['sku_1']; 
     } 

     $cross->id = $analog['id']; 

     if (!in_array($analog['id'],$ids)) 
     { 
      $ids[] = $analog['id']; 
      $mixed[] = AnalogsMix($cross->sku,$ids); 
     } 
    } 

    if (isset($mixed)) 
    { 
     return $mixed; 
    } 
    else 
    { 
     return false; 
    } 
} 
+2

1. Non si usa 'mysql_real_escape_string' per uscire correttamente da' $ sku'. 2. Si noti che le funzioni di 'mysql_ *' sono deprecate (si veda la [scatola rossa] (http://php.net/mysql_query)). 3. Cosa c'è che non va? Cosa emette al momento e cosa dovrebbe produrre? –

+0

Giusto per essere sicuro di capire la domanda, quale risultato ti aspetti dall'esempio che hai fornito? – Fabien

+0

@Marcel Korpel. Non lo userò sul mio vero server, è solo un esempio astratto.E @Fabien, Se metto 'abcd' in questo, devo prendere tutti gli analoghi, perché 'abcd' ha l'analogico come' a1', 'a1' ha l'analogico di' a3', 'a3' ha l'analogico come' a2' , quindi la funzione deve restituirmi tutti gli analoghi. – Smash

risposta

1

SQL UNION

select sku_1 sku from analogs where sku_2 = $yourid 
union 
select sku_2 sku from analogs where sku_1 = $yourid 

quindi si otterrà nei risultati solo gli ID di analoghi.

+0

E vedere quali altri compagni ti dicono delle funzioni corrette di escape e depravati :) – gaRex

+0

Ho aggiunto un metodo per questo. E sto ricevendo questo: $ class_analogs = new Analogs(); $ mixed_analogs = $ class_analogs-> MixedAnalogs ('abcd'); echo "

"; print_r($mixed_analogs); echo "
"; – Smash

+0

Array ( [0] => Array ( [SKU] => A1 ) [1] => ) – Smash

1

Ecco, suppongo che tu abbia tutte le tue coppie in un array. Ad esempio, per il tuo esempio, chiameresti analogsOf(array(array("a1", "abcd"), array("a2", "a3"), array("a3", "a1")), "abcd").

L'idea è quella di creare un elenco di analoghi contenenti inizialmente solo la stringa che si sta cercando e, ogni volta che si trova un analogo, lo si aggiunge all'elenco degli analoghi e si reiterano. Lo fai finché non hai ripetuto l'intera serie di coppie senza trovare nulla di nuovo.

function analogsOf(array $pairs, $key) { 
    $res = array($key); // The result, with only the given key 
    $i = 0;    // Index of the current item 
    $changed = false; // Have we added an item to $res during that iteration ? 

    while ($i < count($pairs)) { 
     $current = $pairs[$i]; 

     foreach ($res as $item) { 
      if (($current[0] === $item) && (!in_array($current[1], $res)) { 
       $res[] = $current[1]; 
       $i = 0; // Reiterate as $res changed 
      } 
      else if (($current[1] === $item) && (!in_array($current[0], $res)) { 
       $res[] = $current[0]; 
       $i = 0; // Reiterate as $res changed 
      } 
      else { 
       $i++; // Nothing found here, go to next item 
      } 
     } 
    } 

    return $res; 
} 

Si noti che questo codice non è stato testato, quindi ci potrebbe essere qualche bug qua e là, ma hai avuto l'idea. Nota anche che ho considerato che potresti mettere l'intero contenuto del database in un array, ma probabilmente non è possibile per ovvi motivi, quindi probabilmente dovrai adattare il codice sopra.

+0

È davvero scalabile? Caricamento di tutti i tuoi dati mysql in una matrice, rende mysql defunto. Si perde la velocità e l'efficienza di un database. – Husman

+0

Lo so, deve essere un livello e lo sarà. Ora è solo una prova. – Smash

+0

@Husman, come ho detto, no, questo non è molto scalabile come è, e devi trovare strategie di caching se i dati diventano sempre più grandi. Se il ridimensionamento diventa un problema, comunque, penso che memorizzare link analogici esplicitamente nel DB sarà di gran lunga l'opzione migliore. – Fabien

1

Ho trovato una soluzione per questo problema ma il problema principale in questo approccio è quello. può fare un ciclo come abcd->a1,a1->a3,a3->a2,a2->abcd. e rende la funzione ricorsiva infinita e php lancia un errore. quindi devi verificarlo se si tratta di un grande progetto.

nella mia soluzione lo considero genitore-> relazione figlio. e se un bambino trovato lo rende padre e controlla di nuovo e così via fino a quando non vi è alcun risultato.

let abcd è padre e dopo la prima esecuzione a1 è figlio e la relazione è abcd->a1. ma nella prossima chiamata a1 è genitore e dalla prima riga di tabella fornisce una nuova relazione che è a1->abcd e il ciclo è infinito. Per evitare che il check-in stessa riga io uso ID di ultima riga dalla base di dati ed è ora controllare riga in cui id! = ID (controllare sempre le altre righe)

questa è la funzione che scrivo, convertirlo in base alla classe e conservare il valore in array come ti piace. Io uso solo una stringa. sapevo che non era una buona soluzione, ma io lavoro bene.

<?php 

mysql_connect('localhost','',''); 
mysql_select_db('test'); 

function getSku($sku, $id, $rel = '') { 
    $query = mysql_query("SELECT * FROM analogs WHERE sku_1 = '$sku' AND id != '$id'"); 
    if (mysql_num_rows($query)) { 
     $row = mysql_fetch_assoc($query); 
     $sku = $row['sku_2']; //PARENT SKU 
     $id = $row['id']; //LAST ID 
     $rel .= $row['sku_1']. '-->' . $row['sku_2']. "<br>"; 

    } else { 
     $query = mysql_query("SELECT * FROM analogs WHERE sku_2 = '$sku' AND id != '$id'"); 
     if (mysql_num_rows($query)) { 
      $row = mysql_fetch_assoc($query); 
      $sku = $row['sku_1']; //PARENT SKU 
      $id = $row['id']; //LAST ID 
      $rel .=$row['sku_2']. '-->' . $row['sku_1']. '<br>'; 
     } else { 

      return (string)$rel; //NOTHING FOUND 
     } 
    } 
    return getSku($sku,$id,$rel);  

} 

echo $new = getSku('abcd','-1'); 
Problemi correlati