select(), addSelect(), selectRaw() — column selection
Concept
Column selection controls which columns are included in the SQL SELECT clause. Returning only needed columns reduces data transfer, memory usage, and can leverage covering indexes.
select(string|array ...$columns): Replace the current select with the given columns. Replaces any previous select() call.
addSelect(string|array ...$columns): Add columns to an existing select. Useful when building queries incrementally.
selectRaw(string $expression, array $bindings = []): Include a raw SQL expression in the SELECT list. Bindings are positional PDO placeholders.
DB::raw(string $expression): Create a raw SQL expression. Can be used in any clause. Be careful of SQL injection — only use with trusted values or bound parameters.
Column aliases: 'total_price as total', DB::raw('COUNT(*) as user_count').
Distinct: ->distinct() adds SELECT DISTINCT.
selectSub(Closure|Builder, string $alias): Use a subquery as a selected column.
Important: select() resets the column list. If middleware or a trait adds columns and you call select() later, previous columns are dropped. Use addSelect() to avoid this.
Code Example
<?php
use Illuminate\Support\Facades\DB;
// Select specific columns
$users = DB::table('users')
->select('id', 'name', 'email', 'created_at')
->get();
// Select with alias
$orders = DB::table('orders')
->select('id', 'user_id', 'total as order_total', 'status')
->get();
// $order->order_total
// addSelect — append without replacing
$query = DB::table('users')->select('id', 'name');
if ($needsEmail) {
$query->addSelect('email');
}
$users = $query->get();
// selectRaw — raw expression in SELECT
$stats = DB::table('orders')
->selectRaw('
COUNT(*) as total_orders,
SUM(total) as revenue,
AVG(total) as avg_order,
DATE(created_at) as order_date
')
->groupBy('order_date')
->get();
// selectRaw with bindings — prevent injection
$users = DB::table('users')
->selectRaw('id, name, DATEDIFF(NOW(), created_at) as days_since_joined')
->get();
// DB::raw in select array
$users = DB::table('users')
->select(['id', 'name', DB::raw('YEAR(created_at) as join_year')])
->get();
// distinct
$roles = DB::table('users')->select('role')->distinct()->pluck('role');
// ['admin', 'user', 'editor']
// Subquery as column — most recent order total for each user
$users = DB::table('users')
->select('id', 'name')
->selectSub(function($query) {
$query->from('orders')
->selectRaw('MAX(total)')
->whereColumn('user_id', 'users.id');
}, 'latest_order_total')
->get();
// $user->latest_order_total — without loading orders