# Laravel whereRaw vs selectRaw: Best Practices for Raw SQL in the Query Builder

> Master Laravel whereRaw vs selectRaw for raw SQL in the query builder. Learn best practices for complex filtering and calculated columns, ensuring secure parameter binding.

- Repository: [Laravel/framework](https://github.com/laravel/framework)
- Tags: best-practices
- Published: 2026-02-16

---

**Use `whereRaw` to inject raw SQL conditions into the WHERE clause for complex filtering, and `selectRaw` to add calculated columns or database-specific functions to the SELECT list, always binding parameters to prevent SQL injection.**

When building complex database queries in the `laravel/framework` repository, developers often encounter scenarios that exceed the expressive capabilities of the standard query builder. Understanding how to safely implement a **where clause with raw SQL statements** using `whereRaw`, and how it architecturally differs from `selectRaw`, is essential for writing secure, maintainable Laravel applications.

## How whereRaw Works in the Query Builder

The `whereRaw` method allows you to inject a raw SQL string directly into the WHERE clause of your query. According to the Laravel source code, this method is defined in [`src/Illuminate/Database/Query/Builder.php`](https://github.com/laravel/framework/blob/main/src/Illuminate/Database/Query/Builder.php) around line 1233.

When you call `whereRaw`, the builder pushes an array containing the raw SQL onto the `$wheres` collection:

```php
['type' => 'raw', 'sql' => $sql, 'boolean' => $boolean]

```

The method then registers any supplied bindings via `addBinding`, ensuring that parameters remain separate from the SQL command itself. During query compilation, the `Grammar::whereRaw` method in [`src/Illuminate/Database/Query/Grammars/Grammar.php`](https://github.com/laravel/framework/blob/main/src/Illuminate/Database/Query/Grammars/Grammar.php) (around line 279) simply returns the raw SQL string while the grammar engine handles the bound parameters.

### Binding Safety with whereRaw

Always use parameter bindings with `whereRaw` to protect against SQL injection. The framework stores these bindings under the `'where'` key in the bindings array.

```php
// Safe: uses parameter binding
$users = DB::table('users')
    ->whereRaw('JSON_EXTRACT(meta, "$.age") > ?', [30])
    ->get();

// Unsafe: string concatenation
$users = DB::table('users')
    ->whereRaw("JSON_EXTRACT(meta, '$.age') > $age")
    ->get();

```

## How selectRaw Differs from whereRaw

While `whereRaw` targets the WHERE clause, `selectRaw` targets the SELECT list. Defined in [`src/Illuminate/Database/Query/Builder.php`](https://github.com/laravel/framework/blob/main/src/Illuminate/Database/Query/Builder.php) around line 348, this method creates a new `Expression` instance and adds it to the `$columns` collection.

The key architectural difference lies in the query phase each method affects:

- **`whereRaw`** filters which rows are returned (the WHERE clause)
- **`selectRaw`** determines what data is returned for each row (the SELECT clause)

Bindings for `selectRaw` are stored under the `'select'` key, separate from WHERE bindings.

### Practical selectRaw Usage

Use `selectRaw` for calculated columns, database-specific functions, or sub-queries in the SELECT list:

```php
// Calculated columns with database functions
$stats = DB::table('orders')
    ->select('customer_id')
    ->selectRaw('COUNT(*) as order_count')
    ->selectRaw('SUM(total) as lifetime_value')
    ->groupBy('customer_id')
    ->get();

// Using database-specific JSON functions
$users = DB::table('users')
    ->select('id')
    ->selectRaw('JSON_EXTRACT(preferences, "$.theme") as theme')
    ->get();

```

## Key Differences Between whereRaw and selectRaw

Understanding the distinct roles of these methods prevents architectural confusion when constructing queries.

| Aspect | `whereRaw` | `selectRaw` |
|--------|------------|-------------|
| **Target clause** | WHERE | SELECT |
| **Primary function** | Filters rows | Defines return columns |
| **Binding key** | `'where'` | `'select'` |
| **Compilation** | `Grammar::whereRaw` | `Expression` object in `$columns` |
| **Return impact** | Boolean filtering | Column values/expressions |

## Best Practices for Raw SQL in Where Clauses

When you need functionality beyond the standard query builder methods, follow these guidelines to maintain security and portability.

### Prefer Dedicated Builder Methods First

Before reaching for `whereRaw`, check if Laravel provides a dedicated method. The framework includes specialized methods for common operations that handle database-specific syntax automatically:

- `whereJsonContains()` for JSON queries
- `whereColumn()` for comparing columns
- `whereBitwise()` for bitwise operations
- `whereDate()`, `whereMonth()`, etc. for date filtering

Only use `whereRaw` when the builder lacks native support for your specific condition.

### Always Use Parameter Bindings

Never concatenate user input or variables directly into raw SQL strings. Laravel's binding system protects against SQL injection by separating data from commands.

```php
// Correct: parameterized query
$query->whereRaw('price > ? AND quantity < ?', [$minPrice, $maxQty]);

// Incorrect: string interpolation (vulnerable)
$query->whereRaw("price > $minPrice AND quantity < $maxQty");

```

### Mix Raw Methods with Standard Builder Chains

`whereRaw` and `selectRaw` integrate seamlessly with other query builder methods. You can combine them with standard `where()`, `join()`, and `orderBy()` calls:

```php
$results = DB::table('products')
    ->select('id', 'name')
    ->selectRaw('(price - cost) as margin')
    ->where('active', true)
    ->whereRaw('stock_level < reorder_point')
    ->orderBy('margin', 'desc')
    ->get();

```

### Document Database-Specific Dependencies

Raw SQL often uses database-specific functions like `JSON_EXTRACT` (MySQL) or `STRING_AGG` (PostgreSQL). When using these, document the dependency in comments or documentation to ensure portability concerns are visible during database migrations.

## Summary

- **`whereRaw`** injects raw SQL into the **WHERE** clause via [`src/Illuminate/Database/Query/Builder.php`](https://github.com/laravel/framework/blob/main/src/Illuminate/Database/Query/Builder.php), storing bindings under the `'where'` key and compiling through `Grammar::whereRaw` in [`src/Illuminate/Database/Query/Grammars/Grammar.php`](https://github.com/laravel/framework/blob/main/src/Illuminate/Database/Query/Grammars/Grammar.php).
- **`selectRaw`** adds raw expressions to the **SELECT** list, creating `Expression` objects stored in the `$columns` collection with bindings under the `'select'` key.
- **Security**: Always use parameter bindings with `whereRaw` to prevent SQL injection; never concatenate variables directly into raw SQL strings.
- **Portability**: Prefer dedicated builder methods (`whereJsonContains`, `whereColumn`) before resorting to raw SQL, and document any database-specific functions used in raw expressions.

## Frequently Asked Questions

### Is whereRaw safe from SQL injection?

**`whereRaw` is safe only when you use parameter bindings.** The method accepts an optional second argument for bindings, which Laravel processes through `addBinding` in [`src/Illuminate/Database/Query/Builder.php`](https://github.com/laravel/framework/blob/main/src/Illuminate/Database/Query/Builder.php) and separates from the SQL command during compilation in `Grammar::whereRaw`. If you concatenate variables directly into the SQL string, you bypass this protection and become vulnerable to SQL injection attacks.

### When should I use whereRaw instead of regular where clauses?

**Use `whereRaw` only when Laravel's dedicated query builder methods cannot express your condition.** According to the [`src/Illuminate/Database/Query/Builder.php`](https://github.com/laravel/framework/blob/main/src/Illuminate/Database/Query/Builder.php) source, you should first check for native methods like `whereJsonContains`, `whereColumn`, `whereBitwise`, or date-specific methods. Reserve `whereRaw` for complex JSON path queries, bitwise operations on unsupported databases, or custom database functions that lack builder abstractions.

### How do I combine whereRaw with other query builder methods?

**`whereRaw` integrates seamlessly with standard builder methods because it returns the Builder instance.** You can chain `whereRaw` with `where()`, `orWhere`, `join()`, `orderBy()`, and other methods just like any other query builder method. The raw condition gets added to the `$wheres` collection alongside standard conditions, and the grammar compiler processes them in order during SQL generation in [`src/Illuminate/Database/Query/Grammars/Grammar.php`](https://github.com/laravel/framework/blob/main/src/Illuminate/Database/Query/Grammars/Grammar.php).

### What is the difference between whereRaw and havingRaw?

**`whereRaw` filters rows before aggregation in the WHERE clause, while `havingRaw` filters results after aggregation in the HAVING clause.** In [`src/Illuminate/Database/Query/Builder.php`](https://github.com/laravel/framework/blob/main/src/Illuminate/Database/Query/Builder.php), `whereRaw` adds conditions to the `$wheres` array processed during the initial row filtering phase, whereas `havingRaw` adds to the `$havings` array processed after `GROUP BY` operations. Use `whereRaw` to filter which rows enter the calculation, and `havingRaw` to filter aggregated results like `SUM(total) > 1000`.