#mysql #sql #database
#mysql #sql #База данных
Вопрос:
У меня есть три таблицы. Foo, Attrib, FooAttrib . Где FooAttrib — это мост между foo и attrib . Как вы можете видеть, в таблице много foo и много атрибутов.
Foo FooAttri Attrib
------------ ----------------------------- --------------
| id | Name | | fooId | attribId | value | | id | Descrip |
|----|-------| |---------|-----------|-------| |----|---------|
| 1 | Sam | | 1 | 1 | red | | 1 | Color |
| 2 | Bill | | 1 | 2 | Grape | | 2 | Flavor |
| 3 | Ted | | 2 | 1 | Blue | | 3 | Weight |
------------ | 3 | 3 | 10 | --------------
| 1 | 3 | 5 |
| 2 | 3 | 1 |
-----------------------------
Я знаю, как получить следующее:
fooId Name Attrib Value
1 Sam Color red
1 Sam Flavor Grape
1 Sam Weight 5
2 Bill Color Blue
2 Bill Weight 1
3 Ted Weight 10
Но что я хочу знать; Возможно ли создать оператор select, чтобы я получал данные foo и attrib, возвращаемые в одном результирующем наборе, который выглядит следующим образом?
fooId Name Color Flavor Weight
1 Sam red Grape 5
2 Bill Blue 1
3 Ted 10
Комментарии:
1. У вас есть базовая модель EAV (Entity-Attribute-Value), которая представляет собой моделирование, ориентированное на столбцы, а процесс преобразования из модели столбца> строки называется поворотом. Поиск в Google для поворота или поиска на этом сайте того же термина должен дать вам представление о том, как это сделать, однако лучший подход — сделать это в приложении (php, c, python или что бы вы ни использовали), чем пытаться сделать это в MySQL.
2. @N.B. Спасибо за ответ, сама терминология очень полезна. Я попробую.
3. Вы понимаете, что модель данных EAV очень сложна для запроса и очень плоха для производительности. Это наихудший возможный дизайн для большинства вещей в реляционной базе данных и является антипаттером SQL. Если вам действительно нужен EAV, я бы предложил базу данных nosql.
Ответ №1:
Вы могли бы сделать это, если знаете общее количество возможных аргументов, которые вы хотите в момент выбора:
select f.id, f.name, fa_color.value as color, , fa_flavor.value as flavor
from foo f
join fooattri fa_color on f.id = fa_color.fooid and fa_color.attribid = 1
join fooattri fa_flavor on f.id = fa_flavor.fooid and fa_flavor.attribid = 2
...
Комментарии:
1. Спасибо за ответ… что, если я не знаю количество атрибутов, которые у меня будут? Или другой способ задать этот вопрос: что, если список атрибутов может измениться (к нему добавлено больше)?
2. Проблема при повороте заключается в том, что вы должны знать максимум. количество атрибутов, чтобы вы знали, сколько раз вам нужно самостоятельно присоединяться к таблице. В противном случае вы не сможете получить обычный макет. Вот почему люди обычно делают этот поворот на языках приложений, поскольку это проще и быстрее. Если вы собираетесь запросить свой набор данных EAV, создав сводную таблицу или представление — не беспокойтесь, это будет ужасно, ужасно медленно.
3. С таблицами EAV вы должны заранее знать количество атрибутов, потому что вам нужно присоединиться к таблице один раз для каждого атрибута. Это одна из причин, по которой этот дизайн является очень плохой идеей.
4. Да, я предоставляю этот ответ как возможное «решение». Но это может работать только в ограниченном подмножестве ситуаций.
5. @kasdega Другим возможным «дополнением» к этому «решению» было бы сначала запросить возможные атрибуты, а затем создать на их основе динамический оператор select. Но переход «по вертикали» намного лучше.
Ответ №2:
Попробуйте это, этот метод обычно работает для меня:
SELECT fo.id, fo.name,
(SELECT fooattri.value
FROM fooattri
INNER JOIN attrib ON attrib.id = fooattri.attribid
WHERE attrib.descrip = 'Color'
AND fooattri.fooid = fo.id) AS Color,
(SELECT fooattri.value
FROM fooattri
INNER JOIN attrib ON attrib.id = fooattri.attribid
WHERE attrib.descrip = 'Flavor'
AND fooattri.fooid = fo.id) AS Flavor,
(SELECT fooattri.value
FROM fooattri
INNER JOIN attrib ON attrib.id = fooattri.attribid
WHERE attrib.descrip = 'Weight'
AND fooattri.fooid = fo.id) AS Weight
FROM foo fo