#php #sql #laravel #eloquent
#php #sql #laravel #красноречивый
Вопрос:
Я использую Laravel Framework 6.16.0
и у меня есть две таблицы, logos
и companies
:
Логотипы:
Schema::create('logos', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('companies_id')->default('999999');
$table->string('logo_path')->nullable($value = true); // path to the logo image
$table->timestamps();
});
Компании:
Schema::create('companies', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('symbol'); // AAPL
$table->string('name'); // company name such as Apple Inc.
$table->timestamps();
});
Модели:
class Logo extends Model
{
protected $table = 'logos';
protected $guarded = ['id'];
public function company()
{
return $this->belongsTo(Company::class, 'companies_id');
}
}
class Company extends Model
{
protected $table = 'companies';
protected $guarded = ['id'];
}
Я хочу получить все символы, у которых нет логотипа в logo-table
, а логотип для 90 days
не обновлялся.
Я попробовал следующее:
$symbolsWithoutLogos = DB::table('companies')
>leftJoin('logos', 'companies.id', '=', 'logos.companies_id')
->whereDate('logos.updated_at', Carbon::now()->subDays(90))
->whereNull('companies.logo_image')
->orderBy('name', 'ASC')
->get('companies.*');
Результатом этого запроса является:
select `companies`.* from `companies` left join `logos` on `companies`.`id` = `logos`.`companies_id` where date(`logos`.`updated_at`) = ? order by `name` asc
Однако я не получаю результата при выполнении этого запроса, даже если в моей таблице companies достаточно записей:
Есть предложения, что я делаю неправильно?
Я ценю ваши ответы!
Комментарии:
1. Я думаю, вам следует исправить информацию, которую вы нам предоставляете. Потому что, во-первых, я вижу столбец «logo_path», а не столбец «logo_image», как вы пишете ниже в конструкторе. Во-вторых, в необработанном запросе Mysql я не вижу «logo_image» или «logo_path». Наконец, вы говорите о получении «символов», у которых нет логотипа, но которые последний раз обновляли логотип по крайней мере 90 дней назад, это противоречиво.
Ответ №1:
Вы можете достичь этого с помощью Eloquent вместо использования left join и DB facade.
Я предполагаю, что соотношение между Company и Logo равно 1: 1 или 1:n. Если мы предположим, что это 1: 1, то ваш запрос будет выглядеть следующим образом:
Company::whereHas('logo', function($query) {
return $query->where('date', '<', Carbon::now()->subDays(90));
})->orWhereDoesntHave('logo')->...
Вы должны проверить: Отсутствие связи с запросом
Пока мы следуем соглашению об именовании Laravel, нам не нужно указывать имя таблицы, Laravel определит это по имени модели.
Модель логотипа должна быть примерно такой:
class Logo extends Model
{
// protected $table = 'logos';
// not necessary, Laravel already knows to use logos table
protected $guarded = ['id'];
public function company()
{
// return $this->belongsTo(Company::class, 'companies_id');
// no need to specify foreign key if we follow naming convention
// foreign key should be {foreign_model_singular}_id
// in this case it is company_id
return $this->belongsTo(Company::class);
}
}
Модель Company также не требует указания имени таблицы, она уже знает, что это должны быть компании.
Модель компании:
class Company extends Model
{
// protected $table = 'companies';
protected $guarded = ['id'];
public function logo()
{
return $this->hasOne(Logo::class);
}
}
Пожалуйста, проверьте, как работают свойства $guarded и $fillable. Если только id установлен как защищенный, то все остальные свойства не защищены, не уверен, что это было вашим намерением.
Полный запрос должен быть:
Company::whereHas('logo', function($query) {
return $query->where('updated_at', '<', Carbon::now()->subDays(90));
})->orWhereDoesntHave('logo')
->orderBy('name', 'ASC')
->get();
Комментарии:
1. Пожалуйста, посмотрите мой обновленный вопрос с двумя моделями.
Ответ №2:
->whereDate(‘logos.updated_at’), где date сравнивает только часть даты столбца DateTime … попробуйте это с помощью toDateString() из carbon …
$symbolsWithoutLogos = DB::table('companies')
->leftJoin('logos', 'companies.id', '=', 'logos.companies_id')
->whereDate('logos.updated_at', Carbon::now()->subDays(90)->toDateString())
->whereNull('companies.logo_image')
->orderBy('name', 'ASC')->select('companies.*')
->get();