Обработка Сложных операторов Where с Конструктором запросов PHP

Там существуют разработанные библиотеки конструктора запросов нескольких ActiveRecord. Некоторые являются одинокими, и некоторые приезжают встроенные в платформы. Однако они действительно испытывают затруднения из-за ГДЕ и пункты НАЛИЧИЯ когда дело доходит до сложного SQL. При откладывании других баз данных - я пытаюсь придумать MySQL и PostgreSQL, совместимый, ГДЕ () метод, который мог зафиксировать эти крушения существующего метода.

То, что следует, является длинным списком идей и примеров, показывающих лучшее, которое я мог придумать до сих пор. Однако я, может казаться, не решаю все варианты использования, и я чувствую, что мое частичное решение неаккуратно. Любой, который может ответить чем-то, что решает все эти проблемы, не только ответит на этот вопрос - но желание быть ответственным за решение проблемы, которая искала реализации 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)

Существует много общих форматов 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 (...) а также подготовленный оператор связал параметрические усилители ("?" И ": назовите").

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)

:UPDATE:

В течение моего вопроса я пришел к пониманию, что, ГДЕ и условия НАЛИЧИЯ только становятся более сложными глубже, Вы идете. Попытка абстрагировать даже 80% функций привела бы к крупной библиотеке только для ГДЕ и НАЛИЧИЕ. Как счет указывает, это просто не разумно для языка сценариев как PHP.

Решение состоит в том, чтобы только вручить ремесло ГДЕ часть Вашего запроса. Пока Вы используете " вокруг Ваших столбцов можно использовать то же, ГДЕ запрос в Postgre, SQLite и MySQL, так как они используют почти тот же синтаксис SQL. (Для MySQL Вы должны str_replace() их с галочкой').

Там прибывает точка, где абстракция повреждает больше, чем помогает, ГДЕ условия являются одним таким местом.

11
задан Community 23 May 2017 в 11:53
поделиться

3 ответа

I worked quite a bit on the Zend_Db library, which includes a PHP class for constructing SQL queries. I decided to punt on trying to handle every imaginable SQL syntax in WHERE and HAVING clauses, for several reasons:

  • PHP is a scripting language that parses and compiles code on every request (unless you use a bytecode cache). So the PHP environment is sensitive to bulky code libraries -- more so than Java or C# or Python or what have you. It's therefore a high priority to keep libraries as lean as we can.

    All of the Zend_Db library I worked on was about 2,000 lines of PHP code. By contrast, Java Hibernate is on the order of 118K lines of code. But that's not so much of an issue since a Java library is precompiled and doesn't have to be loaded on every request.

  • SQL expressions follow a generative grammar that is more compact, and easier to read and maintain that any of the PHP-based construction you showed. Learning the SQL expression grammar is far easier than learning an API that can simulate it. You end up supporting a "simplified grammar." Or else you start out that way, and find yourself coerced by your user community into Feature Creep until your API is unusably complex.

  • To debug an application that used such an API, you'd inevitably need access to the final SQL expression, so it's about the leakiest abstraction you can have.

  • The only advantage to using a PHP-based interface for SQL expressions would be that it assists code-completion in smart editors and IDE's. But when so many of the operators and operands use string constants like '>=', you spoil any code-completion intelligence.


update: I just read a good blog article "A Farewell to ORMs." The writer, Aldo Cortesi, suggests using the SQL Expression Language in Python's SQLAlchemy. Syntactic sugar and operator overloading that is standard in Python (but not supported in PHP) make this a very effective query-generating solution.

You might also look at Perl's DBIx::Class, but it ends up being pretty ugly.

8
ответ дан 3 December 2019 в 08:55
поделиться

API SQLAlchemy - лучший из тех, с которыми я когда-либо работал. Это Python-библиотека, но вы все равно можете вдохновиться ею. Это касается не только предложений WHERE - весь SQL-запрос (будь то select или DML) выражается с помощью легко изменяемой структуры данных.

(я имею в виду его набор инструментов SQL, а не ORM -части.: -)

1
ответ дан 3 December 2019 в 08:55
поделиться

Это часть моего класса ActiveRecord, я не обрабатываю подзапросы (я даже не беспокоюсь):

public function Having($data, $operator = 'LIKE', $merge = 'AND')
{
    if (array_key_exists('query', $this->sql) === true)
    {
        foreach ($data as $key => $value)
        {
            $this->sql['having'][] = ((empty($this->sql['having']) === true) ? 'HAVING' : $merge) . ' ' . $this->Tick($key) . ' ' . $operator . ' ' . $this->Quote($value);
        }
    }

    return $this;
}

public function Where($data, $operator = 'LIKE', $merge = 'AND')
{
    if (array_key_exists('query', $this->sql) === true)
    {
        foreach ($data as $key => $value)
        {
            $this->sql['where'][] = ((empty($this->sql['where']) === true) ? 'WHERE' : $merge) . ' ' . $this->Tick($key) . ' ' . $operator . ' ' . $this->Quote($value);
        }
    }

    return $this;
}

Еще одна вещь, которую вы можете рассмотреть, это наличие customHaving () и методы customWhere ().

2
ответ дан 3 December 2019 в 08:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: