Как мне перечислить нормализованные данные из MySQL в PHP? - PullRequest
0 голосов
/ 19 декабря 2009

Мне всегда трудно иметь дело с нормализованными данными и способами их отображения. Возможно, потому, что я не совсем понимаю правила нормализации, например, как полностью включить его в Бойс-Кодд. На данном этапе производительность не является проблемой, хотя ремонтопригодность схемы снижается.

Пользователь

ID  Name
1   Alice
2   Bob
3   Charlie

навыки

ID   Name
1    Karate
2    Marksmen
3    Cook

событие

ID   Name
1    Island
2    Volcano

пользователь-M2M-умение

MemberID  SkillID
1         1
1         2
2         1
2         3
3         1

пользователь M2M-событие

MemberID  EventID
1         1
1         2
2         1
3         2

Как мне получить эту информацию из базы данных? Я хотел бы отобразить такую ​​таблицу, где у меня есть общее количество каждого навыка:

Навыки на событии

Event    Karate Marksmen Cook
Island   2      1        1
Volcano  2      1        0

Маловероятно, что таблица навыков сильно изменится. Это означает, что я мог бы сделать такой набор подзапросов (очевидно, сокращенный и неправильный синтаксис)

SELECT event.name,
  (SELECT COUNT(*) FROM ... WHERE skill = 'Karate'), 
  (SELECT COUNT(*) FROM ... WHERE skill = 'Marksmen') FROM event

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

Другой способ обработать его на стороне клиента. Так что я просто возвращаюсь примерно так:

Event   Skill    Count
Island  Karate   2
Island  Marksmen 1
Island  Cook     1
Volcano Karate   2
Volcano Marksmen 1

И я перебираю результаты, переформатируя их. Но я ненавижу это еще больше. Разве база данных не должна делать данные?

Итак: что я делаю не так? Я ожидаю слишком многого? Какое меньшее зло?

(Как сказал бы b3ta, извиняюсь за длину поста и за плохую разметку. :()

Ответы [ 3 ]

1 голос
/ 19 декабря 2009

Это типичный сводный запрос, потому что вы хотите преобразовать данные в строках в столбцы.

   SELECT e.name,
          MAX(CASE WHEN x.skill_name = 'Karate' THEN x.num_skill ELSE 0) END AS Karate,
          MAX(CASE WHEN x.skill_name = 'Marksmen' THEN x.num_skill ELSE 0 END) AS Marksmen
     FROM EVENT e
LEFT JOIN (SELECT um.eventid,
                  s.name AS skill_name,
                  COUNT(*) 'num_skill'
             FROM SKILLS s
             JOIN USER-M2M-SKILL us ON us.skillid = s.id
             JOIN USER-M2M-EVENT um ON um.memberid = us.memberid
         GROUP BY um.eventid, s.name) x ON x.eventid = e.id
 GROUP BY e.name

Дополнительный вопрос:

... что это означает, что загрузка подзапросов этого не делает?

SELECT как операторы в предложении SELECT. IE:

SELECT x.name,
       (SELECT COUNT(*) FROM TABLE)

... означает, что для каждого навыка выполняется отдельный запрос. Если бы запросы были коррелированы - если они были связаны между собой идентификатором, чтобы убедиться, что записи синхронизированы с событием, то счетчик будет работать для каждого события.

Заключение к продолжению

Подход ужасно неэффективен. Лучше всего получить нужные значения один раз, как я указал в своем ответе.

Добавление

Что касается обновления запроса - можно минимизировать обслуживание путем реализации запроса с динамическим SQL.

0 голосов
/ 19 декабря 2009

Кто такой b3ta?

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

0 голосов
/ 19 декабря 2009

Ваш второй пример с «Event», «Skill» и «Count» в качестве заголовков - это то, что вы должны ожидать от динамически генерируемых результатов из нормализованных данных. Базы данных не предназначены для форматирования данных для отображения (это не электронная таблица Excel), они предназначены для хранения данных и возврата , что означает этих данных. Это зависит от вашего кода, чтобы отобразить его в хорошем стиле.

...