匹配分隔的字符串到表行

时间:2010-09-30 01:13:18

标签: sql mysql string

所以我在这个简化的例子中有两个表:人和房子。人们可以拥有多个房子,所以我有一个People.Houses字段,这是一个带逗号分隔符的字符串(例如:“House1,House2,House4”)。房子里面可以有多个人,所以我有一个Houses.People字段,它的工作方式相同(“Sam,Samantha,Daren”)。

我想找到People表中与给定房屋中人员姓名相对应的所有行,反之亦然,因为房屋属于人。但我无法弄清楚如何做到这一点。

这是我到目前为止所提出的:

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

但是我得到了一些误报(例如:当我想要Samantha时,Sam和Samantha可能都会被抓住。还有House3,House34和House343,当我想要House343时)。

我想我可能会尝试编写一个SplitString函数,这样我就可以将一个字符串(使用一个分隔符列表)拆分成一个集合,并在该集合上做一些子查询,但是MySQL函数不能将表作为返回值。

同样,你不能将数组存储为字段,并且从我收集的内容中,长字符串中的逗号分隔元素似乎是解决此问题的常用方法。

我可以想出一些不同的方法来获得我想要的东西,但我想知道是否有一个不错的解决方案。

5 个答案:

答案 0 :(得分:6)

  

同样,你不能将数组存储为字段,并且从我收集的内容中,长字符串中的逗号分隔元素似乎是解决此问题的常用方法。

我希望那不是真的。在SQL数据库中表示“数组”不应采用逗号分隔格式,但可以使用junction table正确解决问题。以逗号分隔的字段在关系数据库中应该没有位置,它们实际上违反了first normal form

您希望表架构看起来像这样:

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';

不再有误报,他们从此过上幸福的生活。

答案 1 :(得分:5)

很好的解决方案是重新设计您的架构,以便您拥有以下表格:

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


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


Houses
------
HouseID (PK)
...

答案 2 :(得分:3)

短期解决方案

对于您当前的问题,FIND_IN_SET function是您要用于加入的内容:

For People

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)
)

答案 3 :(得分:0)

问题是你必须使用另一个模式,比如@RedFilter提出的模式。您可以将其视为:

人员表: 的peopleid otherFields

房屋表: HouseID otherFields

所有权表: 的peopleid HouseID otherFields

希望有所帮助,

答案 4 :(得分:0)

您好,您只需更改表名称的位置,左侧是人,然后右侧是Houses:

选择人物。*      来自人民 LEFT JOIN Houses on Houses.People like CONCAT(CONCAT('%',People.Name),'%')     在哪里House.Name ='SomeArbitraryHouseImInterestedIn'