小编典典

使用PHP查询生成器处理复杂的WHERE子句

sql

有几个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”)。

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()将其打勾)。

有一种观点认为,抽象带来的伤害大于其带来的帮助,而在这种情况下,条件就是如此。


阅读 179

收藏
2021-04-15

共1个答案

小编典典

我在该Zend_Db库上做了很多工作,该库包括一个用于构造SQL查询的PHP。我决定尝试处理WHEREandHAVING子句中所有可以想象的SQL语法,原因如下:

  • PHP是一种脚本语言,可对每个请求进行解析和编译(除非您使用字节码缓存)。因此,PHP环境对庞大的代码库敏感-比Java或C#或Python或您拥有的代码库更敏感。因此,尽可能使库保持精益化是当务之急。

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,但最终结果很难看。

2021-04-15