MySQL设计具有动态数量的字段

时间:2009-01-13 16:23:36

标签: php mysql database

我对MySQL的经验非常基础。简单的东西很容易,但我遇到了需要更多知识的东西。我需要一个存储一小部分单词的表。存储的单词数量可以是1到15之间的任何值。后来,我打算用这些单词在表格中搜索。我考虑过几种不同的方法:

A。)我可以用15个字段创建数据库,只要数据小于15就填充空值。我真的不喜欢这个。这看起来效率很低。

B。)另一种选择是只使用一个字段,并将数据存储为逗号分隔列表。每当我回到搜索时,我都会在场上运行正则表达式。再次,这似乎效率很低。

我希望这两个选项有一个很好的选择。任何建议都将非常感激。

-Thanks

7 个答案:

答案 0 :(得分:15)

C)使用normal form;使用适当键的多行。一个例子:

mysql> SELECT * FROM blah;
+----+-----+-----------+
| K  | grp | name      |
+----+-----+-----------+
|  1 |   1 | foo       |
|  2 |   1 | bar       |
|  3 |   2 | hydrogen  |
|  4 |   4 | dasher    |
|  5 |   2 | helium    |
|  6 |   2 | lithium   |
|  7 |   4 | dancer    |
|  8 |   3 | winken    |
|  9 |   4 | prancer   |
| 10 |   2 | beryllium |
| 11 |   1 | baz       |
| 12 |   3 | blinken   |
| 13 |   4 | vixen     |
| 14 |   1 | quux      |
| 15 |   4 | comet     |
| 16 |   2 | boron     |
| 17 |   4 | cupid     |
| 18 |   4 | donner    |
| 19 |   4 | blitzen   |
| 20 |   3 | nod       |
| 21 |   4 | rudolph   |
+----+-----+-----------+
21 rows in set (0.00 sec)

这是我在关于group_concat的其他问题中发布的表格。您会注意到每行都有一个唯一键K。还有另一个键grp代表每个类别。剩下的字段代表一个类别成员,每个类别可以有不同数量的这些。

答案 1 :(得分:1)

这些词还有哪些其他数据?

通过示例可以最好地描述处理此类问题的一种典型方法。我们假设您的表格捕获了某些文档中的某些单词。一种典型的方法是为每个文档分配一个标识符。让我们暂时假装每个文档都是一个Web URL,所以你有一个像这样的表:

CREATE TABLE WebPage (
    ID INTEGER NOT NULL,
    URL VARCHAR(...) NOT NULL
)

您的Words表格可能如下所示:

CREATE TABLE Words (
    Word VARCHAR(...) NOT NULL,
    DocumentID INTEGER NOT NULL 
)

然后,对于每个单词,您在表中创建一个新行。要查找特定文档中的所有单词,请选择文档的ID:

SELECT Words.Word FROM Words, WebPage 
WHERE Words.DocumentID = WebPage.DocumentID
AND WebPage.URL = 'http://whatever/web/page/'

要查找具有特定字词的所有文档,请按字词选择:

SELECT WebPage.URL FROM WebPage, Words
WHERE Words.Word = 'hello' AND Words.DocumentID = WebPage.DocumentID

或者其他一些。

答案 2 :(得分:1)

Hurpe,是您描述的场景,您将拥有一个数据库表,其中包含最多可包含15个关键字的列。稍后您将使用这些关键字来搜索可能还有其他列的表格?

那么关键字的单独表格不是答案吗?您还需要在关键字和主表之间建立多对多的关系。

因此,以汽车为例,将存储15个左右关键字的WORD表具有以下结构:

ID             int
Word           varchar(100)

CAR表的结构类似于:

ID              int
Name            varchar(100)

然后最后你需要一个CAR_WORD表来保存多对多关系:

ID              int
CAR_ID          int
WORD_ID         int

并为WORD表提供示例数据:

ID   Word

001  Family
002  Sportscar
003  Sedan
004  Hatchback
005  Station-wagon
006  Two-door
007  Four-door
008  Diesel
009  Petrol

与CAR表的样本数据一起

ID   Name

001  Audi TT
002  Audi A3
003  Audi A4

然后交集CAR_WORD表样本数据可以是:

ID    CAR_ID   WORD_ID
001   001      002
002   001      006
003   001      009

为奥迪TT提供了正确的特性。

最后要搜索的SQL类似于:

SELECT c.name
FROM CAR c
INNER JOIN CAR_WORD x
ON c.id = x.id
INNER JOIN WORD w
ON x.id = w.id
WHERE w.word IN('Petrol', 'Two-door')

唷!不打算开始写这么多,它看起来很复杂,但它总是似乎最终我努力简化事情。

答案 3 :(得分:0)

你是对的,A是不好的。 B也不好,因为它不能遵守第一范式(每个字段必须是原子的)。你的例子中没有任何内容表明你会通过避免1NF而获益。

你想要一个表格,列出你自己行中每个单词的单词列表。

答案 4 :(得分:0)

我会创建一个带有ID和一个字段的表,然后将结果存储为多个记录。这提供了许多好处。例如,您可以以编程方式强制执行15个字的限制,而不是在设计中执行此操作,因此如果您改变主意,它应该相当容易。您搜索数据的查询运行起来也会快得多,正则表达式需要花费大量时间才能运行(相对而言)。另外,使用varchar作为字段将允许您更好地压缩表。使用此设计,表格上的索引应该更容易(更有效)。

答案 5 :(得分:0)

执行额外的工作并将15个字存储为表中的15行,即标准化数据。它可能需要你稍微重新考虑一下你的策略,但是当客户出现并且说“你能将那15个限制改为20 ......”时,请相信我,你会很高兴你做到了。

答案 6 :(得分:0)

取决于您想要完成的目标:

  1. 在字符串表上使用全文索引

  2. 三个表:一个用于原始字符串,一个用于唯一字(在生根后?)和连接表。这也可以让你做更复杂的搜索,例如“返回包含以下五个单词中至少三个的所有字符串”或“返回'dog'之后'狐狸'出现的所有字符串”。

    CREATE TABLE字符串(   id INT NOT NOT AUTO_INCREMENT PRIMARY KEY,   string TEXT NOT NULL )

    创建表字(   id INT NOT NOT AUTO_INCREMENT PRIMARY KEY,   word VARCHAR(14)NOT NULL UNIQUE,   独特的索引(字ASC) )

    CREATE TABLE word_string(   id INT NOT NOT AUTO_INCREMENT PRIMARY KEY,   string_id INT NOT NULL,   word_id INT NOT NULL,   word_order INT NOT NULL,   FOREIGN KEY(string_id)REFERENCES(string.id),   FOREIGN KEY(word_id)REFERENCES(word.id),   INDEX(word_id ASC) )

    //示例数据 INSERT INTO string(string)VALUES   ('这是一个测试字符串'),   ('快速的红狐狸跳过懒惰的棕色狗')

    插入单词(单词)值   ('这个'),   ('测试'),   ('串'),   ('快'),   ('红色'),   ('狐狸'),   ('跳'),   ('过度'),   ('懒'),   ('棕色'),   ( '狗')

    INSERT INTO word_string(string_id,word_id,word_order)VALUES   (0,0,0),   (0,1,3),   (0,2,4),   (1,3,1),   (1,4,2),   (1,5,3),   (1,6,4),   (1,7,5),   (1,8,7),   (1,9,8),   (1,10,9)

    //示例查询 - 查找包含'fox'和'quick'的所有字符串 选择   UNIQUE string.id,string.string 从   串   INNER JOIN word_string ON string.id = word_string.string_id   INNER JOIN单词AS fox ON fox.word ='fox'和word_string.word_id = fox.id   INNER JOIN字AS快速开启quick.word ='快速'和word_string.word_id = word.id