5

我有两张桌子

table: people 

id name goods_owned
1  john   1,4,3
2  Mike   2,5
3  Sam    1,5,2
4  Andy   5,3,4

-

table goods:

  g_id g_name  g_class
    1   sugar  food
    2   salt   food
    3   boat   transp
    4   house  habitation
    5   car    transp

这是一个简单的表格示例,goods它实际上很长,每个人都people可以有多个goods分配给他,例如汽车、船、糖等,一个人可以拥有多少没有限制,而且完全随机。我找不到比逗号分隔更好的方法来存储它,例如1,5,3

我在进行选择时遇到问题,例如

SELECT people.*, goods.name
   FROM people
      LEFT JOIN  goods ON goods.g_id = people.goods_owned
         WHERE name = "Sam"

然而问题是goods_owned在单元格中有多个商品ID,它们需要以某种方式分解以获得答案:

1, Sam, sugar, car, salt

如果您知道在一个单元格中存储(例如 100 个)多个逗号分隔值的更好替代方法,请告诉我。

4

3 回答 3

3

一个人可以与零、一种或多种商品相关。一件商品可以与零个、一个或多个人相关。

那是多对多的关系。

通常,我们通过创建第三个表来处理这个问题,这是一个指向其他两个表的“关系”

table: goods_owned
people_id goods_id
        1        1
        1        4
        1        3
        2        2
        2        5
        3        1
        3        5
        3        2
        4        5
        4        3
        4        4    

这两列的组合可以指定为唯一的,并且可以作为表的主键。每列都可以定义为父表的外键。

CREATE TABLE goods_owned
( people_id  INT UNSIGNED NOT NULL
, goods_id   INT UNSIGNED NOT NULL
, PRIMARY KEY (people_id, goods_id)
-- , KEY FK_goods_owned_people (people_id)  -- redundant with PK
, KEY FK_goods_owned_goods (goods_id)
, CONSTRAINT FK_goods_owned_people FOREIGN KEY (people_id) REFERENCES people (id)
, CONSTRAINT FK_goods_owned_goods FOREIGN KEY (goods_id) REFERENCES goods (g_id)
) ;

另一种选择是,如果“商品”的集合是静态且定义明确的,并且不需要在表中表示,那么您可以使用 MySQL SET 数据类型,并拥有一个表。但这种方法仅适用于集合是静态的(不需要更改。)

于 2012-05-16T23:51:54.420 回答
2

您的数据库未标准化。您在列中有重复组。如果可能,您应该标准化您的数据库。

如果你不能改变你的数据库设计,你可以使用FIND_IN_SET,但它会很慢:

SELECT people.id, people.name, people.goods_owned, goods.name
FROM people
LEFT JOIN goods ON FIND_IN_SET(goods.g_id, people.goods_owned)
WHERE name = 'Sam'
于 2012-05-16T23:46:13.693 回答
1

让我真的很无聊......

CREATE TABLE `people` (
  `id` int(11) NOT NULL,
  `name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
;
CREATE TABLE `goods` (
  `id` int(11) NOT NULL,
  `name` varchar(50) DEFAULT NULL,
  `class_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
;
CREATE TABLE `goods_owned` (
  `people_id` INT(11) DEFAULT NULL,
  `goods_id` INT(11) DEFAULT NULL
) ENGINE=MYISAM CHARSET=latin1
;
CREATE TABLE `classes` (
  `id` int(11) NOT NULL,
  `class_name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
;

INSERT INTO `people` (`id`, `name`) VALUES('1','John');
INSERT INTO `people` (`id`, `name`) VALUES('2','Mike');
INSERT INTO `people` (`id`, `name`) VALUES('3','Sam');
INSERT INTO `people` (`id`, `name`) VALUES('4','Andy');

INSERT INTO `classes` (`id`, `class_name`) VALUES('1','Food');
INSERT INTO `classes` (`id`, `class_name`) VALUES('2','Trans');
INSERT INTO `classes` (`id`, `class_name`) VALUES('3','Habitation');

INSERT INTO `goods` (`id`, `name`, `class_id`) VALUES('1','Sugar','1');
INSERT INTO `goods` (`id`, `name`, `class_id`) VALUES('2','Salt','1');
INSERT INTO `goods` (`id`, `name`, `class_id`) VALUES('3','Boat','2');
INSERT INTO `goods` (`id`, `name`, `class_id`) VALUES('4','House','3');
INSERT INTO `goods` (`id`, `name`, `class_id`) VALUES('5','Car','2');

INSERT INTO `goods_owned` (`people_id`, `goods_id`) VALUES('1','1');
INSERT INTO `goods_owned` (`people_id`, `goods_id`) VALUES('1','4');
INSERT INTO `goods_owned` (`people_id`, `goods_id`) VALUES('1','3');
INSERT INTO `goods_owned` (`people_id`, `goods_id`) VALUES('2','2');
INSERT INTO `goods_owned` (`people_id`, `goods_id`) VALUES('2','5');
INSERT INTO `goods_owned` (`people_id`, `goods_id`) VALUES('3','1');
INSERT INTO `goods_owned` (`people_id`, `goods_id`) VALUES('3','5');
INSERT INTO `goods_owned` (`people_id`, `goods_id`) VALUES('3','2');
INSERT INTO `goods_owned` (`people_id`, `goods_id`) VALUES('4','5');
INSERT INTO `goods_owned` (`people_id`, `goods_id`) VALUES('4','3');
INSERT INTO `goods_owned` (`people_id`, `goods_id`) VALUES('4','4');

SELECT
    people.name
    , goods.name
    , classes.class_name
FROM people
    LEFT JOIN goods_owned ON (people.id = goods_owned.people_id)
    LEFT JOIN goods ON (goods_owned.goods_id = goods.id)
    LEFT JOIN classes ON (goods.class_id = classes.id)
WHERE classes.id = 1  /*Include only Food Goods*/
ORDER BY people.name;
        ;
于 2012-05-16T23:59:29.017 回答