MySQL дизайн с динамическим количеством полей - PullRequest
3 голосов
/ 13 января 2009

Мой опыт работы с MySQL очень прост. Простые вещи достаточно просты, но я столкнулся с чем-то, что потребует немного больше знаний. Мне нужна таблица, в которой хранится небольшой список слов. Количество сохраненных слов может быть где-то между 1 и 15. Позже я планирую поиск по таблице по этим словам. Я думал о нескольких разных методах:

A.) Я мог бы создать базу данных из 15 полей и просто заполнять поля нулевыми значениями всякий раз, когда данные меньше 15. Мне это не очень нравится. Это кажется действительно неэффективным.

B.) Другой вариант - использовать только одно поле и хранить данные в виде списка через запятую. Всякий раз, когда я возвращаюсь к поиску, я просто запускаю регулярное выражение в поле. Опять же, это кажется действительно неэффективным.

Я надеюсь, что есть хорошая альтернатива этим двум вариантам. Любой совет будет очень признателен.

-Спасибо

Ответы [ 7 ]

15 голосов
/ 13 января 2009

C) используйте нормальную форму ; используйте несколько строк с соответствующими ключами. пример:

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 голос
/ 13 января 2009

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

Тогда не является ли ответом иметь отдельную таблицу для ключевых слов? Вам также нужно будет иметь отношение многие ко многим между ключевыми словами и основной таблицей.

Таким образом, используя автомобили в качестве примера, таблица WORD, в которой будет храниться около 15 ключевых слов, будет иметь следующую структуру:

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

, которые дают Audi 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')

Уф! Я не собирался писать так много, это выглядит сложно, но это то, где я всегда оказываюсь, как бы сильно я ни пытался упростить вещи.

1 голос
/ 13 января 2009

Какие еще данные связаны с этими словами?

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

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

Ваша таблица слов может выглядеть примерно так:

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

Затем для каждого слова вы создаете новую строку в таблице. Чтобы найти все слова в определенном документе, выберите по идентификатору документа:

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

Или некоторые такие.

0 голосов
/ 13 января 2009

В зависимости от того, чего именно вы хотите достичь:

  1. Использование полнотекстового индекса в таблице строк

  2. Три таблицы: одна для исходной строки, одна для уникальных слов (после корня слова?) И таблица соединения. Это также позволит вам выполнять более сложные поиски, такие как «вернуть все строки, содержащие не менее трех из следующих пяти слов» или «вернуть все строки, где« fox »происходит после« dog »».

    CREATE TABLE string ( id INT NOT NULL AUTO_INCREMENT ПЕРВИЧНЫЙ КЛЮЧ, строка ТЕКСТ НЕ НУЛЬ )

    CREATE TABLE word ( id INT NOT NULL AUTO_INCREMENT ПЕРВИЧНЫЙ КЛЮЧ, слово VARCHAR (14) НЕ ПУСТО УНИКАЛЬНО, УНИКАЛЬНЫЙ ИНДЕКС (слово ASC) )

    CREATE TABLE word_string ( id INT NOT NULL AUTO_INCREMENT ПЕРВИЧНЫЙ КЛЮЧ, string_id INT NOT NULL, word_id INT NOT NULL, word_order INT NOT NULL, FOREIGN KEY (string_id) ССЫЛКИ (string.id), КЛЮЧЕВОЙ КЛЮЧ (word_id) ССЫЛКИ (word.id), INDEX (word_id ASC) )

    // Пример данных INSERT INTO string (string) ЗНАЧЕНИЯ («Это тестовая строка»), («Быстрая рыжая лиса перепрыгнула через ленивую коричневую собаку»)

    ВСТАВИТЬ В слово (слово) ЦЕННОСТИ ('этот'), ('тестовое задание'), ( 'Строка'), ('быстрый'), ( 'Красный'), ('лиса'), ('Прыгать'), ('над'), ( 'Ленивым'), ( 'Коричневого'), ( 'Собака')

    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» ВЫБРАТЬ УНИКАЛЬНЫЙ string.id, string.string ОТ строка ВНУТРЕННЕЕ ПРИСОЕДИНЕНИЕ word_string ON string.id = word_string.string_id ВНУТРЕННЕЕ СОЕДИНЕНИЕ Слово КАК ЛИСА НА fox.word = 'fox' И word_string.word_id = fox.id ВНУТРЕННЕЕ СОЕДИНЕНИЕ Слово КАК БЫСТРО ВКЛЮЧЕНО

0 голосов
/ 13 января 2009

Сделайте дополнительную работу и сохраните 15 слов в виде 15 строк в таблице, то есть нормализуйте данные. Может потребоваться, чтобы вы немного переосмыслили свою стратегию, но поверьте мне, когда клиент придет и скажет: «Можете ли вы изменить этот предел 15 на 20 ...», вы будете рады, что сделали это.

0 голосов
/ 13 января 2009

Я хотел бы создать таблицу с идентификатором и одним полем, а затем сохранить результаты в виде нескольких записей. Это предлагает много преимуществ. Например, вы можете программно применять ограничение в 15 слов вместо того, чтобы делать это в своем дизайне, поэтому, если вы когда-нибудь передумали, это должно быть довольно легко. Ваши запросы для поиска по данным также будут выполняться намного быстрее, регулярные выражения занимают много времени (сравнительно). Плюс использование varchar для поля позволит вам сжать ваш стол намного лучше. И индексирование по таблице должно быть намного проще (более эффективным) с этим дизайном.

0 голосов
/ 13 января 2009

Вы правы, что А это не хорошо. B также не годится, так как он не соответствует первой нормальной форме (каждое поле должно быть атомарным). В вашем примере нет ничего, что подсказывало бы, что вы выиграли бы, если бы не 1NF.

Вам нужна таблица для вашего списка слов с каждым словом в отдельной строке.

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