5

好吧,情况就是这样,我有一个用 Zend_Framework 编写的应用程序,它与 MySQL 和 MSSQL 作为后端兼容。现在,ZF 非常擅长解决两种语言之间的许多 SQL 差异/差异,但我还没有弄清楚这一点。

目标是从表中随机选择 1 条记录,这是一个非常简单的语句。

例如,这里有一个 select 语句:

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

这非常适用于 MySQL 数据库表,因为 MySQL 的 sql 如下:

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

另一方面,现在 MSSQL 使用newid()函数进行随机化。

是否有某种帮助我可以传递给order()函数以使其意识到它必须使用正确的排序?我搜索了文档并在 zfforums 上找到了一些提示,但没有什么可靠的。

我确实发现的一件事是:

ORDER BY RANDOM() 不起作用- ZFForums.com

他们正在使用以下内容:

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

它可以工作......但我不希望通过键入它并在字符串上进行替换来构建我的选择语句,我试图将它保留在同一个 Zend_Db_Select 对象中。我也尝试过将 in 传递Zend_Db_Expr('RANDOM()')->order()on 语句中,但它失败了。他还发布了一个寻找答案的理论解决方案,但我不打算重写其中的函数,修改 $db->fetch() 调用。

有任何想法吗?

4

2 回答 2

14

您可以快速将该函数抽象为一个表 - 谁知道它正在使用哪个适配器:

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();

另外,我在某处发现了一篇丢失的文章,建议尝试以下操作:

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

颠覆 MSSQL 的查询优化器并欺骗它为每一行计算一个新值。

于 2009-09-25T02:28:33.097 回答
2

我将创建类 My_Db_Expr_Rand 扩展 Zend_Db_Expr。根据适配器,我将返回一个或另一个。

于 2009-09-24T22:00:27.293 回答