Как выбрать данные из нескольких таблиц с фильтрацией по определенным значениям

168
04 января 2019, 08:50

Считаю вопрос очень важным так как нигде ранее не встречал, поиск всех значений по одной большой таблице в которую они все записаны.

На сайтах, где была настроена хоть какая нибудь фильтрация выборка идет из таблицы где все поля раскиданы по колонкам и по нескольким таблицам, но не свалены в одну.

теперь суть моей задачи:

Есть три таблицы таблица с id анкет пользователей users_anket

вот ее скрин для общего представления

она связана с другой таблицей значений profile_fields_value по полю an_id,

а это сама таблица profile_fields_value

она связана с третьей таблицей названий полей profile_fields по полю pfld_id

вот ее скрин

для выборки данных из этих таблиц написал вот такой запрос:

SELECT *
    FROM gmcrm_users_anket table1 
    JOIN gmcrm_profile_fields_value table2 ON table1.an_id=table2.an_id 
    JOIN gmcrm_profile_fields table3 ON table2.pfld_id = table3.pfld_id
    WHERE table1.an_status = 1

в итоге в php на выходе получаю длинный массив который я уже группирую и обрабатываю.

Array
(
    [0] => Array
        (
            [an_id] => 2
            [an_status] => 1
            [an_date] => 1534938430
            [pfldv_id] => 79
            [pfld_id] => 1
            [uid] => 0
            [pfld_value] => Петров
            [pfld_status] => 1
            [p_f_m_str] => 
            [pfldv_revision] => 0
            [pfld_name] => last_name
            [pfild_group_id] => 1
            [pfild_group_name] => passport_data
            [pfild_group_status] => 1
        )
    [1] => Array
        (
            [an_id] => 2
            [an_status] => 1
            [an_date] => 1534938430
            [pfldv_id] => 80
            [pfld_id] => 2
            [uid] => 0
            [pfld_value] => Петр
            [pfld_status] => 1
            [p_f_m_str] => 
            [pfldv_revision] => 0
            [pfld_name] => name
            [pfild_group_id] => 1
            [pfild_group_name] => passport_data
            [pfild_group_status] => 1
        )
    [2] => Array
        (
            [an_id] => 2
            [an_status] => 1
            [an_date] => 1534938430
            [pfldv_id] => 81
            [pfld_id] => 3
            [uid] => 0
            [pfld_value] => Петровчи
            [pfld_status] => 1
            [p_f_m_str] => 
            [pfldv_revision] => 0
            [pfld_name] => otchestvo
            [pfild_group_id] => 1
            [pfild_group_name] => passport_data
            [pfild_group_status] => 1
        )
    [3] => Array
        (
            [an_id] => 2
            [an_status] => 1
            [an_date] => 1534938430
            [pfldv_id] => 82
            [pfld_id] => 4
            [uid] => 0
            [pfld_value] => 1
            [pfld_status] => 1
            [p_f_m_str] => 
            [pfldv_revision] => 0
            [pfld_name] => sex
            [pfild_group_id] => 1
            [pfild_group_name] => passport_data
            [pfild_group_status] => 1
        )
    [4] => Array
        (
            [an_id] => 2
            [an_status] => 1
            [an_date] => 1534938430
            [pfldv_id] => 83
            [pfld_id] => 5
            [uid] => 0
            [pfld_value] => 10,10,1925
            [pfld_status] => 1
            [p_f_m_str] => 
            [pfldv_revision] => 0
            [pfld_name] => date_of_birth
            [pfild_group_id] => 1
            [pfild_group_name] => passport_data
            [pfild_group_status] => 1
        )
    [5] => Array
        (
            [an_id] => 2
            [an_status] => 1
            [an_date] => 1534938430
            [pfldv_id] => 84
            [pfld_id] => 6
            [uid] => 0
            [pfld_value] => Россия
            [pfld_status] => 1
            [p_f_m_str] => 
            [pfldv_revision] => 0
            [pfld_name] => grajdanstvo
            [pfild_group_id] => 1
            [pfild_group_name] => passport_data
            [pfild_group_status] => 1
        )
    [6] => Array
        (
            [an_id] => 2
            [an_status] => 1
            [an_date] => 1534938430
            [pfldv_id] => 85
            [pfld_id] => 7
            [uid] => 0
            [pfld_value] => 4434
            [pfld_status] => 1
            [p_f_m_str] => 
            [pfldv_revision] => 0
            [pfld_name] => series_of_pass
            [pfild_group_id] => 1
            [pfild_group_name] => passport_data
            [pfild_group_status] => 1
        )
    [7] => Array
        (
            [an_id] => 2
            [an_status] => 1
            [an_date] => 1534938430
            [pfldv_id] => 86
            [pfld_id] => 8
            [uid] => 0
            [pfld_value] => 0884
            [pfld_status] => 1
            [p_f_m_str] => 
            [pfldv_revision] => 0
            [pfld_name] => num_of_pass
            [pfild_group_id] => 1
            [pfild_group_name] => passport_data
            [pfild_group_status] => 1
        )
    [8] => Array
        (
            [an_id] => 2
            [an_status] => 1
            [an_date] => 1534938430
            [pfldv_id] => 87
            [pfld_id] => 9
            [uid] => 0
            [pfld_value] => отделом уфмс россии
            [pfld_status] => 1
            [p_f_m_str] => 
            [pfldv_revision] => 0

и т.д

Вопрос: Как мне изменить запрос (вставить в него дополнительные параметры для поиска по конкретным значениям? то есть не только где table1.an_status = 1 (эта часть выборки была простой) но и

где например name='Петр' и last_name="Петров"

вижу что все нужные мне данные собраны в одном столбце таблицы profile_fields_value где объединяющим для них полем является an_id

Попробовал эти варианты

SELECT *
    FROM gmcrm_users_anket table1 
    JOIN gmcrm_profile_fields_value table2 ON table1.an_id=table2.an_id 
    JOIN gmcrm_profile_fields table3 ON table2.pfld_id = table3.pfld_id
    WHERE table1.an_status = 1 and table1.an_id in 
    (
        SELECT sub.an_id
        FROM gmcrm_profile_fields_value sub
        WHERE 
        (pfld_id=2 and pfld_value ='Петр') OR (pfld_id=1 and pfld_value='Петров')
        GROUP BY sub.an_id Having COUNT(sub.pfld_value) = 2
    )

и такой

SELECT *
    FROM gmcrm_users_anket table1 
    JOIN gmcrm_profile_fields_value table2 ON table1.an_id=table2.an_id 
    JOIN gmcrm_profile_fields table3 ON table2.pfld_id = table3.pfld_id
    WHERE table1.an_status = 1 and table1.an_id in 
    (
        SELECT sub.an_id
        FROM gmcrm_profile_fields_value sub
        WHERE (pfld_id, pfld_value) IN(
            (1, 'Петров'), (2, 'Петр')
        )
        GROUP BY sub.an_id Having COUNT(sub.pfld_value) = 2
    )

когда ищу Петрова Петра запрос выполняется 0,3с, но если я ищу Петрова Ивана запрос выполняется уже 15 секунд. То же самое и с Ивановым Иваном.(запрос выполняется почему то 15 сек)

Неужели при таком способе хранения данных в таблице извлечь из нее нужную группу значений нельзя?

Мне говорили что такой способ хранения в бд будет самым лучшим так как извлечь все нужные данные из одной таблицы быстрее через из n-ного количества связанных. Но пока пользы не увидел.

это план выполнения

Answer 1

Попробуйте написать ваше условие в подзапрос, типа такого:

    SELECT *
        FROM gmcrm_users_anket table1 
        JOIN gmcrm_profile_fields_value table2 ON table1.an_id=table2.an_id 
        JOIN gmcrm_profile_fields table3 ON table2.pfld_id = table3.pfld_id
        WHERE table1.an_status = 1 and table1.an_id in 
    ( SELECT sub.an_id FROM gmcrm_profile_fields_value sub 
        WHERE sub.pfld_value ='Петр' OR sub.pfld_value ="Петров"
       GROUP BY sub.an_id Having COUNT(sub.pfld_value) = 2 )
READ ALSO
Указание места хранения файла

Указание места хранения файла

С помощью кода ниже сохраняю картинки на хостинге и записываю их имена в БД

176
Как подписаться на изменение файла в файловой системе?

Как подписаться на изменение файла в файловой системе?

Хочу создать процесс, который посылал данные из файла, при изменении этих файловНа ум приходит только, в цикле на каждом тике проверять время...

168
Почему не загружается содержимое Iframe?

Почему не загружается содержимое Iframe?

до полной загрузки сайта фрейм загружается полностью, а после полной загрузки сайта содержимое фрейма не подгружается

139
Экранирование символов php

Экранирование символов php

Вопрос в следующем: Есть несколько строк кода для отправки через json (те

179