2009-09-24 3 views
5

Okay, hier ist die Situation, ich habe eine Anwendung in Zend_Framework geschrieben, die sowohl mit MySQL als auch mit MSSQL als Backend kompatibel ist. Nun, ZF ist ziemlich gut darin, viele der SQL-Diskrepanzen/Unterschiede zwischen den beiden Sprachen zu lösen, aber ich muss diese noch herausfinden.Zend_Db_Auswahl nach dem Zufallsprinzip, kompatibel in mssql/mysql

Ziel ist es, einen zufälligen Datensatz aus der Tabelle auszuwählen, was eine äußerst einfache Aussage ist.

Hier ist eine select-Anweisung zum Beispiel:

$sql = $db->select() 
     ->from("table") 
     ->order("rand()") 
     ->limit(1); 

Diese perfekt für die MySQL-Datenbank-Tabellen funktioniert, weil die SQL für MySQL ist wie folgt:

SELECT `table`.* FROM `table` ORDER BY rand() ASC 

Jetzt MSSQL auf der anderen Seite, verwendet die Funktion newid(), um eine Randomisierung durchzuführen.

Gibt es eine Art von Helfer, den ich in die order() Funktion übergeben kann, um es zu erkennen, dass es die richtige Reihenfolge verwenden muss? Ich habe die Dokumentation und die Zfforums durchsucht, ein paar Tipps gefunden, aber nichts Solides.

Eines der Dinge, die ich finden tat, war:

ORDER BY RANDOM() not working - ZFForums.com

Sie verwenden die folgenden:

$res = $db->fetchAll(
'SELECT * FROM table ORDER BY :random', 
array('random' => new Zend_Db_Expr('RANDOM()') 
); 

Es funktioniert ... aber ich bin nicht auf der Suche nach baue meine select-Anweisung auf, indem ich sie austippe und eine Ersetzung für die Zeichenfolge durchführe. Ich versuche, sie im selben Zend_Db_Select-Objekt zu behalten. Ich habe auch versucht, die Zend_Db_Expr('RANDOM()') in die ->order() auf der Anweisung zu übergeben, und es schlägt fehl. Er postuliert auch eine theoretische Lösung, um die Antwort zu finden, aber ich versuche nicht, die Funktion, in der sie sich befindet, neu zu schreiben, indem ich den Aufruf von $ db-> fetch() modifiziere.

Irgendwelche Ideen?

Antwort

14

Sie könnten schnell abstrakt die Funktion auf einen Tisch - wer es den Adapter weiß verwendet:

class MyTable extends Zend_Db_Table_Abstract { 
    public function randomSelect($select=null) { 
    if ($select === null) $select = $this->select(); 
    if (!$select instanceOf Zend_Db_Select) $select = $this->select($select); 
    $adapter = $this->getAdapter(); 
    if ($adapter instanceOf Zend_Db_Adapter_Mysqli) { 
     $select->order(new Zend_Db_Expr('RAND()')); 
    } else if ($adapter instanceOf Zend_Db_Adapter_Dblib) { 
     $select->order(new Zend_Db_Expr('NEWID()')); 
    } else { 
     throw new Exception('Unknown adapter in MyTable'); 
    } 
    return $select; 
    } 
} 

$someSelect = $table->select(); 
// add it to an existing select 
$table->randomSelect($someSelect); 

// or create one from scratch 
$select = $table->randomSelect(); 

Auch fand ich irgendwo einen Artikel, den ich verloren, die versuchen, so etwas wie empfohlen:

$select->order(new Zend_Db_Expr('0*`id`+RAND())); 

, um den MSSQL-Abfrageoptimierer zu unterwandern und einen neuen Wert für jede Zeile zu berechnen.

2

Ich würde Klasse erstellen My_Db_Expr_Rand erweitert Zend_Db_Expr. Basierend auf dem Adapter würde ich entweder das eine oder das andere zurückgeben.

+0

Ich mag es, aber ich denke, ich mag gnarf Idee ein bisschen mehr. Es reicht aus, den Table Abstract für eine zufällige Auswahl zu erweitern. – Jesta

+0

Ja, natürlich. Meine Lösung ist komplexer und kommt von der Sache, die Sie erstellen möchten ** EIN EXPRESSION ** basierend auf einem Adapter. Daher ist es im Allgemeinen für jedes andere Projekt wiederverwendbar ... Aber ich stimme zu, dass die Tabellenlösung einfacher ist ... –

+0

Am Ende zeigte er auch das Db_Expr, das Sie für MSSQL und MySQL verwenden können, ohne es modifizieren zu müssen in der Regel auch für jedes Projekt wiederverwendbar. – Jesta