Using DB::select() in Laravel with LIKE clause and a variable column name
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
Mastering Dynamic Queries: Using DB::select() for Dynamic Columns and LIKE Searches in Laravel
As senior developers, we often encounter scenarios where standard ORM features fall short. While Laravel's Eloquent and Query Builder are fantastic for standard CRUD operations, complex, highly dynamic queries—especially those involving variable column names or intricate database-specific functions like LIKE searches—often necessitate dropping down to raw SQL using the DB facade.
This post addresses a common stumbling block: how to safely construct dynamic SELECT statements with variable column names and pattern matching (LIKE) when you prefer the raw power of DB::select() over the Query Builder.
The Pitfall: Why Standard Binding Fails
The initial attempt often looks like this:
$column = 'refno';
$value = 'te';
// Attempt using standard binding fails because ? placeholders are for VALUES, not COLUMN NAMES.
$results = DB::select('select * from users where ? LIKE ?', array($column, $value));
As you discovered, attempting to bind variable column names directly into a prepared statement placeholder (?) results in an error like SQLSTATE[42P18]: Indeterminate datatype. This is because prepared statements are designed to safely substitute data values (strings, integers), not database identifiers (table or column names). The database engine cannot treat the variable $column as a safe placeholder for an identifier within a standard bind operation.
Similarly, trying to hardcode the value causes issues with escaping if you mix it into the string manually, leading to potential SQL injection vulnerabilities if not handled perfectly.
The Solution: Mixing Raw Strings and Bound Values Safely
When dealing with dynamic identifiers (like column names) alongside variable data values (like search terms), we must use a hybrid approach. We will construct the static parts of the query string ourselves, but we will still rely on Laravel's binding mechanism for the actual search values to maintain security.
The key is to treat the column name dynamically in the SQL string and bind only the user-supplied data into the LIKE comparison.
Step-by-Step Implementation
We need to ensure that the dynamic part (the column name) is properly quoted, and the search pattern (%value%) is safely bound.
Here is how you can achieve this robustly:
use Illuminate\Support\Facades\DB;
// Assume these variables are dynamically set from user input or logic
$column = 'refno'; // The variable column name we want to search on
$value = 'te'; // The search term
// 1. Construct the dynamic WHERE clause string using the variable column name.
// Note: We must manually quote the identifier, which is safe here because $column
// comes from a trusted source (or has been sanitized), but we treat it as raw SQL context.
$whereClause = sprintf('%s LIKE ?', $column);
// 2. Construct the full query string.
$sql = "SELECT * FROM users WHERE {$whereClause}";
// 3. Prepare the actual search pattern to be bound.
$searchPattern = '%' . $value . '%';
// 4. Execute the query using DB::select() with safe binding for the value.
// We use the raw SQL string, but we bind only the dynamic LIKE pattern.
$results = DB::select($sql, [$searchPattern]);
// Output the results
print_r($results);
Explanation of Best Practices
- Dynamic Identifiers vs. Values: The crucial distinction here is between identifiers (column names, table names) and values (data being compared). Identifiers must be baked into the string contextually, while values are passed via binding to prevent injection.
sprintffor String Construction: Usingsprintfallows us to reliably inject the dynamic column name ($column) directly into the SQL structure we are building.- Safe Binding for Search Terms: The actual search term,
$searchPattern, is constructed outside the primary SQL string and then passed as a separate array element toDB::select(). This ensures that the pattern is safely escaped by the underlying database driver when executed.
This technique allows you to leverage raw SQL's flexibility for complex joins or non-standard operations while maintaining the security provided by Laravel’s binding system, which is a core principle we strive for at laravelcompany.com.
Conclusion
When faced with dynamic database queries that involve both variable column names and pattern matching, avoid trying to force standard prepared statement placeholders (?) onto identifiers. Instead, embrace the power of string interpolation (like sprintf) to construct the structure of your query dynamically, and reserve the binding mechanism strictly for the data values you are comparing. This hybrid approach gives you the necessary flexibility without compromising security or readability.