Как получить несколько записей против одной записи на основе отношения? - PullRequest
9 голосов
/ 19 сентября 2008

У меня есть две таблицы «Организация» и «Сотрудник», имеющие отношение «один ко многим», т.е. в одной организации может быть несколько сотрудников. Теперь я хочу выбрать всю информацию о конкретной организации плюс имя всех сотрудников этой организации. Какой лучший способ сделать это? Могу ли я получить все это в одном наборе записей, или мне придется получить несколько строк на основе нет. из сотрудников? Вот немного графическая демонстрация того, что я хочу:

Org_ID      Org_Address    Org_OtherDetails    Employess

1           132A B Road    List of details     Emp1, Emp2, Emp3.....

Ответы [ 8 ]

18 голосов
/ 20 сентября 2008

Первоначальный вопрос был специфичен для базы данных, но, возможно, это хорошее место, чтобы включить более общий ответ. Это общий вопрос. Концепцию, которую вы описываете, часто называют «объединением групп». Там нет стандартного решения в SQL-92 или SQL-99. Поэтому вам понадобится решение для конкретного поставщика.

  • MySQL - Вероятно, самое простое решение. Используйте встроенную функцию GROUP_CONCAT. В вашем примере вы хотели бы что-то вроде этого:
select 
  o.ID, o.Address, o.OtherDetails,
  GROUP_CONCAT( concat(e.firstname, ' ', e.lastname) ) as Employees
from 
  employees e 
  inner join organization o on o.org_id=e.org_id
group by o.org_id
  • PostgreSQL - РЕДАКТИРОВАТЬ: PostgreSQL 9.0 одинаково прост теперь, когда встроен string_agg (выражение, разделитель). Вот с запятой между элементами:
select 
  o.ID, o.Address, o.OtherDetails,
  STRING_AGG( (e.firstname || ' ' || e.lastname), ', ' ) as Employees
from 
  employees e 
  inner join organization o on o.org_id=e.org_id
group by o.org_id

PostgreSQL до 9.0 позволяет вам определять свои собственные агрегатные функции с помощью CREATE AGGREGATE. Чуть больше работы, чем MySQL, но гораздо более гибкий. Смотрите этот другой пост для более подробной информации. (Конечно, PostgreSQL 9.0 и новее также имеют эту опцию.)

  • Oracle & MS SQL Server - Создайте хранимую процедуру, которая принимает org_id в качестве входных данных и выводит объединенные имена сотрудников. Затем используйте эту хранимую процедуру в своем запросе. Некоторые другие ответы здесь включают некоторые детали о том, как писать хранимые процедуры, подобные этим.
select 
  o.ID, o.Address, o.OtherDetails,
  MY_CUSTOM_GROUP_CONCAT_PROCEDURE( o.ID ) as Employees
from 
  organization o
  • Другие технологии СУБД - Наиболее вероятен маршрут хранимой процедуры. Возможно, другие могут обновить этот ответ более специфичными для технологии ответами.
3 голосов
/ 20 сентября 2008

Поскольку вопрос помечен как MySQL, вы должны иметь возможность использовать решение, специфичное для MySQL, а именно GROUP_CONCAT. Например,

select Org_ID, Org_Address, Org_OtherDetails,
       GROUP_CONCAT(employees) as Employees
from  employees a, organization b
where a.org_id=b.org_id
group by b.org_id;
2 голосов
/ 19 сентября 2008

в MS SQL вы можете сделать:

create function dbo.table2list (@input int)
returns varchar(8000)
as
BEGIN
declare @putout varchar(8000)
set @putout = ''
select @putout = @putout + ', ' + <employeename>
from <employeetable>
where <orgid> = @input
return @putout
end

затем выполните:

select * from org, dbo.table2list(orgid)
from <organisationtable>

Я думаю, что вы можете сделать это и с COALESCE (), но не можете вспомнить синтаксис на макушке

0 голосов
/ 19 мая 2011

Для SQL Server SQLCLR агрегаты в этом проекте вдохновлены примером кода MSDN, однако они работают намного лучше и позволяют при необходимости сортировать (в виде строк) и альтернативные разделители. Они предлагают почти эквивалентную функциональность MySQL GROUP_CONCAT для SQL Server.

Полное сравнение преимуществ / недостатков агрегатов CLR и решения FOR XML можно найти в документации:

http://groupconcat.codeplex.com

0 голосов
/ 19 сентября 2008

Вот что вы можете сделать, у вас есть 2 варианта:

select *
FROM
  users u
  LEFT JOIN organizations o ON (u.idorg = o.id);

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

Или вы можете сделать:

select o.*, group_concat(u.name)
FROM
  users u
  LEFT JOIN organizations o ON (u.idorg = o.id)
GROUP BY
  o.id

http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat

Второй подход применим, если вы хотите увидеть, т.е. список имен пользователей «user1, user2, user3», но они не хотят работать с самими полями

0 голосов
/ 19 сентября 2008

Краткий ответ - «нет».

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

сожалею об этом: (

Предположительно, одно из решений для конкретного поставщика подойдет вам?

0 голосов
/ 19 сентября 2008

Все зависит. Если вы выполните объединение, вы получите все данные организации в каждой строке. (1 строка на сотрудника). Это имеет цену. Если вы делаете два запроса. (Org и Emp), который имеет другую стоимость.

Собери свой яд.

0 голосов
/ 19 сентября 2008

Если вы используете Oracle, вы можете создать функцию PL / SQL, которую вы можете использовать в своем запросе, которая принимает в качестве входных данных значение organization_id и возвращает имя всех сотрудников, принадлежащих к этой организации, в виде строки. Например: -

select
   o.org_id,
   o.org_address,
   o.org_otherdetails,
   org_employees( o.org_id ) as org_employees
from
   organization o
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...