2010-07-16 3 views
13

У меня есть две таблицыКаков наиболее эффективный способ хранения массива целых чисел в столбце MySQL?

A:

plant_ID | name. 
1  | tree 
2  | shrubbery 
20  | notashrubbery 

B:

area_ID | name | plants 
1  | forrest | *needhelphere* 

теперь я хочу область хранить любое количество растений, в определенном порядке, а некоторые растения могли бы несколько раз: например, 2,20,1,2,2,20,1

Каков наиболее эффективный способ хранения этого массива растений?
Помните, что мне нужно сделать так, чтобы, если я выполняю поиск, чтобы найти области с растением 2, я не получаю области, которые, например, 1,20,232,12,20 (прокладка с ведущими 0s?) Что будет ли это запрос?

если это помогает, допустим, у меня есть база данных не более 99999999 разных растений. И да, этот вопрос не имеет ничего общего с заводами.

Бонус Вопрос Пришло время уйти от MySQL? Есть ли более эффективная БД для управления этим?

+2

Если только MySQL просто дал нам несколько значений для одного столбца ... – animuson

+6

Каждый раз, когда вы чувствуете необходимость комбинирования данных в одном поле, пинайте себя: вы нарушаете нормальную форму и вам нужно добавить другую таблицу для обработки ситуация должным образом. (См. Ответы Matchu и mgrove ниже.) –

+0

, если вам интересен нереляционный способ хранения этих данных (т. Е. Фактического набора/массива), посмотрите на OODBMS, например, db4o. –

ответ

25

Если вы собираетесь искать как по лесу, так и по заводу, звучит так, как будто вы выиграете от полноправного отношения «многие ко многим». Выровняйте столбец plants и создайте целую новую таблицу areas_plants (или что бы вы хотели назвать), чтобы связать эти две таблицы.

Если область 1 имеет заводы 1 и 2, а площадь 2 имеет заводы 2 и 3, ваша areas_plants таблица будет выглядеть следующим образом:

area_id | plant_id | sort_idx 
----------------------------- 
     1 |  1 |  0 
     1 |  2 |  1 
     2 |  2 |  0 
     2 |  3 |  1 

Вы можете посмотреть взаимоотношения с обеих сторон, и использовать простые ПРИСОЕДИНИТЕСЬ, чтобы получить соответствующие данные из любой таблицы. Не нужно гадать в условиях LIKE, чтобы выяснить, есть ли в списке, бла, bleh, yuck. Я был там для устаревшей базы данных. Не весело. Используйте SQL с наибольшим потенциалом.

+6

Это (введение таблицы соединений) является правильным решением проблемы. Единственное, что я хотел бы добавить, это столбец sort_idx, чтобы сохранить заводский заказ в соответствии с запросом в вопросе. –

+0

@Paul Sasik - хорошо пятнистый :) Не буду докучать, так как вы уже получили ответ прямо там. – Matchu

+1

Я пошел вперед и добавил колонку. Это помогает ошибаться на стороне педантичного для db design noobs, я думаю. –

3

Вы знаете, что это нарушает нормальную форму?

Как правило, для обеих двух таблиц должна быть таблица isaplants: area_ID, plant_ID с уникальным ограничением для двух и внешних ключей. Эта таблица «ссылок» - это то, что дает вам много-много или многие-к-одному.

Запросы на это, как правило, очень эффективны, они используют индексы и не требуют разбора строк.

+0

+1: Но составной первичный ключ> составное уникальное ограничение –

+0

@OMG Ponies, да, но иногда людям нужен суррогатный ключ на этом столе. –

+0

Те же люди, что и ОРМ, и Майли Сайрус ... –

2

Ваши атрибуты отношения должны быть атомарными, но не состоящими из нескольких значений, таких как списки. Слишком сложно их искать. Вам нужно новое отношение, которое сопоставляет растения с идентификатором area_ID, и комбинация area_ID/plant является первичным ключом.

7

Как об этом:

таблицы: растения

plant_ID | name 
1  | tree 
2  | shrubbery 
20  | notashrubbery 

стол: районы

area_ID | name 
1  | forest 

стол: area_plant_map

area_ID | plant_ID | sequence 
1  | 1  | 0 
1  | 2  | 1 
1  | 20  | 2 

Это стандартный нормализованный способ сделать это (с таблица отображения).

Чтобы найти все районы с кустарником (завод 2), сделайте следующее:

SELECT * 
FROM areas 
INNER JOIN area_plant_map ON areas.area_ID = area_plant_map.area_ID 
WHERE plant_ID = 2 
+3

Я прочитал «shubbery» и теперь у вас есть рыцари Ни! skit, проходящий через мою голову ... –

+0

См. вопрос. В области 1 может быть такая последовательность растений: 2,20,1,2,2,20,1 (поэтому в области 1 есть 3 кустарника в положении 0,3 и 4) – Moak

+0

@Moak в этом случае просто поместите другой столбец с порядковым номером. –

2

Использование многие ко многим отношений:

CREATE TABLE plant (
    plant_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    name VARCHAR(255) 
) ENGINE=INNODB; 

CREATE TABLE area (
    area_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
    name VARCHAR(255) 
) ENGINE=INNODB; 

CREATE TABLE plant_area_xref (
    plant_id INT NOT NULL, 
    area_id INT NOT NULL, 
    sort_idx INT NOT NULL, 
    FOREIGN KEY (plant_id) REFERENCES plant(plant_id) ON DELETE CASCADE, 
    FOREIGN KEY (area_id) REFERENCES area(area_id) ON DELETE CASCADE, 
    PRIMARY KEY (plant_id, area_id, sort_idx)  
) ENGINE=INNODB; 

EDIT:

Просто в ответ ваш вопрос о бонусе:

Bonus Question Is it time to step away from MySQL? Is there a better DB to manage this? 

Это не имеет ничего общего с MySQL. Это была просто проблема с плохим дизайном базы данных. Вы должны использовать таблицы пересечений и отношения «многие ко многим» для таких случаев в каждой СУБД (MySQL, Oracle, MSSQL, PostgreSQL и т. Д.).

+0

разве это не пропустить sort_idx? 'plant_id, area_id' не является уникальным,' area_id/sort_idx' будет. Мне нужно иметь возможность сохранить эту последовательность неповрежденной 'area: 1' ->' plants: 2,20,1,2,2,20,1' (в указанном порядке) – Moak

+0

Добавлен sort_idx. plant_id, area_id не обязательно должны быть уникальными. Уникальность достигается двойным первичным ключом. –

+0

Да, но моя точка зрения заключается в том, что Area 1 - Plant 2 может быть двойным (одно и то же растение дважды в области, поэтому реальная уникальность - это область/sort_index. Я получил то, что мне нужно (двойное первичное), если вы измените его, тогда оно Я могу принять ответ. – Moak

Смежные вопросы