Несколько столбцов подвыбрать в MySQL 5 (5.1.42) - PullRequest
5 голосов
/ 15 марта 2010

Эта проблема кажется простой, но я не могу заставить ее работать за один раз. выберите или вложенный выберите . Получить авторов и (если таковые имеются) советники бумага (статья) в один ряд.

Я приказываю объяснить проблему, вот две таблицы данных (псевдо)

papers (id, title, c_year)
persons (id, firstname, lastname)

плюс таблица ссылок с одним дополнительным атрибутом (псевдо):

paper_person_roles(
  paper_id
  person_id
  act_role ENUM ('AUTHOR', 'ADVISER')
)

Это в основном список письменных работ (таблица: документы) и список сотрудников и / или студентов (таблица: человек)

Статья моих авторов (1, N).
Статья может иметь (0, N) советников.
Человек может быть в роли «АВТОР» или «СОВЕТНИК» (но не одновременно).

Приложение в конечном итоге выводит строки таблицы, содержащие следующие записи:

TH: || Paper_ID  |  Author(s)          |   Title                 |   Adviser(s)  |
TD: ||   21334   |John Doe, Jeff Tucker|Why the moon looks yellow|Brown, Rayleigh|
...

Мой первый подход был такой:
выбрать / извлечь полный список статей в приложение, например,

SELECT 
   q.id, q.title
FROM 
   papers AS q
ORDER BY 
   q.c_year
и сохранить результаты запроса в массив (в приложении). После этого шаг, цикл по массиву возвращенной информации и извлекать авторов и советники (если таковые имеются), через подготовленное заявление (? это идентификатор бумаги) из таблицы ссылок как:
APPLICATION_LOOP(paper_ids in array)
  SELECT 
      p.lastname, p.firstname, r.act_role 
  FROM 
      persons AS p, paper_person_roles AS r
   WHERE 
      p.id=r.person_id AND r.paper_id = ?
   # The application does further processing from here (pseudo):
   foreach record from resulting records
     if  record.act_role eq 'AUTHOR' then join to author_column
     if  record.act_role eq 'ADVISER' then join to avdiser_column
   end
   print id, author_column, title, adviser_column
APPLICATION_LOOP
Это работает до сих пор и дает желаемый результат. Будет ли это сделать смысл положить вычисления обратно в БД?

Я не очень опытный в нетривиальном SQL и не могу найти решение с помощью одного (комбинированного или вложенного) вызова select. я попробовал что-нибудь как

SELECT
    q.title 
    (CONCAT_WS(' ',
     (SELECT p.firstname, p.lastname AS aunames
      FROM persons AS p, paper_person_roles AS r
      WHERE q.id=r.paper_id AND r.act_role='AUTHOR')
     )
    ) AS aulist
FROM 
    papers AS q, persons AS p, paper_person_roles AS r
в нескольких вариациях, но не повезло ...

Может быть, есть шанс?

Заранее спасибо

круглодонный

Ответы [ 2 ]

2 голосов
/ 16 марта 2010

Следующий запрос работал с моими тестовыми данными, пожалуйста, попробуйте.

Два подзапроса необходимы для получения списка авторов / консультантов по статье.

Select
  p.id,
  p.title,
  p_aut.aut_name,
  p_adv.adv_name
From papers p
Left Join (
  Select pp_aut.paper_id,
         Group_Concat(Concat(p_aut.firstname, ' ', p_aut.lastname)) aut_name
  From paper_person_roles pp_aut
  Join persons p_aut On (p_aut.id = pp_aut.person_id)
  Where pp_aut.act_role='AUTHOR'
  Group By pp_aut.paper_id
) p_aut On ( p_aut.paper_id = p.id )
Left Join (
  Select pp_adv.paper_id,
         Group_Concat(Concat(p_adv.firstname, ' ', p_adv.lastname)) adv_name
  From paper_person_roles pp_adv
  Join persons p_adv On (p_adv.id = pp_adv.person_id)
  Where pp_adv.act_role='ADVISER'
  Group By pp_adv.paper_id
) p_adv On ( p_adv.paper_id = p.id )
Group By p.id, p.title
2 голосов
/ 16 марта 2010

По моему опыту, базы данных SQL не очень хороши для объединения подобных табличных данных в единый ряд сжатых данных. В принципе, я думаю, что подход, который вы используете, хорош, но другая альтернатива, которая мне выпадает, состоит в том, чтобы просто присоединиться к таблице лиц, так что вы получите одну строку назад для каждого человека, у которого есть роль для данной статьи.

Что-то вроде:

    SELECT q.id, q.title, p.firstName, p.lastName, r.act_role FROM papers q, persons p, 
        paper_person_roles r where r.paper_id = q.id and r.person_id = p.id

Который для приведенного выше примера даст вам данные, подобные следующим:

21334   |Why the moon looks yellow|John Doe   |AUTHOR
21334   |Why the moon looks yellow|Jeff Tucker|AUTHOR
21334   |Why the moon looks yellow|Brown      |ADVISER
21334   |Why the moon looks yellow|Rayleigh   |ADVISER

, что достаточно просто для анализа конечного результата, который вы ищете.

С такими вещами, это все о компромиссах:
- Вы тратите слишком много времени, возвращаясь к базе данных снова и снова?
- Слишком много данных, которые вы не можете объединить сразу?
- В результате ваша «оптимизация» делает ваш код слишком трудным для чтения?

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

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