Skip to content

Raw Queries

Muhammet Şafak edited this page May 24, 2026 · 1 revision

Raw Queries

RawQuery is the explicit escape hatch for SQL fragments that should be inlined verbatim — no identifier escaping, no parameter binding. Use it where the fluent DSL does not (or should not) cover the case.

When to use it

  • Database functionsNOW(), CURRENT_TIMESTAMP, JSON_EXTRACT(…), INET_ATON(…), custom UDFs.
  • Dialect-specific operators — PostgreSQL ~, SQLite LIKE ESCAPE …, MySQL MATCH () AGAINST ().
  • Inline sub-queries — a static SQL fragment you have hand-written and want to embed without subQuery()'s closure indirection.
  • Anything the builder doesn't expose directly — set-returning functions, window functions, lateral joins.

When NOT to use it

🚨 Never embed unsanitized user input. RawQuery bypasses the parameter bag entirely — if you concatenate a $_GET value into the string, you've reintroduced SQL injection. Route user values through where() / set() / setParameter(). See Security.

Three input forms

RawQuery::__construct(mixed $rawQuery) accepts:

1. A string — used as-is

use InitORM\QueryBuilder\RawQuery;

$raw = new RawQuery('NOW()');
echo (string) $raw;
// NOW()

2. A Closure

The closure is invoked with a fresh QueryBuilder. It may either:

  • return a string — the string becomes the raw fragment;
  • return a stringable object — its __toString() is captured;
  • return nothing — the inner builder's __toString() is captured (the closure built a query against the supplied builder).
$raw = new RawQuery(function () {
    return 'CURRENT_TIMESTAMP';
});
// CURRENT_TIMESTAMP

$raw = new RawQuery(function (QueryBuilder $qb) {
    $qb->select('id')->from('users')->where('active', 1);
});
// SELECT `id` FROM `users` WHERE `active` = 1

3. Any other value — cast to string

$raw = new RawQuery(42);
echo (string) $raw;
// 42

The two factory shortcuts

// Inside a builder chain
$qb->from('users')->where('created_at', '>=', $qb->raw('NOW() - INTERVAL 7 DAY'));

// Outside a chain
$now = RawQuery::raw('NOW()');

$qb->raw() is the convenience for use inside chains; RawQuery::raw() is the static factory for use anywhere.

Where you can drop a RawQuery

Anywhere the builder accepts RawQuery|string (or RawQuery|<other>):

  • Projectionsselect($qb->raw('NOW() AS now')), selectAs($qb->raw('JSON_EXTRACT(payload, "$.name")'), 'name').
  • Tablesfrom($qb->raw('users FORCE INDEX (idx_status)')).
  • JOIN ONinnerJoin('posts', $qb->raw('posts.user_id = users.id')).
  • WHERE valueswhere('created_at', '<', $qb->raw('NOW()')).
  • BETWEEN boundsbetween('ts', $qb->raw('NOW() - INTERVAL 1 DAY'), $qb->raw('NOW()')).
  • IN valueswhereIn('id', $qb->raw('(SELECT user_id FROM bans)')).
  • SET column valuesset('updated_at', $qb->raw('NOW()')).
  • LIKE valueslike('name', $qb->raw("'custom%pattern'")) (opts out of the v2 wildcard auto-escape, see Security §V4).

Patterns

Database function on the right-hand side

$qb->set([
    'created_at' => $qb->raw('NOW()'),
    'token'      => $qb->raw('UUID()'),
    'name'       => 'Muhammet',
]);
// (`created_at`, `token`, `name`) VALUES (NOW(), UUID(), :name)

Dialect-specific WHERE

PostgreSQL ILIKE:

$qb->from('users')->where('email', $qb->raw('ILIKE :search'));
$qb->setParameter('search', '%@example.test');

Free-form HAVING

$qb->select('author_id')
   ->selectCount('id', 'post_count')
   ->from('post')
   ->groupBy('author_id')
   ->having($qb->raw('COUNT(id) > 5'));
// HAVING COUNT(id) > 5

Inline static sub-query

$qb->whereIn('user_id', $qb->raw('(SELECT id FROM admin_users)'));
// WHERE `user_id` IN (SELECT id FROM admin_users)

For dynamic inner SELECTs prefer [[Sub Queries|subQuery()]] — it gives you the fluent DSL inside the closure.

Closure that returns the builder it built

Useful for one-liner derived expressions:

$raw = $qb->raw(function (QueryBuilder $inner) {
    $inner->select('AVG(views)')->from('posts')->where('status', 1);
});

$qb->select('post.title')
   ->selectAs($raw, 'avg_views')
   ->from('post');

Updating an existing RawQuery

$raw = new RawQuery('NOW()');
$raw->set('CURRENT_TIMESTAMP');
echo (string) $raw;
// CURRENT_TIMESTAMP

set() returns the RawQuery for chaining.

Reading a RawQuery's contents

$raw = new RawQuery('NOW()');
echo $raw->get();   // 'NOW()'
echo (string) $raw; // 'NOW()'

__toString() and get() are equivalent.


Next: Parameters

Clone this wiki locally