1. Base de datos
  2. Base de datos: Generador de consultas

Introducción

El generador de consultas de la base de datos de Laravel proporciona una interfaz fluida y conveniente para crear y ejecutar consultas de base de datos. Puede usarse para realizar la mayoría de las operaciones de base de datos en tu aplicación y funciona perfectamente con todos los sistemas de base de datos compatibles con Laravel.

El generador de consultas de Laravel utiliza la vinculación de parámetros de PDO para proteger tu aplicación contra ataques de inyección SQL. No es necesario limpiar o sanear cadenas que se pasen al generador de consultas como vinculaciones de consulta.

Advertencia PDO no admite la vinculación de nombres de columnas. Por lo tanto, nunca debes permitir que la entrada del usuario dicte los nombres de las columnas referenciadas por tus consultas, incluidas las columnas "order by".

Ejecución de Consultas de Base de Datos

Recuperar Todas las Filas de una Tabla

Puedes usar el método table proporcionado por la fachada DB para comenzar una consulta. El método table devuelve una instancia de generador de consultas fluido para la tabla dada, lo que te permite encadenar más restricciones en la consulta y finalmente recuperar los resultados de la consulta usando el método get:

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
 
class UserController extends Controller
{
/**
* Muestra una lista de todos los usuarios de la aplicación.
*/
public function index(): View
{
$users = DB::table('users')->get();
 
return view('user.index', ['users' => $users]);
}
}

El método get devuelve una instancia de Illuminate\Support\Collection que contiene los resultados de la consulta, donde cada resultado es una instancia del objeto PHP stdClass. Puedes acceder al valor de cada columna accediendo a la columna como una propiedad del objeto:

use Illuminate\Support\Facades\DB;
 
$users = DB::table('users')->get();
 
foreach ($users as $user) {
echo $user->name;
}

Nota Las colecciones de Laravel proporcionan una variedad de métodos extremadamente poderosos para mapear y reducir datos. Para obtener más información sobre las colecciones de Laravel, consulta la documentación de colecciones.

Recuperar una Única Fila / Columna de una Tabla

Si solo necesitas recuperar una sola fila de una tabla de base de datos, puedes usar el método first del facade DB. Este método devolverá un solo objeto stdClass:

$user = DB::table('users')->where('name', 'John')->first();
 
return $user->email;

Si no necesitas una fila completa, puedes extraer un solo valor de un registro utilizando el método value. Este método devolverá el valor de la columna directamente:

$email = DB::table('users')->where('name', 'John')->value('email');

Para recuperar una sola fila por el valor de su columna id, utiliza el método find:

$user = DB::table('users')->find(3);

Recuperar una Lista de Valores de Columna

Si deseas recuperar una instancia de Illuminate\Support\Collection que contenga los valores de una sola columna, puedes usar el método pluck. En este ejemplo, recuperaremos una colección de títulos de usuario:

use Illuminate\Support\Facades\DB;
 
$titles = DB::table('users')->pluck('title');
 
foreach ($titles as $title) {
echo $title;
}

Puedes especificar la columna que la colección resultante debería usar como sus claves proporcionando un segundo argumento al método pluck:

$titles = DB::table('users')->pluck('title', 'name');
 
foreach ($titles as $name => $title) {
echo $title;
}

Fragmentación de Resultados

Si necesitas trabajar con miles de registros de bases de datos, considera usar el método chunk proporcionado por la fachada DB. Este método recupera un pequeño fragmento de resultados a la vez y alimenta cada fragmento en un cierre para su procesamiento. Por ejemplo, recuperemos toda la tabla de users en fragmentos de 100 registros a la vez:

use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
 
DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) {
foreach ($users as $user) {
// ...
}
});

Puedes evitar que se procesen más fragmentos devolviendo false desde el cierre:

DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) {
// Procesa los registros...
 
return false;
});

Si estás actualizando registros de bases de datos mientras fragmentas resultados, tus resultados fragmentados podrían cambiar de maneras inesperadas. Si planeas actualizar los registros recuperados mientras fragmentas, siempre es mejor usar el método chunkById en su lugar. Este método paginará automáticamente los resultados según la clave primaria del registro:

DB::table('users')->where('active', false)
->chunkById(100, function (Collection $users) {
foreach ($users as $user) {
DB::table('users')
->where('id', $user->id)
->update(['active' => true]);
}
});

Advertencia Al actualizar o eliminar registros dentro del callback de chunk, cualquier cambio en la clave primaria o las claves foráneas podría afectar la consulta de chunk. Esto podría resultar en que los registros no se incluyan en los resultados fragmentados.

Transmisión de Resultados de forma Perezosa

El método lazy funciona de manera similar al método chunk en el sentido de que ejecuta la consulta en fragmentos. Sin embargo, en lugar de pasar cada fragmento a un callback, el método lazy() devuelve una LazyCollection, que te permite interactuar con los resultados como un solo flujo:

use Illuminate\Support\Facades\DB;
 
DB::table('users')->orderBy('id')->lazy()->each(function (object $user) {
// ...
});

Nuevamente, si planeas actualizar los registros recuperados mientras iteras sobre ellos, es mejor usar los métodos lazyById o lazyByIdDesc. Estos métodos paginarán automáticamente los resultados según la clave primaria del registro:

DB::table('users')->where('active', false)
->lazyById()->each(function (object $user) {
DB::table('users')
->where('id', $user->id)
->update(['active' => true]);
});

Advertencia Al actualizar o eliminar registros mientras iteras sobre ellos, cualquier cambio en la clave primaria o las claves foráneas podría afectar la consulta de chunk. Esto podría resultar en que los registros no se incluyan en los resultados.

Agregados

El generador de consultas también proporciona una variedad de métodos para recuperar valores agregados como count, max, min, avg y sum. Puedes llamar a cualquiera de estos métodos después de construir tu consulta:

use Illuminate\Support\Facades\DB;
 
$users = DB::table('users')->count();
 
$price = DB::table('orders')->max('price');

Por supuesto, puedes combinar estos métodos con otras cláusulas para ajustar cómo se calcula tu valor agregado:

$price = DB::table('orders')
->where('finalized', 1)
->avg('price');

Determinar si existen registros

En lugar de usar el método count para determinar si existen registros que coincidan con las restricciones de tu consulta, puedes usar los métodos exists y doesntExist:

if (DB::table('orders')->where('finalized', 1)->exists()) {
// ...
}
 
if (DB::table('orders')->where('finalized', 1)->doesntExist()) {
// ...
}

Declaraciones Select

Especificar una Cláusula Select

No siempre necesitas seleccionar todas las columnas de una tabla de base de datos. Utilizando el método select, puedes especificar una cláusula "select" personalizada para la consulta:

use Illuminate\Support\Facades\DB;
 
$users = DB::table('users')
->select('name', 'email as user_email')
->get();

El método distinct te permite forzar que la consulta devuelva resultados distintos:

$users = DB::table('users')->distinct()->get();

Si ya tienes una instancia del generador de consultas y deseas agregar una columna a su cláusula de selección existente, puedes usar el método addSelect:

$query = DB::table('users')->select('name');
 
$users = $query->addSelect('age')->get();

Expresiones Raw

En ocasiones, es posible que necesites insertar una cadena arbitraria en una consulta. Para crear una expresión de cadena sin procesar, puedes usar el método raw proporcionado por la fachada DB:

$users = DB::table('users')
->select(DB::raw('count(*) as user_count, status'))
->where('status', '<>', 1)
->groupBy('status')
->get();

Advertencia Las declaraciones sin procesar se inyectarán en la consulta como cadenas, por lo que debes tener mucho cuidado de evitar crear vulnerabilidades de inyección de SQL.

Métodos Raw

En lugar de usar el método DB::raw, también puedes usar los siguientes métodos para insertar una expresión sin procesar en varias partes de tu consulta. Recuerda, Laravel no puede garantizar que cualquier consulta que utilice expresiones sin procesar esté protegida contra vulnerabilidades de inyección SQL.

selectRaw

El método selectRaw se puede usar en lugar de addSelect(DB::raw(/* ... */)). Este método acepta un array opcional de vinculaciones como segundo argumento:

$orders = DB::table('orders')
->selectRaw('price * ? as price_with_tax', [1.0825])
->get();

whereRaw / orWhereRaw

Los métodos whereRaw y orWhereRaw se pueden usar para inyectar una cláusula "where" sin procesar en tu consulta. Estos métodos aceptan un array opcional de vinculaciones como su segundo argumento:

$orders = DB::table('orders')
->whereRaw('price > IF(state = "TX", ?, 100)', [200])
->get();

havingRaw / orHavingRaw

Los métodos havingRaw y orHavingRaw se pueden utilizar para proporcionar una cadena sin procesar como el valor de la cláusula "having". Estos métodos aceptan un array opcional de vinculaciones como su segundo argumento:

$orders = DB::table('orders')
->select('department', DB::raw('SUM(price) as total_sales'))
->groupBy('department')
->havingRaw('SUM(price) > ?', [2500])
->get();

orderByRaw

El método orderByRaw se puede utilizar para proporcionar una cadena sin procesar como el valor de la cláusula "order by":

$orders = DB::table('orders')
->orderByRaw('updated_at - created_at DESC')
->get();

groupByRaw

El método groupByRaw se puede utilizar para proporcionar una cadena sin procesar como el valor de la cláusula group by:

$orders = DB::table('orders')
->select('city', 'state')
->groupByRaw('city, state')
->get();

Uniones

Cláusula Inner Join

El generador de consultas también se puede utilizar para agregar cláusulas de unión a tus consultas. Para realizar un "inner join" básico, puedes usar el método join en una instancia del generador de consultas. El primer argumento pasado al método join es el nombre de la tabla a la que necesitas unirte, mientras que los argumentos restantes especifican las restricciones de columnas para la unión. Incluso puedes unir varias tablas en una sola consulta:

use Illuminate\Support\Facades\DB;
 
$users = DB::table('users')
->join('contacts', 'users.id', '=', 'contacts.user_id')
->join('orders', 'users.id', '=', 'orders.user_id')
->select('users.*', 'contacts.phone', 'orders.price')
->get();

Cláusula Left Join / Right Join

Si deseas realizar un "left join" o "right join" en lugar de un "inner join", utiliza los métodos leftJoin o rightJoin. Estos métodos tienen la misma firma que el método join:

$users = DB::table('users')
->leftJoin('posts', 'users.id', '=', 'posts.user_id')
->get();
 
$users = DB::table('users')
->rightJoin('posts', 'users.id', '=', 'posts.user_id')
->get();

Cláusula Cross Join

Puedes usar el método crossJoin para realizar una "cross join". Las "cross join" generan un producto cartesiano entre la primera tabla y la tabla unida:

$sizes = DB::table('sizes')
->crossJoin('colors')
->get();

Cláusulas de Unión Avanzadas

También puedes especificar cláusulas de unión más avanzadas. Para empezar, pasa un cierre como segundo argumento al método join. El cierre recibirá una instancia de Illuminate\Database\Query\JoinClause que te permite especificar restricciones en la cláusula "join":

DB::table('users')
->join('contacts', function (JoinClause $join) {
$join->on('users.id', '=', 'contacts.user_id')->orOn(/* ... */);
})
->get();

Si deseas usar una cláusula "where" en tus uniones, puedes usar los métodos where y orWhere proporcionados por la instancia JoinClause. En lugar de comparar dos columnas, estos métodos compararán la columna contra un valor:

DB::table('users')
->join('contacts', function (JoinClause $join) {
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.user_id', '>', 5);
})
->get();

Uniones con Subconsultas

Puedes usar los métodos joinSub, leftJoinSub y rightJoinSub para unir una consulta a una subconsulta. Cada uno de estos métodos recibe tres argumentos: la subconsulta, su alias de tabla y un cierre que define las columnas relacionadas. En este ejemplo, recuperaremos una colección de usuarios donde cada registro de usuario también contiene la marca de tiempo created_at de la publicación de blog más reciente del usuario:

$latestPosts = DB::table('posts')
->select('user_id', DB::raw('MAX(created_at) as last_post_created_at'))
->where('is_published', true)
->groupBy('user_id');
 
$users = DB::table('users')
->joinSub($latestPosts, 'latest_posts', function (JoinClause $join) {
$join->on('users.id', '=', 'latest_posts.user_id');
})->get();

Uniones

El generador de consultas también proporciona un método conveniente para "unir" dos o más consultas. Por ejemplo, puedes crear una consulta inicial y usar el método union para unirla con más consultas:

use Illuminate\Support\Facades\DB;
 
$first = DB::table('users')
->whereNull('first_name');
 
$users = DB::table('users')
->whereNull('last_name')
->union($first)
->get();

Además del método union, el generador de consultas proporciona un método unionAll. Las consultas combinadas con el método unionAll no eliminarán sus resultados duplicados. El método unionAll tiene la misma firma de método que el método union.

Cláusulas Básicas Where

Cláusulas Where

Puedes usar el método where del generador de consultas para agregar cláusulas "where" a la consulta. La llamada más básica al método where requiere tres argumentos. El primer argumento es el nombre de la columna. El segundo argumento es un operador, que puede ser cualquiera de los operadores admitidos por la base de datos. El tercer argumento es el valor con el que comparar el valor de la columna.

Por ejemplo, la siguiente consulta recupera usuarios donde el valor de la columna votes es igual a 100 y el valor de la columna age es mayor que 35:

$users = DB::table('users')
->where('votes', '=', 100)
->where('age', '>', 35)
->get();

Para mayor comodidad, si deseas verificar que una columna es = a un valor dado, puedes pasar el valor como segundo argumento al método where. Laravel asumirá que deseas usar el operador =:

$users = DB::table('users')->where('votes', 100)->get();

Como se mencionó anteriormente, puedes usar cualquier operador admitido por tu sistema de base de datos:

$users = DB::table('users')
->where('votes', '>=', 100)
->get();
 
$users = DB::table('users')
->where('votes', '<>', 100)
->get();
 
$users = DB::table('users')
->where('name', 'like', 'T%')
->get();

También puedes pasar un array de condiciones a la función where. Cada elemento del array debe ser un array que contenga los tres argumentos que se pasan típicamente al método where:

$users = DB::table('users')->where([
['status', '=', '1'],
['subscribed', '<>', '1'],
])->get();

Advertencia PDO no admite la vinculación de nombres de columnas. Por lo tanto, nunca debes permitir que la entrada del usuario dicte los nombres de las columnas referenciadas por tus consultas, incluidas las columnas "order by".

Cláusulas Or Where

Al encadenar llamadas al método where del generador de consultas, las cláusulas "where" se unirán utilizando el operador and. Sin embargo, puedes usar el método orWhere para unir una cláusula a la consulta usando el operador or. El método orWhere acepta los mismos argumentos que el método where:

$users = DB::table('users')
->where('votes', '>', 100)
->orWhere('name', 'John')
->get();

Si necesitas agrupar una condición "or" entre paréntesis, puedes pasar un cierre como primer argumento al método orWhere:

$users = DB::table('users')
->where('votes', '>', 100)
->orWhere(function (Builder $query) {
$query->where('name', 'Abigail')
->where('votes', '>', 50);
})
->get();

El ejemplo anterior producirá el siguiente SQL:

select * from users where votes > 100 or (name = 'Abigail' and votes > 50)

Advertencia Siempre debes agrupar las llamadas a orWhere para evitar comportamientos inesperados cuando se aplican ámbitos globales.

Cláusulas Where Not

Los métodos whereNot y orWhereNot se pueden usar para negar un grupo dado de restricciones de consulta. Por ejemplo, la siguiente consulta excluye productos que están en oferta o que tienen un precio inferior a diez:

$products = DB::table('products')
->whereNot(function (Builder $query) {
$query->where('clearance', true)
->orWhere('price', '<', 10);
})
->get();

Cláusulas Where JSON

Laravel también admite consultas de tipos de columna JSON en bases de datos que admiten tipos de columna JSON. Actualmente, esto incluye MySQL 5.7+, PostgreSQL, SQL Server 2016 y SQLite 3.39.0 (con la extensión JSON1). Para consultar una columna JSON, usa el operador ->:

$users = DB::table('users')
->where('preferences->dining->meal', 'salad')
->get();

Puedes usar whereJsonContains para consultar matrices JSON. Esta función no es compatible con versiones de bases de datos SQLite anteriores a 3.38.0:

$users = DB::table('users')
->whereJsonContains('options->languages', 'en')
->get();

Si tu aplicación utiliza las bases de datos MySQL o PostgreSQL, puedes pasar un array de valores al método whereJsonContains:

$users = DB::table('users')
->whereJsonContains('options->languages', ['en', 'de'])
->get();

Puedes usar el método whereJsonLength para consultar matrices JSON por su longitud:

$users = DB::table('users')
->whereJsonLength('options->languages', 0)
->get();
 
$users = DB::table('users')
->whereJsonLength('options->languages', '>', 1)
->get();

Cláusulas Where Adicionales

whereBetween / orWhereBetween

El método whereBetween verifica que el valor de una columna esté entre dos valores:

$users = DB::table('users')
->whereBetween('votes', [1, 100])
->get();

whereNotBetween / orWhereNotBetween

El método whereNotBetween verifica que el valor de una columna esté fuera de dos valores:

$users = DB::table('users')
->whereNotBetween('votes', [1, 100])
->get();

whereBetweenColumns / whereNotBetweenColumns / orWhereBetweenColumns / orWhereNotBetweenColumns

El método whereBetweenColumns verifica que el valor de una columna esté entre los dos valores de dos columnas en la misma fila de la tabla:

$patients = DB::table('patients')
->whereBetweenColumns('weight', ['minimum_allowed_weight', 'maximum_allowed_weight'])
->get();

El método whereNotBetweenColumns verifica que el valor de una columna esté fuera de los dos valores de dos columnas en la misma fila de la tabla:

$patients = DB::table('patients')
->whereNotBetweenColumns('weight', ['minimum_allowed_weight', 'maximum_allowed_weight'])
->get();

whereIn / whereNotIn / orWhereIn / orWhereNotIn

El método whereIn verifica que el valor de una columna dada esté contenido dentro del array dado:

$users = DB::table('users')
->whereIn('id', [1, 2, 3])
->get();

El método whereNotIn verifica que el valor de la columna dada no esté contenido en el array dado:

$users = DB::table('users')
->whereNotIn('id', [1, 2, 3])
->get();

También puedes proporcionar un objeto de consulta como segundo argumento del método whereIn:

$activeUsers = DB::table('users')->select('id')->where('is_active', 1);
 
$users = DB::table('comments')
->whereIn('user_id', $activeUsers)
->get();

El ejemplo anterior producirá el siguiente SQL:

select * from comments where user_id in (
select id
from users
where is_active = 1
)

Advertencia Si estás agregando una gran cantidad de enlaces de enteros a tu consulta, los métodos whereIntegerInRaw o whereIntegerNotInRaw se pueden usar para reducir significativamente el uso de memoria.

whereNull / whereNotNull / orWhereNull / orWhereNotNull

El método whereNull verifica que el valor de la columna dada sea NULL:

$users = DB::table('users')
->whereNull('updated_at')
->get();

El método whereNotNull verifica que el valor de la columna no sea NULL:

$users = DB::table('users')
->whereNotNull('updated_at')
->get();

whereDate / whereMonth / whereDay / whereYear / whereTime

El método whereDate se puede usar para comparar el valor de una columna con una fecha:

$users = DB::table('users')
->whereDate('created_at', '2016-12-31')
->get();

El método whereMonth se puede usar para comparar el valor de una columna con un mes específico:

$users = DB::table('users')
->whereMonth('created_at', '12')
->get();

El método whereDay se puede usar para comparar el valor de una columna con un día específico del mes:

$users = DB::table('users')
->whereDay('created_at', '31')
->get();

El método whereYear se puede usar para comparar el valor de una columna con un año específico:

$users = DB::table('users')
->whereYear('created_at', '2016')
->get();

El método whereTime se puede usar para comparar el valor de una columna con una hora específica:

$users = DB::table('users')
->whereTime('created_at', '=', '11:20:45')
->get();

whereColumn / orWhereColumn

El método whereColumn se puede usar para verificar que dos columnas son iguales:

$users = DB::table('users')
->whereColumn('first_name', 'last_name')
->get();

También puedes pasar un operador de comparación al método whereColumn:

$users = DB::table('users')
->whereColumn('updated_at', '>', 'created_at')
->get();

También puedes pasar un array de comparaciones de columnas al método whereColumn. Estas condiciones se unirán utilizando el operador and:

$users = DB::table('users')
->whereColumn([
['first_name', '=', 'last_name'],
['updated_at', '>', 'created_at'],
])->get();

Agrupación Lógica

A veces, es posible que necesites agrupar varias cláusulas "where" dentro de paréntesis para lograr el agrupamiento lógico deseado de tu consulta. De hecho, generalmente siempre debes agrupar las llamadas al método orWhere en paréntesis para evitar un comportamiento inesperado de la consulta. Para lograr esto, puedes pasar un cierre al método where:

$users = DB::table('users')
->where('name', '=', 'John')
->where(function (Builder $query) {
$query->where('votes', '>', 100)
->orWhere('title', '=', 'Admin');
})
->get();

Como puedes ver, pasar un cierre al método where instruye al generador de consultas a comenzar un grupo de restricciones. El cierre recibirá una instancia del generador de consultas que puedes usar para establecer las restricciones que deben estar contenidas dentro del grupo de paréntesis. El ejemplo anterior producirá el siguiente SQL:

select * from users where name = 'John' and (votes > 100 or title = 'Admin')

Advertencia Siempre debes agrupar las llamadas a orWhere para evitar comportamientos inesperados cuando se aplican ámbitos globales.

Cláusulas Where Avanzadas

Cláusulas Where Exists

El método whereExists te permite escribir cláusulas SQL "where exists". El método whereExists acepta un cierre que recibirá una instancia de generador de consultas, lo que te permite definir la consulta que se debe colocar dentro de la cláusula "exists":

$users = DB::table('users')
->whereExists(function (Builder $query) {
$query->select(DB::raw(1))
->from('orders')
->whereColumn('orders.user_id', 'users.id');
})
->get();

Alternativamente, puedes proporcionar un objeto de consulta al método whereExists en lugar de un cierre:

$orders = DB::table('orders')
->select(DB::raw(1))
->whereColumn('orders.user_id', 'users.id');
 
$users = DB::table('users')
->whereExists($orders)
->get();

Ambos ejemplos anteriores producirán el siguiente SQL:

select * from users
where exists (
select 1
from orders
where orders.user_id = users.id
)

Cláusulas Where con Subconsultas

En ocasiones, es posible que necesites construir una cláusula "where" que compare los resultados de una subconsulta con un valor dado. Puedes lograr esto pasando un cierre y un valor al método where. Por ejemplo, la siguiente consulta recuperará todos los usuarios que tienen una "membresía" reciente de un tipo dado;

use App\Models\User;
use Illuminate\Database\Query\Builder;
 
$users = User::where(function (Builder $query) {
$query->select('type')
->from('membership')
->whereColumn('membership.user_id', 'users.id')
->orderByDesc('membership.start_date')
->limit(1);
}, 'Pro')->get();

O bien, es posible que necesites construir una cláusula "where" que compare una columna con los resultados de una subconsulta. Puedes lograr esto pasando una columna, un operador y un cierre al método where. Por ejemplo, la siguiente consulta recuperará todos los registros de ingresos donde la cantidad es menor que el promedio;

use App\Models\Income;
use Illuminate\Database\Query\Builder;
 
$incomes = Income::where('amount', '<', function (Builder $query) {
$query->selectRaw('avg(i.amount)')->from('incomes as i');
})->get();

Cláusulas Where de Texto Completo

Advertencia Las cláusulas where de texto completo actualmente son compatibles con MySQL y PostgreSQL.

Los métodos whereFullText y orWhereFullText se pueden utilizar para agregar cláusulas "where" de texto completo a una consulta para columnas que tienen índices de texto completo. Estos métodos se transformarán en el SQL adecuado para el sistema de base de datos subyacente por Laravel. Por ejemplo, se generará una cláusula MATCH AGAINST para aplicaciones que utilizan MySQL:

$users = DB::table('users')
->whereFullText('bio', 'web developer')
->get();

Orden, Agrupación, Límite y Desplazamiento

Ordenar

El Método orderBy

El método orderBy te permite ordenar los resultados de la consulta por una columna dada. El primer argumento aceptado por el método orderBy debe ser la columna por la cual deseas ordenar, mientras que el segundo argumento determina la dirección de la ordenación y puede ser asc o desc:

$users = DB::table('users')
->orderBy('name', 'desc')
->get();

Para ordenar por varias columnas, simplemente puedes invocar orderBy tantas veces como sea necesario:

$users = DB::table('users')
->orderBy('name', 'desc')
->orderBy('email', 'asc')
->get();

Los Métodos latest y oldest

Los métodos latest y oldest te permiten ordenar fácilmente los resultados por fecha. Por defecto, el resultado se ordenará por la columna created_at de la tabla. O bien, puedes pasar el nombre de la columna por la cual deseas ordenar:

$user = DB::table('users')
->latest()
->first();

Orden Aleatorio

El método inRandomOrder se puede utilizar para ordenar los resultados de la consulta de forma aleatoria. Por ejemplo, puedes usar este método para obtener un usuario aleatorio:

$randomUser = DB::table('users')
->inRandomOrder()
->first();

Eliminar Ordenamientos Existentes

El método reorder elimina todas las cláusulas "order by" que se hayan aplicado previamente a la consulta:

$query = DB::table('users')->orderBy('name');
 
$unorderedUsers = $query->reorder()->get();

Puedes pasar una columna y dirección al llamar al método reorder para eliminar todas las cláusulas "order by" existentes y aplicar un orden completamente nuevo a la consulta:

$query = DB::table('users')->orderBy('name');
 
$usersOrderedByEmail = $query->reorder('email', 'desc')->get();

Agrupar

Los Métodos groupBy y having

Como podrías esperar, los métodos groupBy y having se pueden utilizar para agrupar los resultados de la consulta. La firma del método having es similar a la del método where:

$users = DB::table('users')
->groupBy('account_id')
->having('account_id', '>', 100)
->get();

Puedes usar el método havingBetween para filtrar los resultados dentro de un rango dado:

$report = DB::table('orders')
->selectRaw('count(id) as number_of_orders, customer_id')
->groupBy('customer_id')
->havingBetween('number_of_orders', [5, 15])
->get();

Puedes pasar varios argumentos al método groupBy para agrupar por varias columnas:

$users = DB::table('users')
->groupBy('first_name', 'status')
->having('account_id', '>', 100)
->get();

Para construir declaraciones having más avanzadas, consulta el método havingRaw.

Límite y Desplazamiento

Los Métodos skip y take

Puedes usar los métodos skip y take para limitar la cantidad de resultados devueltos por la consulta o para omitir un número determinado de resultados en la consulta:

$users = DB::table('users')->skip(10)->take(5)->get();

Alternativamente, puedes usar los métodos limit y offset. Estos métodos son funcionalmente equivalentes a los métodos take y skip, respectivamente:

$users = DB::table('users')
->offset(10)
->limit(5)
->get();

Cláusulas Condicionales

A veces, es posible que desees que ciertas cláusulas de consulta se apliquen a una consulta en función de otra condición. Por ejemplo, es posible que solo desees aplicar una declaración where si un determinado valor de entrada está presente en la solicitud HTTP entrante. Puedes lograr esto usando el método when:

$role = $request->string('role');
 
$users = DB::table('users')
->when($role, function (Builder $query, string $role) {
$query->where('role_id', $role);
})
->get();

El método when solo ejecuta el cierre dado cuando el primer argumento es true. Si el primer argumento es false, el cierre no se ejecutará. Entonces, en el ejemplo anterior, el cierre dado al método when solo se invocará si el campo role está presente en la solicitud entrante y evalúa a true.

Puedes pasar otro cierre como tercer argumento al método when. Este cierre solo se ejecutará si el primer argumento se evalúa como false. Para ilustrar cómo se puede usar esta característica, la usaremos para configurar el orden predeterminado de una consulta:

$sortByVotes = $request->boolean('sort_by_votes');
 
$users = DB::table('users')
->when($sortByVotes, function (Builder $query, bool $sortByVotes) {
$query->orderBy('votes');
}, function (Builder $query) {
$query->orderBy('name');
})
->get();

Declaraciones de Inserción

El generador de consultas también proporciona un método insert que se puede utilizar para insertar registros en la tabla de la base de datos. El método insert acepta un array de nombres de columna y valores:

DB::table('users')->insert([
'email' => '[email protected]',
'votes' => 0
]);

Puedes insertar varios registros a la vez pasando un array de arrays. Cada array representa un registro que se debe insertar en la tabla:

DB::table('users')->insert([
['email' => '[email protected]', 'votes' => 0],
['email' => '[email protected]', 'votes' => 0],
]);

El método insertOrIgnore ignorará errores al insertar registros en la base de datos. Al usar este método, debes tener en cuenta que los errores de registro duplicado se ignorarán y también se pueden ignorar otros tipos de errores según el motor de base de datos. Por ejemplo, insertOrIgnore omitirá el modo estricto de MySQL:

DB::table('users')->insertOrIgnore([
['id' => 1, 'email' => '[email protected]'],
['id' => 2, 'email' => '[email protected]'],
]);

El método insertUsing insertará nuevos registros en la tabla utilizando una subconsulta para determinar los datos que se deben insertar:

DB::table('pruned_users')->insertUsing([
'id', 'name', 'email', 'email_verified_at'
], DB::table('users')->select(
'id', 'name', 'email', 'email_verified_at'
)->where('updated_at', '<=', now()->subMonth()));

IDs de Autoincremento

Si la tabla tiene una ID con autoincremento, usa el método insertGetId para insertar un registro y luego recuperar la ID:

$id = DB::table('users')->insertGetId(
['email' => '[email protected]', 'votes' => 0]
);

Advertencia Cuando uses PostgreSQL, el método insertGetId espera que la columna de incremento automático se llame id. Si deseas recuperar la ID de un "sequence" diferente, puedes pasar el nombre de la columna como segundo parámetro al método insertGetId.

Inserciones con Conflicto

El método upsert intentará insertar registros que no existen y actualizar los registros que ya existen con nuevos valores que puedes especificar. El primer argumento del método consta de los valores a insertar o actualizar, mientras que el segundo argumento enumera la(s) columna(s) que identifican de manera única los registros dentro de la tabla asociada. El tercer y último argumento es un array de columnas que deben actualizarse si ya existe un registro coincidente en la base de datos:

DB::table('flights')->upsert(
[
['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
],
['departure', 'destination'],
['price']
);

En el ejemplo anterior, Laravel intentará insertar dos registros. Si ya existe un registro con los mismos valores de columna departure y destination, Laravel actualizará la columna price de ese registro.

Advertencia Todos los motores de base de datos excepto SQL Server requieren que las columnas en el segundo argumento del método upsert tengan un índice "primary" o "unique". Además, el controlador de base de datos MySQL ignora el segundo argumento del método upsert y siempre utiliza los índices "primary" y "unique" de la tabla para detectar registros existentes.

Declaraciones de Actualización

Además de insertar registros en la base de datos, el generador de consultas también puede actualizar registros existentes mediante el método update. El método update, al igual que el método insert, acepta un array de pares de columnas y valores que indican las columnas que se actualizarán. El método update devuelve la cantidad de filas afectadas. Puedes restringir la consulta update usando cláusulas where:

$affected = DB::table('users')
->where('id', 1)
->update(['votes' => 1]);

Actualizar o Insertar

A veces, es posible que desees actualizar un registro existente en la base de datos o crearlo si no existe un registro coincidente. En este escenario, se puede utilizar el método updateOrInsert. El método updateOrInsert acepta dos argumentos: un array de condiciones por las cuales encontrar el registro y un array de pares de columnas y valores que indican las columnas que se actualizarán.

El método updateOrInsert intentará localizar un registro coincidente en la base de datos utilizando las columnas y los valores del primer argumento. Si el registro existe, se actualizará con los valores del segundo argumento. Si no se puede encontrar el registro, se insertará un nuevo registro con los atributos combinados de ambos argumentos:

DB::table('users')
->updateOrInsert(
['email' => '[email protected]', 'name' => 'John'],
['votes' => '2']
);

Actualizar Columnas JSON

Al actualizar una columna JSON, debes usar la sintaxis -> para actualizar la clave adecuada en el objeto JSON. Esta operación es compatible con MySQL 5.7+ y PostgreSQL 9.5+:

$affected = DB::table('users')
->where('id', 1)
->update(['options->enabled' => true]);

Incremento y Decremento

El generador de consultas también proporciona métodos convenientes para incrementar o decrementar el valor de una columna dada. Ambos de estos métodos aceptan al menos un argumento: la columna a modificar. Se puede proporcionar un segundo argumento para especificar la cantidad por la cual se debe incrementar o decrementar la columna:

DB::table('users')->increment('votes');
 
DB::table('users')->increment('votes', 5);
 
DB::table('users')->decrement('votes');
 
DB::table('users')->decrement('votes', 5);

Si es necesario, también puedes especificar columnas adicionales para actualizar durante la operación de incremento o decremento:

DB::table('users')->increment('votes', 1, ['name' => 'John']);

Además, puedes incrementar o decrementar múltiples columnas a la vez utilizando los métodos incrementEach y decrementEach:

DB::table('users')->incrementEach([
'votes' => 5,
'balance' => 100,
]);

Declaraciones de Eliminación

El método delete del generador de consultas se puede utilizar para eliminar registros de la tabla. El método delete devuelve la cantidad de filas afectadas. Puedes restringir las declaraciones delete agregando cláusulas "where" antes de llamar al método delete:

$deleted = DB::table('users')->delete();
 
$deleted = DB::table('users')->where('votes', '>', 100)->delete();

Si deseas truncar una tabla completa, lo que eliminará todos los registros de la tabla y restablecerá el ID de autoincremento a cero, puedes usar el método truncate:

DB::table('users')->truncate();

Truncado de Tablas y PostgreSQL

Al truncar una base de datos PostgreSQL, se aplicará el comportamiento CASCADE. Esto significa que todos los registros relacionados con claves foráneas en otras tablas también se eliminarán.

Bloqueo Pesimista

El generador de consultas también incluye algunas funciones para ayudarte a lograr un "bloqueo pesimista" al ejecutar tus declaraciones select. Para ejecutar una declaración con un "bloqueo compartido", puedes llamar al método sharedLock. Un bloqueo compartido evita que las filas seleccionadas se modifiquen hasta que tu transacción se confirme:

DB::table('users')
->where('votes', '>', 100)
->sharedLock()
->get();

Alternativamente, puedes usar el método lockForUpdate. Un bloqueo "for update" evita que los registros seleccionados se modifiquen o se seleccionen con otro bloqueo compartido:

DB::table('users')
->where('votes', '>', 100)
->lockForUpdate()
->get();

Depuración

Puedes usar los métodos dd y dump mientras construyes una consulta para volcar las vinculaciones y SQL actuales. El método dd mostrará la información de depuración y luego detendrá la ejecución de la solicitud. El método dump mostrará la información de depuración pero permitirá que la solicitud continúe ejecutándose:

DB::table('users')->where('votes', '>', 100)->dd();
 
DB::table('users')->where('votes', '>', 100)->dump();

Los métodos dumpRawSql y ddRawSql se pueden invocar en una consulta para volcar el SQL de la consulta con todas las vinculaciones de parámetros correctamente sustituidas:

DB::table('users')->where('votes', '>', 100)->dumpRawSql();
 
DB::table('users')->where('votes', '>', 100)->ddRawSql();