Соответствие строки с разделителями для строк таблицы - PullRequest
2 голосов
/ 30 сентября 2010

Итак, у меня есть две таблицы в этом упрощенном примере: люди и дома.Люди могут иметь несколько домов, поэтому у меня есть поле People.Houses, которое представляет собой строку с разделителями запятых (например, «House1, House2, House4»).В домах может быть несколько человек, поэтому у меня есть поле Houses.People, которое работает одинаково («Сэм, Саманта, Дарен»).

Я хочу найти все строки в таблице People, соответствующиена имена людей в данном доме, и наоборот, для домов принадлежат людям.Но я не могу понять, как это сделать.

Это так близко, как я уже придумал:

   SELECT People.* 
     FROM Houses 
LEFT JOIN People ON Houses.People Like CONCAT(CONCAT('%', People.Name), '%')
    WHERE House.Name = 'SomeArbitraryHouseImInterestedIn'

Но я получаю некоторые ложные срабатывания (например:Сэма и Саманту могут схватить, когда я просто захочу Саманту, а также с House3, House34 и House343, когда я хочу House343).

Я подумал, что мог бы попытаться написать функцию SplitString, чтобы разбитьstring (используя список разделителей) в набор и выполняйте некоторые подзапросы для этого набора, но функции MySQL не могут иметь таблицы в качестве возвращаемых значений.

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

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

Ответы [ 5 ]

6 голосов
/ 30 сентября 2010

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

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

Вы бы хотели, чтобы схема вашей таблицы выглядела примерно так:

CREATE TABLE people (
   id int NOT NULL,
   name varchar(50),
   PRIMARY KEY (id)
) ENGINE=INNODB;

CREATE TABLE houses (
   id int NOT NULL,
   name varchar(50),
   PRIMARY KEY (id)
) ENGINE=INNODB;

CREATE TABLE people_houses (
   house_id int,
   person_id int,
   PRIMARY KEY (house_id, person_id),
   FOREIGN KEY (house_id) REFERENCES houses (id),
   FOREIGN KEY (person_id) REFERENCES people (id)
) ENGINE=INNODB;

Тогда поиск людей будет таким же простым, как этот:

SELECT  p.* 
FROM    houses h
JOIN    people_houses ph ON ph.house_id = h.id
JOIN    people p ON p.id = ph.person_id
WHERE   h.name = 'SomeArbitraryHouseImInterestedIn';

Больше никаких ложных срабатываний, и все они жили долго и счастливо.

5 голосов
/ 30 сентября 2010

Хорошее решение состоит в том, чтобы изменить схему вашей схемы так, чтобы у вас были следующие таблицы:

People
------
PeopleID (PK)
...


PeopleHouses
------------
PeopleID (PK) (FK to People)
HouseID (PK) (FK to Houses)


Houses
------
HouseID (PK)
...
3 голосов
/ 30 сентября 2010

Краткосрочное решение

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

для людей

SELECT p.*
  FROM PEOPLE p
  JOIN HOUSES h ON FIND_IN_SET(p.name, h.people)
 WHERE h.name = ?

Для дома

SELECT h.*
  FROM HOUSES h
  JOIN PEOPLE p ON FIND_IN_SET(h.name, p.houses)
 WHERE p.name = ?

Долгосрочное решение

Нужно правильно смоделировать это, добавив таблицу, чтобы связать дома с людьми, потому что вы, вероятно, храните избыточные отношения в обеих таблицах:

CREATE TABLE people_houses (
  house_id int,
  person_id int,
  PRIMARY KEY (house_id, person_id),
  FOREIGN KEY (house_id) REFERENCES houses (id),
  FOREIGN KEY (person_id) REFERENCES people (id)
)
0 голосов
/ 30 сентября 2010

Привет, просто поменяйте местами названия таблиц, слева - Люди, а затем справа - Дома:

ВЫБЕРИТЕ Людей. * ИЗ ЛЮДЕЙ СЛЕДУЕТ ПРИСОЕДИНЯТЬСЯ К ДОМАМ. Дома., People.Name), '%') WHERE House.Name = 'SomeArbitraryHouseImInterestedIn'

0 голосов
/ 30 сентября 2010

Проблема в том, что вам нужно использовать другую схему, например, предложенную @RedFilter.Вы можете видеть это как:

Таблица людей: PeopleID otherFields

Таблица домов: HouseID otherFields

Таблица владельцев: PeopleID HouseID otherFields

Надеюсь, что помогает,

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...