有几个ActiveRecord样式的查询生成器库。有些是独立的,有些内置在框架中。但是,当涉及到复杂的SQL时,他们对WHERE和HAVING子句确实感到麻烦。将其他数据库放在一边- 我试图提出一种与MySQL和PostgreSQL兼容的WHERE()方法,该方法可以解决这些当前方法的不足。
接下来是一长串的想法和示例,这些列表显示了到目前为止我能提出的最好的想法和示例。但是,我似乎无法解决 所有用例, 而且我觉得我的部分解决方案草率。任何能够解决所有这些问题的人都可以回答,不仅会回答这个问题,而且还将负责解决已经困扰了几年PHP实现的问题。
普通运营商
= Equal <> Not Equal > Greater Than < Less Than >= Greater Than Or Equal <= Less Than Or Equal BETWEEN between values on right NOT logical NOT AND logical AND OR logical OR
示例where子句
SELECT ... FROM table... WHERE column = 5 WHERE column > 5 WHERE column IS NULL WHERE column IN (1, 2, 3) WHERE column NOT IN (1, 2, 3) WHERE column IN (SELECT column FROM t2) WHERE column IN (SELECT c3 FROM t2 WHERE c2 = table.column + 10) WHERE column BETWEEN 32 AND 34 WHERE column BETWEEN (SELECT c3 FROM t2 WHERE c2 = table.column + 10) AND 100 WHERE EXISTS (SELECT column FROM t2 WHERE c2 > table.column)
在不同的 当前 库中,where()子句使用许多常见的ActiveRecord格式。
$this->db->where(array('session_id' => '?', 'username' => '?')); $this->db->fetch(array($id, $username)); // vs with is_int($key) $this->db->where(array('session_id', 'username')); $this->db->fetch(array($id, $username)); // vs with is_string($where) $this->db->where('session_id', '?'); $this->db->where('username'); $this->db->fetch(array($id, $username)); // vs with is_array($value) $this->db->where('session_id', '?'); $this->db->where('username', array('Sam', 'Bob')); $this->db->fetch(array($id));
这是我到目前为止的最终格式。它应该处理分组(...) AND (...)以及准备好的语句绑定参数(“?”和“:name”)。
(...) AND (...)
function where($column, $op = '=', $value = '?', $group = FALSE){} // Single line $this->db->where('column > 5'); $this->db->where('column IS NULL'); // Column + condition $this->db->where('column', '='); // WHERE column = ? (prepared statement) $this->db->where('column', '<>'); // WHERE column <> ? (prepared statement) // Column + condition + values $this->db->where('column', '=', 5); // // WHERE column = 5 $this->db->where('column', 'IN', '(SELECT column FROM t2)'); // WHERE column IN (SELECT column FROM t2) $this->db->where('column', 'IN', array(1,2,3)); // WHERE column IN (1, 2, 3) $this->db->where('column', 'NOT IN', array(1,2,3)); // WHERE column NOT IN (1, 2, 3) // column + condition + values + group $this->db->where( array( array('column', '<', 20), array('column', '>', 10) ), NULL, NULL, $group = TRUE ); // WHERE (column < 20 AND column > 10)
:更新:
在我的问题过程中,我逐渐意识到,只要您走得更深,WHERE和HAVING条件只会变得越来越复杂。尝试抽象80%的功能将导致庞大的库仅用于WHERE和HAVING。正如Bill所指出的那样,对于像PHP这样的脚本语言来说,这是不合理的。
解决方案只是手工处理查询的WHERE部分。只要您"在列周围使用,就可以在Postgre,SQLite和MySQL中使用相同的WHERE查询,因为它们使用几乎相同的SQL语法。(对于MySQL,您必须str_replace()将其打勾)。
"
str_replace()
有一种观点认为,抽象带来的伤害大于其带来的帮助,而在这种情况下,条件就是如此。
我在该Zend_Db库上做了很多工作,该库包括一个用于构造SQL查询的PHP类。我决定尝试处理WHEREandHAVING子句中所有可以想象的SQL语法,原因如下:
Zend_Db
WHERE
HAVING
Zend_Db我研究的所有库都是大约2,000行PHP代码。相比之下,Java Hibernate的代码行数约为11.8万行。但这并不是什么大问题,因为Java库是预编译的,不必每次请求都加载。
SQL表达式遵循生成语法,该语法更加紧凑,并且与您显示的任何基于PHP的构造相比,都更易于阅读和维护。学习SQL表达式语法比学习可以模拟它的API容易得多。您最终支持“简化语法”。否则,您将以这种方式开始,并发现自己被用户社区强迫进入Feature Creep,直到您的API变得非常复杂为止。
要调试使用此类API的应用程序,您不可避免地需要访问最终的SQL表达式,因此它涉及的是您可能拥有的最泄漏的抽象。
将基于PHP的接口用于SQL表达式的唯一好处是,它可以帮助智能编辑器和IDE的代码完成。但是,当如此多的运算符和操作数使用像这样的字符串常量时'>=',就会破坏任何代码完成智能。
'>='
更新: 我刚刚读了一篇不错的博客文章“告别ORM”。作者Aldo Cortesi建议在Python的SQLAlchemy中使用SQL表达式语言。Python中标准的语法糖和运算符重载(但PHP不支持)使之成为非常有效的查询生成解决方案。
您可能还会看到Perl的DBIx :: Class,但最终结果很难看。