Поиск значений с разделителями-запятыми в базе данных с запросом SELECT MYSQL

У меня проблема с получением результатов из базы данных. У меня есть столбец под названием «Регионы», который в качестве значения содержит все регионы, выбранные пользователем через форму подписки на информационный бюллетень, с запятыми, например «Ближний Восток, Европа».

Я создаю фильтр, который должен будет получить список всех пользователей, которые регистрируются в определенном или нескольких регионах. Пользователи могут выбрать несколько регионов. Из внешнего интерфейса я получаю все выбранные регионы в этом формате «Глобальный, Ближний Восток», который мне нужно использовать в моем SQL-запросе, чтобы найти всех пользователей, у которых глобальный и Ближний Восток выбран в качестве выбранного региона.

Я пытался использовать FIND_IN_SET, но это не очень помогает. Пробовал ниже

 $trimmedRegions = rtrim($sortType,', ');

 $query = "SELECT * FROM health_alerts_subscribers
            WHERE FIND_IN_SET(Regions, $trimmedRegions)";

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


person Anahit DEV    schedule 22.02.2019    source источник
comment
Лучшим решением было бы реорганизовать вашу базу данных и использовать отдельную таблицу и таблицу ссылок для хранения этих данных. Столбцы, содержащие текстовые данные с разделителями, всегда будут вызывать у вас больше сердечной боли в конце, чем потратить несколько минут на правильное проектирование базы данных.   -  person RiggsFolly    schedule 22.02.2019
comment
значение содержит все регионы, которые пользователь выбрал с помощью формы подписки на рассылку новостей, разделенные запятыми — я думаю, вы сейчас сожалеете об этом дизайнерском решении. Данные зависят от ключа [1NF], всего ключа [2NF] и ничего, кроме ключа [3NF], поэтому помогите мне, Codd. Как ни странно, результат #1 в Google для ключа весь ключ и ничего, кроме перехода на другой ТАК вопрос о нормализации данных.   -  person CD001    schedule 22.02.2019
comment
FIND_IN_SET должно работать. Можете ли вы поделиться, как он использовался и как он работал? Я бы пошел по нормализованному маршруту, данные с разделителями всегда будут вызывать проблемы.   -  person user3783243    schedule 22.02.2019
comment
@user3783243 user3783243 я обновил свой вопрос. Итак, вы предлагаете хранить все регионы отдельно и иметь такие значения, как «да» или «нет»?   -  person Anahit DEV    schedule 22.02.2019
comment
Я думаю, что если вам нужны все строки из глобального, вы можете просто использовать %Global%, поэтому вам нужно будет выполнить запрос для каждого региона.   -  person Vidal    schedule 22.02.2019
comment
@ Видал, что, если у меня есть несколько вариантов фильтра, таких как «Глобальный» и «Европа»?   -  person Anahit DEV    schedule 22.02.2019
comment
см. мой ответ, вы делаете 2 лайка, где регион нравится (%Global%) и регион нравится (%Europe%)   -  person Vidal    schedule 22.02.2019
comment
Вам нужен FIND_IN_SET для каждого отдельного значения. WHERE FIND_IN_SET(Regions, 'Middle East') and FIND_IN_SET(Regions, 'Global'). Я бы сделал другую таблицу, которая имеет отношение к каждой записи.   -  person user3783243    schedule 22.02.2019


Ответы (4)


Я рекомендую то, что говорит пользователь 3783243. Я бы выбрал FIND_IN_SET. Вот пример.

SELECT {columns} FROM {table} WHERE FIND_IN_SET({item_to_search}, {comma-delimited column})

Лучшим способом было бы создать таблицу regions и добавить свои регионы, а затем создать связанную таблицу с именем regionRelation (пример), а затем добавить идентификатор из региона и связанной таблицы (как много для много)

Table structure example

Table region
id,region
1, Middle East
2, Global

Table user
id,name
1, John
2, Jan

Table userRegion
userId,regionId
1,1
2,1

SELECT user.id,user.name,region.region from user
left join userRegion ON region.userId=user.id
left  join region
where region.region in('Middle East','Global');

В раскрывающемся списке просто выберите все регионы, и когда пользователь выберет нужные, вы сохраните его в таблице userRegion с помощью INSERT INTO userRegion (userid,regionId) (1,2 ); и так далее.

person blupointmedia    schedule 22.02.2019
comment
на место item_to_search что поставить? строка с выбранными областями, разделенными запятыми? и {столбец с разделителями-запятыми} указать имя столбца? - person Anahit DEV; 22.02.2019
comment
Так вы рекомендуете или нет? - person Strawberry; 22.02.2019
comment
Если у меня будет каждый регион в виде отдельного столбца со значением «да» или «нет», решит ли это мою проблему? - person Anahit DEV; 22.02.2019
comment
Анаит, тогда вам придется добавлять новый столбец для каждого нового региона. Это не правильный путь. Я рекомендую свой пример выше. - person blupointmedia; 22.02.2019
comment
Если пользователь пишет вам письмо и говорит, что его региона нет в списке. Затем все, что вам нужно сделать, это добавить новый регион в таблицу регионов, а все остальное продолжит работать. Вам не придется менять структуру вашей базы данных. - person blupointmedia; 22.02.2019
comment
Дело в том, что Регионы фиксированы, их 6 Глобальный, Африка, Средний Восток, Америка, Азия и Европа. - person Anahit DEV; 22.02.2019
comment
Вы тоже пойдете по этому пути. Технически их 8. Я бы создал логический столбец для каждого и 1 для да/истина и 0 для нет/ложь - person blupointmedia; 22.02.2019
comment
Хорошо, и тогда мой запрос будет похож на select, где значение равно 1? - person Anahit DEV; 22.02.2019
comment
ВЫБЕРИТЕ {столбцы} из {таблицы}, ГДЕ Африка = 1 ИЛИ Азия = 1 и т. д. Вам нужно будет построить запрос на основе выбора пользователя - person blupointmedia; 22.02.2019
comment
Если это сработает, пожалуйста, примите ответ. Спасибо и удачи. - person blupointmedia; 22.02.2019
comment
Сработало :) Большое спасибо - person Anahit DEV; 22.02.2019

Вам в значительной степени нужно отформатировать свой sql следующим образом:

SELECT
    *
FROM
    table
WHERE
    regions = 'Europe' or
    regions like 'Europe,%' or
    regions like '%,Europe' or
    regions like '%,Europe,%' or
    regions = 'Middle East' or
    regions like 'Middle East,%' or
    regions like '%,Middle East' or
    regions like '%,Middle East,%'

В PHP вам нужно будет перебирать регионы, которые выбрал пользователь, и динамически создавать такой запрос.

person MonkeyZeus    schedule 22.02.2019
comment
Зачем столько лайков, можно поставить один вайлд и в начале и другой в конце. как %значение% - person Vidal; 22.02.2019
comment
@Vidal Я понятия не имею, как выглядит полный список регионов, поэтому, если regions содержит что-то вроде Global,Middle East,Europe,East,Asia, то %East% вернет слишком много результатов. - person MonkeyZeus; 22.02.2019
comment
@Vidal Я уверен, что всю эту ситуацию можно REGEXP_LIKE() разрулить, но у меня нет терпения разобраться в этом для ОП. Они должны нормализовать свои таблицы и жить дальше. Это будет настоящее дерьмовое шоу, если регион когда-нибудь изменит свое название, заглавные буквы или разделится на несколько регионов или что-то в этом роде. - person MonkeyZeus; 22.02.2019

Я могу предложить такой подход.

SELECT * FROM table
WHERE 
   region like("%Global%")
   and region like ("%Middle East%")

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

person Vidal    schedule 22.02.2019
comment
но, как и у меня, у меня будет много запросов, и мне нужно выбрать выбранные результаты, а не статические - person Anahit DEV; 22.02.2019
comment
Вы хотите получить список подписчиков, чтобы отправить электронное письмо? какова цель увидеть, могу ли я дать вам лучший ответ? - person Vidal; 22.02.2019
comment
Да, мне нужно будет получить список, который затем будет импортирован в список рассылки по регионам. - person Anahit DEV; 22.02.2019
comment
хорошо, вы можете сделать запрос [SELECT * FROM table WHERE region like(%Global%)] и получить всех глобальных подписчиков, а затем сохранить их в глобальном списке рассылки, а затем сделать запрос для следующего региона Ближний Восток и сын на . - person Vidal; 22.02.2019
comment
хорошо, но что мне делать с пользователями, у которых несколько регионов в качестве значения? Одним запросом это не приведет к тому, что пользователи - person Anahit DEV; 22.02.2019
comment
Я думаю, что это не одноразовый запрос, возможно, вам придется запрашивать все разные регионы по отдельности. Пользователи, которые подписаны на несколько регионов, они будут в соответствующем списке рассылки, возможно, в нескольких, как они выбрали. - person Vidal; 22.02.2019
comment
Итак, если у меня есть все регионы в отдельных столбцах со значением «да» или «нет», я достигну результата? Пользователь должен получить одно письмо со всеми регионами, а не несколько писем. - person Anahit DEV; 22.02.2019
comment
ОК, теперь я в замешательстве, если вы собираетесь отправить пользователю его / ее регионы, просто запросите таблицу без какого-либо фильтра «где» или «регион». Что вы хотите получить от стола? Какова цель, если вы можете поделиться этим? - person Vidal; 22.02.2019
comment
Мне нужно отправить пользователю по электронной почте новости о выбранных им регионах, поэтому мне нужно знать, какие пользователи, например, для Европы и Азии, поэтому я экспортирую этот список - person Anahit DEV; 22.02.2019
comment
Вы отправляете разные электронные письма для каждого региона? - person Vidal; 22.02.2019
comment
Хорошо, тогда мой 4-й комментарий — это то, что вам нужно. Вам нужно будет сделать запрос для каждого региона. - person Vidal; 22.02.2019

Для вашего требования нет точной функции, но вы можете использовать приведенный ниже код:

$trimmedRegions = rtrim($sortType,', ');
$trimmedRegionsCollection = explode(",", $trimmedRegions);
$trimmedRegionsRegex = implode("|", $trimmedRegionsCollection); // make string like Global|Middle East

$query = 'SELECT * from health_alerts_subscribers WHERE CONCAT(",", `Regions`, ",") REGEXP ",('.$trimmedRegionsRegex.'),"';

Надеюсь, это поможет вам.

person Rohit Mittal    schedule 22.02.2019