Как лучше хранить список стран в БД?

Статус
В этой теме нельзя размещать новые ответы.

verfaa

Профессор
Регистрация
29 Янв 2007
Сообщения
416
Реакции
49
Стоит задача хранить список ID стран в таблице БД MySQL. Т.е. значение в поле может быть одиночным, например 258, несколько стран - например 231 456 234 10 45 и 0 - т.е. все страны.

Каким образом лучше хранить насколько стран в поле? Перечислять их через запятую: 231,456,234? И как тогда составить запрос, если нужно выбрать поля в которых присутствует страна, например, 234?
 
я как-то делал такой вариант - ограничители спереди и сзади. Т.е. к примеру, #231##456##234#. Тогда поиск - "LIKE '%#234#%'. И не будет склеивания со страной 23 (поиском по стране 23). Можно и через запятую, но добивать нулями - 231,456,023. Запрос "LIKE '%023%'"
 
Готовый пример
Код:
SELECT * FROM `table` WHERE `country` regexp '[[:<:]](234)[[:>:]]'
 
Я так понимаю, что "LIKE '%#234#%' будет работать быстрее, чем regexp '[[:<:]](234)[[:>:]]' и лучше выбрать его?
 
Вы же используете реляционную базу данных, так используйте ее по назначению: для хранения одной страны - одна запись в таблице. Если нужно сохранить несколько стран, то используете в таблице несколько записей. Построите кластерный индекс на таблицу и все летать будет + такое решение обслуживать легче, джойнить таблицу опять же удобно.
 
Вы же используете реляционную базу данных, так используйте ее по назначению: для хранения одной страны - одна запись в таблице. Если нужно сохранить несколько стран, то используете в таблице несколько записей. Построите кластерный индекс на таблицу и все летать будет + такое решение обслуживать легче, джойнить таблицу опять же удобно.
Вообще, хранение ярлыков в реляционной базе - та ещё проблема :) Тут просится документоориентированное решение, но в большинстве случаев это местечковая задача, выходит стрельба из пушки по воробьям.

Как выбрать все строки, которым принадлежат страны "Финляндия", "Португалия" и "Греция", но при этом не должно быть "Швеции" и "Люксембурга"?

С денормализованной базой выходит более-менее понятно (хотя изобилие LIKE и % сигнализирует, что в рабочем окружении этот код неэффективен) :
PHP:
SELECT * FROM `items`
WHERE `countries` LIKE '%#Финляндия#%'
  AND `countries` LIKE '%#Португалия#%'
  AND `countries` LIKE '%#Греция#%'
  AND `countries` NOT LIKE '%#Швеция#%'
  AND `countries` NOT LIKE '%#Люксембург#%'

Как это переписать в нормализованном виде?
 
Как это переписать в нормализованном виде?

Наверное мы с вами будем зря рассуждать, пока не увидим проблему целиком. Я имел в виду следующий сценарий:
1. На клиенте есть комбобокс со странами которые надо выбрать (множественный выбор)
2. На клиенте есть второй комбобокс со странами которые надо исключить (множественный выбор).
3. После того как вы укажете значения и в том и в другом списках, вы передаете на сервер не названия стран, а ID этих стран как параметры-строки (Искать: 1,2,3; Исключить 4,5)
4. На сервере в запросе, вы первым делом парсите эти строчки в 2 темповые таблицы @T1 и @T2 (1 строчка = 1 ID страны)
5. Делаете сам запрос аля:
PHP:
      Select Distinct TC.Name as CustomerName
      From Customer_Country as TCC
           Join Customer as TC on TC.ID = TCC.CustomerID
      Where TCC.CountryID in (select ID from @T1)  
               and TCC.CountryID not in (select ID from @T2)
Расставив индексы по этим 2 таблицам можно добиться, что этот запрос будет очень быстро работать на любых объемах данных.

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

С одной стороны это довольно банальная задача, но с другой стороны, она просто взрывает мозг, когда сталкиваешься с требованием разработать систему типа Avito.ru. Вроде там все построено на простых справочниках типа Ключ-Значение, но с другой стороны когда в запрос заходит одновременно с десяток параметров типа "Включить в поиск список/Исключить из поиска список" + объявлений в базе пару миллионов + нужно чтобы запрос отдавал данные не более чем за 2-3 сек. вот тут-то и задумываешься как все же умудриться сделать хлопок одной ладонью :)))
 
Последнее редактирование модератором:
4. На сервере в запросе, вы первым делом парсите эти строчки в 2 темповые таблицы @T1 и @T2 (1 строчка = 1 ID страны)

В чём профит от использования темп таблиц, по идее это 2 лишних запроса к базе, можно ведь добавить джойн Customer_Country на Country и в where перечислять нужные страны
Код:
TCO.country_name in ("Финляндия", "Португалия", "Греция") AND TCO.country_name NOT in ("Швеции", "Люксембург")

В отдельных случаях есть смысл хранить country_id 2 country_name не только в бд, но и "под рукой" в мемкеше, тогда список id для условия IN на php сформируем.

PS:Если стран о-о-очень много, не забывайте увеличить лимиты на длину запроса в mysql.
 
Статус
В этой теме нельзя размещать новые ответы.
Назад
Сверху