Форум программистов, компьютерный форум, киберфорум
PHP: Laravel
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.95/21: Рейтинг темы: голосов - 21, средняя оценка - 4.95
0 / 0 / 1
Регистрация: 21.02.2010
Сообщений: 351

Как в Laravel eloquent сделать запрос с одним фильтром по многим полям ?

19.05.2020, 14:03. Показов 4599. Ответов 11
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет,

В Laravel 5.7/ mysql приложении я делаю форму фильтра с более 10 инпутами,
и один из них ($filter_search) должен сравниваться со всеми полями данных(string, number, date,
ссылки на другие таблицы таблицы) выходных данных.

Я сделал scope в модели таблицы и у меня возникла проблема как сделать поиск по
полю job_ref_no которое берется как подзапроз из другой таблицы:

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    public function scopeGetBySearch($query, $search = null)
    {
        if (empty($search)) {
            return $query;
        }
        $tb= with(new StorageSpace)->getTable();
        return $query->where(
            $tb.'.number',  $search
        ) ->orWhere(function ($query) use ($search, $tb) {
            $query->where( $tb.".notes",  'like',  '%'.$search.'%' )
                ->orWhere($tb.".selling_range", $search)
                    ->orWhere($tb.".actual_storage_rent", $search)
                        ->orWhere($tb.".insurance_vat", $search)
//                            ->havingRaw("job_ref_no", $search)
 
        })
Я старался создать нужный запрос вручную.
используя Laravel r:
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
        $storageSpacesCollection = StorageSpace
            ::getByStatus($filter_status)
            ->whereRaw('storage_spaces.id <= 8') // DEBUGGING
            ->getById($relatedStorageSpacesArray)
            ->getByLocationId($filter_location_id, 'warehouses')
            ->getByCapacityCategoryId($filter_capacity_category_id, 'storage_capacities')
            ->getByLevel($filter_level)
            ->getByNumber($filter_number, true)
            ->orderBy('storage_spaces.id', 'asc')
            ->getByStorageCapacityId($filter_storage_capacity_id)
            ->getByClientId($filter_client_id)
            ->getByColorId($filter_color_id)
            ->getBySearch($filter_search)
 
            ->leftJoin( 'storage_capacities', 'storage_capacities.id', '=', 'storage_spaces.storage_capacity_id' )
            ->leftJoin( 'warehouses', 'warehouses.id', '=', 'storage_spaces.warehouse_id' )
            ->leftJoin( 'clients', 'clients.id', '=', 'storage_spaces.client_id')
            ->select(
                "storage_spaces.*",
 
                \DB::raw( "CONCAT(storage_capacities.count, ' ', storage_capacities.sqft ) as storage_capacity_name" ),
 
                \DB::raw("( SELECT check_ins.job_ref_no FROM check_ins WHERE check_ins.storage_space_id=storage_spaces.id ORDER BY check_ins.id ASC limit 1 ) AS job_ref_no"),
 
                "warehouses.name as warehouse_name",
                "clients.full_name as client_full_name")
            ->get();
И в трассировке я вижу sql-запрос с with job_ref_no полем:
SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
   SELECT `storage_spaces`.*, CONCAT(storage_capacities.count, ' ', storage_capacities.sqft )     AS storage_capacity_name, (   SELECT check_ins.job_ref_no 
    FROM check_ins 
    WHERE check_ins.storage_space_id=storage_spaces.id 
    ORDER BY check_ins.id ASC LIMIT 1 )     AS job_ref_no, `warehouses`.`name`     AS `warehouse_name`, `clients`.`full_name`     AS `client_full_name` 
    FROM `storage_spaces` 
    LEFT JOIN `storage_capacities` ON `storage_capacities`.`id` = `storage_spaces`.`storage_capacity_id` 
    LEFT JOIN `warehouses` ON `warehouses`.`id` = `storage_spaces`.`warehouse_id` 
    LEFT JOIN `clients` ON `clients`.`id` = `storage_spaces`.`client_id` 
    WHERE storage_spaces.id <= 8     AND (`storage_spaces`.`number` = '999'     OR 
  
      (`storage_spaces`.`notes` LIKE '%999%'     OR 
       `storage_spaces`.`selling_range` = '999'     OR 
       `storage_spaces`.`actual_storage_rent` = '999'     OR 
       `storage_spaces`.`insurance_vat` = '999') ) 
    ORDER BY `storage_spaces`.`id` ASC
Пробую установить фильтр на job_ref_no поле вручную :
SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  SELECT `storage_spaces`.*, CONCAT(storage_capacities.count, ' ', storage_capacities.sqft )     AS storage_capacity_name, (   SELECT check_ins.job_ref_no 
    FROM check_ins 
    WHERE check_ins.storage_space_id=storage_spaces.id 
    ORDER BY check_ins.id ASC LIMIT 1 )     AS job_ref_no, `warehouses`.`name`     AS `warehouse_name`, `clients`.`full_name`     AS `client_full_name` 
    FROM `storage_spaces` 
    LEFT JOIN `storage_capacities` ON `storage_capacities`.`id` = `storage_spaces`.`storage_capacity_id` 
    LEFT JOIN `warehouses` ON `warehouses`.`id` = `storage_spaces`.`warehouse_id` 
    LEFT JOIN `clients` ON `clients`.`id` = `storage_spaces`.`client_id` 
    WHERE storage_spaces.id <= 8     AND (`storage_spaces`.`number` = '999'     OR 
  
      (`storage_spaces`.`notes` LIKE '%999%'     OR 
       `storage_spaces`.`selling_range` = '999'     OR 
       `storage_spaces`.`actual_storage_rent` = '999'     OR 
       `storage_spaces`.`insurance_vat` = '999' OR 
       job_ref_no = '999' )   // I added this line @
     ) 
    ORDER BY `storage_spaces`.`id` ASC
Но получаю ошибку :
Code
1
Error in query (1054): Unknown column 'job_ref_no' in 'where clause'
Почему ошибка и как это исправить с помощью eloquent ?

Спасибо!
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
19.05.2020, 14:03
Ответы с готовыми решениями:

Как реализовать такую архитектуру на Eloquent Laravel?
Есть проект, в нем такие роли - админ, врач, клиент. У клиента своя анкета, у врача своя. Про RBAC вопросов не задаю, тут мы просто...

Laravel- Eloquent "many to many". Как создать модель из дополнительной таблицы
Здравствуйте. Я новичок в фреймворках. Нужно сделать электронный документооборот. есть таблицы Сотрудники и Документы. У 1 документа...

Как лучше всего осуществлять связи Многие-ко-Многим (Laravel)
Читала про полиморфные связи - там все как-то мутновато пока-что. Есть еще какие-то варианты? Какой лучший? Например, надо связать...

11
30 / 20 / 12
Регистрация: 26.03.2020
Сообщений: 52
19.05.2020, 14:49
Если хотите значение из подзапроса использовать в where, то этот подзапрос и вставлять надо в where
0
0 / 0 / 1
Регистрация: 21.02.2010
Сообщений: 351
19.05.2020, 15:09  [ТС]
Видимо этот подзапрос должен быть внутри scopeGetBySearch ?
Можно чуть подробнее как это должно выглядить ? Или ссылочку на схожий пример ?
0
30 / 20 / 12
Регистрация: 26.03.2020
Сообщений: 52
19.05.2020, 15:19
Сначала с сырым sql попробуйте, а потом уже с конструктором запросов разбирайтесь.
Как-то так попробуйте сначала:
SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT `storage_spaces`.*, CONCAT(storage_capacities.count, ' ', storage_capacities.sqft )     AS storage_capacity_name, `warehouses`.`name`     AS `warehouse_name`, `clients`.`full_name`     AS `client_full_name` 
    FROM `storage_spaces` 
    LEFT JOIN `storage_capacities` ON `storage_capacities`.`id` = `storage_spaces`.`storage_capacity_id` 
    LEFT JOIN `warehouses` ON `warehouses`.`id` = `storage_spaces`.`warehouse_id` 
    LEFT JOIN `clients` ON `clients`.`id` = `storage_spaces`.`client_id` 
    WHERE storage_spaces.id <= 8     AND (`storage_spaces`.`number` = '999'     OR 
  
      (`storage_spaces`.`notes` LIKE '%999%'     OR 
       `storage_spaces`.`selling_range` = '999'     OR 
       `storage_spaces`.`actual_storage_rent` = '999'     OR 
       `storage_spaces`.`insurance_vat` = '999' OR 
       (SELECT check_ins.job_ref_no FROM check_ins WHERE check_ins.storage_space_id=storage_spaces.id ORDER BY check_ins.id ASC LIMIT 1) = '999')   // I added this line @
     ) 
    ORDER BY `storage_spaces`.`id` ASC
1
0 / 0 / 1
Регистрация: 21.02.2010
Сообщений: 351
19.05.2020, 17:17  [ТС]
Да спасибо за цу Я добавил в scope :

PHP
1
2
    ->orWhereRaw("(SELECT check_ins.job_ref_no FROM check_ins WHERE
       check_ins.storage_space_id=storage_spaces.id ORDER BY check_ins.id ASC LIMIT 1) = '".$search."'")
И вроде работает как надо.

Далее нужно сделать поиск по одному из телефонов(которых может быть несколько в связной таблице)
Это как ?
0
30 / 20 / 12
Регистрация: 26.03.2020
Сообщений: 52
19.05.2020, 17:26
Привязывайте таблицу телефонов через join и делайте where. В чём конкретно тут проблема? Просто из вашего стартпоста не очень понятен контекст вашей задачи, поэтому я не могу дать конкретный развёрнутый ответ
0
0 / 0 / 1
Регистрация: 21.02.2010
Сообщений: 351
20.05.2020, 13:55  [ТС]
есть таблица storage_spaces table, с полем
client_id (может быть пустым) - это ссылка на таблицу clients.
Каждый client может иметь несколько мейлов в таблице client_additive_emails с полями
client_id и email
Мне нужно по значению $search с введенным емейлом(вроде 'hgedsaemail3.com' ) получить все
storage_spaces у которых clients имею мейлы в таблице client_additive_emails.В моем запросе
$filter_search как раз и не находит данные в client_additive_emails



PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
        $storageSpacesCollection = StorageSpace
            ::getByStatus($filter_status)
            ->whereRaw('storage_spaces.id <= 8') // DEBUGGING
            ->getById($relatedStorageSpacesArray)
            ->getByLocationId($filter_location_id, 'warehouses')
            ->getByCapacityCategoryId($filter_capacity_category_id, 'storage_capacities')
            ->getByLevel($filter_level)
            ->getByNumber($filter_number, true)
            ->orderBy('storage_spaces.id', 'asc')
            ->getByStorageCapacityId($filter_storage_capacity_id)
            ->getByClientId($filter_client_id)
            ->getByColorId($filter_color_id) // ЭТО МОЙ SCOPE
 
            ->leftJoin( 'storage_capacities', 'storage_capacities.id', '=', 'storage_spaces.storage_capacity_id' )
            ->leftJoin( 'warehouses', 'warehouses.id', '=', 'storage_spaces.warehouse_id' )
            ->leftJoin( 'clients', 'clients.id', '=', 'storage_spaces.client_id')
 
            ->select(
                "storage_spaces.*",
                \DB::raw( "CONCAT(storage_capacities.count, ' ', storage_capacities.sqft ) as storage_capacity_name" ),
                \DB::raw("( SELECT check_ins.job_ref_no FROM check_ins WHERE check_ins.storage_space_id=storage_spaces.id ORDER BY check_ins.id DESC limit 1 ) AS job_ref_no"),
                "warehouses.name as warehouse_name",
                "clients.id as client_id",
                \DB::raw( "CONCAT( clients.id, ' ', clients.full_name ) as client_full_name" ) )
            ->get();
Подзавпрос в scope :
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    public function scopeGetBySearch($query, $search = null)
    {
        if (empty($search)) {
            return $query;
        }
        $search_is_is_valid_float = with(new StorageSpace)->isValidFloat($search);
 
        $tb= with(new StorageSpace)->getTable();
        return $query->where(
            $tb.'.number',  $search
        ) ->orWhere(function ($query) use ($search, $tb, $search_is_is_valid_float) {
            $query->where( $tb.".notes",  'like',  '%'.$search.'%' )
                ->orWhere("clients.full_name", $search)
                ->orWhereRaw("(SELECT check_ins.job_ref_no FROM check_ins WHERE check_ins.storage_space_id=storage_spaces.id ORDER BY check_ins.id ASC LIMIT 1) = '".$search."'");
 
            if($search_is_is_valid_float) {
                $query->orWhere("storage_capacities.count", $search);
                $query->orWhere($tb . ".selling_range", $search);
                $query->orWhere($tb . ".actual_storage_rent", $search);
                $query->orWhere($tb . ".insurance_vat", $search);
            } // if($search_is_is_valid_float) {
 
 
            // THAT SUBQUERY DOES NOT WORK:
            $query->orWhereIn('storage_spaces.client_id', function($query) use ($search){
                $query->select('client_additive_emails.client_id')
                      ->from("client_additive_emails")
                      ->where('client_additive_emails.client_id', "clients.id")
                      ->where('client_additive_emails.email', $search);
            });

в sql-trace я вижу :

SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
   SELECT `storage_spaces`.*, CONCAT(storage_capacities.count, ' ', storage_capacities.sqft )     AS storage_capacity_name, (   SELECT check_ins.job_ref_no 
    FROM check_ins 
    WHERE check_ins.storage_space_id=storage_spaces.id 
    ORDER BY check_ins.id DESC LIMIT 1 )     AS job_ref_no, `warehouses`.`name`     AS `warehouse_name`, `clients`.`id`     AS `client_id`, CONCAT( clients.id, ' ', clients.full_name )     AS client_full_name 
    FROM `storage_spaces` 
    LEFT JOIN `storage_capacities` ON `storage_capacities`.`id` = `storage_spaces`.`storage_capacity_id` 
    LEFT JOIN `warehouses` ON `warehouses`.`id` = `storage_spaces`.`warehouse_id` 
    LEFT JOIN `clients` ON `clients`.`id` = `storage_spaces`.`client_id` 
    WHERE storage_spaces.id <= 8     AND (`storage_spaces`.`number` = 'hgedsaemail3.com'     OR (`storage_spaces`.`notes` LIKE '%hgedsaemail3.com%'     OR `clients`.`full_name` = 'hgedsaemail3.com'     OR (  SELECT check_ins.job_ref_no 
    FROM check_ins 
    WHERE check_ins.storage_space_id=storage_spaces.id 
    ORDER BY check_ins.id ASC LIMIT 1) = 'hgedsaemail3.com'     OR `storage_spaces`.`client_id` IN (  SELECT `client_additive_emails`.`client_id` 
    FROM `client_additive_emails` 
    WHERE `client_additive_emails`.`client_id` = 'clients.id'     AND `client_additive_emails`.`email` = 'hgedsaemail3.com'))) 
    ORDER BY `storage_spaces`.`id` ASC
Я стрался отлаживать подзапрос с client id = 1885(если запустит запрос выше
с пустым $search тогда находится storage_spaces с client_id= 1885 в результирующих данных)
SQL
1
2
3
4
SELECT *
 FROM `client_additive_emails` 
    WHERE `client_additive_emails`.`client_id` = 1885    AND 
`client_additive_emails`.`email` = 'hgedsaemail3.com'
Возвращает 1 строку как я и ожидал

Ер что неправильно ?

Спасибо!
0
30 / 20 / 12
Регистрация: 26.03.2020
Сообщений: 52
20.05.2020, 15:59
Так а в чём вопрос?) Что именно не так работает?
0
0 / 0 / 1
Регистрация: 21.02.2010
Сообщений: 351
20.05.2020, 16:33  [ТС]
Не находит данные в client_additive_emails
0
30 / 20 / 12
Регистрация: 26.03.2020
Сообщений: 52
21.05.2020, 14:03
Что у вас хранится в поле check_ins.job_ref_no и почему вы делаете сравнение этого поля с email?
0
0 / 0 / 1
Регистрация: 21.02.2010
Сообщений: 351
21.05.2020, 17:06  [ТС]
В check_ins.job_ref_no - хранится номер документа(произвольная строка)
Как я писал сначала $filter_search - должен сравниваться со всеми полями данных(string, number, date,
ссылки на другие таблицы таблицы с мейлами) выходных данных.
0
30 / 20 / 12
Регистрация: 26.03.2020
Сообщений: 52
22.05.2020, 15:22
Лучший ответ Сообщение было отмечено mstdmstd как решение

Решение

У вас слишком монструозный запрос получается, там много лишнего. Его раза в 2, а то и 3, сократить можно.
Рекомендую пойти другим путём. Перенесите все where or в условия php внутри скоупа. Если у вас в $filter_search могут лежать любые данные, то передавайте вместе с этим параметром ещё тип поля (email, phone и т.д.). Тогда вы сможете внутри скоупа определить, по какому полю надо сделать where. Сильно упростите себе жизнь и оптимизируете запрос.

Если же это у вас общая строка поиска и вы тип передать не можете, то like вас не спасёт, и всё равно придётся полнотекстовый поиск через ElasticSearch или Sphinx делать. Иначе ваша база быстро упадёт от таких запросов
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
22.05.2020, 15:22
Помогаю со студенческими работами здесь

Как переделать запрос в цикле на один запрос с фильтром по массиву
Мне говорят: код неправильный, надо запрос ciblockelement::getlist c фильтром по разделу, который в цикле для каждого раздела выполняется...

Сортировка по многим полям в базе данных
В базе данных хранится N записей, вида (Name, a1, a2, …, ak) – во всех записях одинаковое число параметров. На вход задачи подается...

Как сформировать запрос к базе (многие ко многим)
Есть 3 таблицы: Роли id_role|name_role 1|admin 2|user Доступы id_access|name_access 1|create

Отправка сообщения (одним) сервером многим клиентам
Здравствуйте. Столкнулся с одним проблематичным заданием. Есть приложение клиент-сервер. Нужно с сервера отправить сообщение...

Как составить запрос к трём таблицам (многие ко многим)
Есть 3 таблицы: authors - список авторов книг books - список книг books_authors - таблица связи авторов с книгами ---- Таблица...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru