Как выполнить внешнее соединение двух таблиц (основной таблицы и вложенной таблицы многие-к-одному), чтобы получить только ОДИН элемент из второй таблицы? - PullRequest
1 голос
/ 20 марта 2009

У меня есть две таблицы, которые выглядят примерно так:

Основная таблица: id (int), title (varchar) и т. Д. Подтаблица: main_table_id (внешний ключ в основной таблице), тег (varchar) и т. Д.

Для данной строки в основной таблице может быть ноль или более субтаблиц.

Я хочу сделать запрос, который будет возвращать каждую строку основной таблицы со столбцами основной таблицы и столбцами только из одной строки (неважно, какая) из вложенной таблицы, если в этих столбцах они есть, иначе NULL.

Конечно, если я просто выполню простое ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ, тогда, конечно, я получу повторение основной таблицы несколько раз, по одному на каждое совпадение в подстол.

Я уверен, что видел, как это было сделано до использования LEFT OUTER JOIN и какой-то хитрости, которая заставляет выбрать только одну строку из вложенной таблицы, а не все - возможно, выбирая минимум или максимум OID. Однако более часа поиска в Google не принесло никаких решений.

Кто-нибудь имеет этот трюк в своем инструментальном поясе?

Ответы [ 4 ]

4 голосов
/ 20 марта 2009

Если вы используете SQL Server, вы можете использовать предложение TOP. Если это что-то отличное от SQL Server, вам нужно посмотреть, предлагает ли эта база данных нечто эквивалентное (многие из них делают). Как то так ...

Select * from Main m
left outer join 
(select top 1 * from subtable s
  where s.main_table_id = m.id) q
on q.main_table_id = m.id;

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

2 голосов
/ 20 марта 2009

Мне больше нравится ответ Чарли, но я не уверен, есть ли у Postges функция TOP / LIMIT, поэтому вот альтернативное решение, в котором оно не нужно (но предполагается, что sub_table имеет первичный ключ с именем "id"):

SELECT * 
FROM main_table m LEFT OUTER JOIN sub_table s 
ON s.main_table_id = m.id
WHERE s.id IS NULL OR s.id IN ( 
  SELECT MAX(id) FROM sub_table GROUP BY main_table_id
)
0 голосов
/ 18 сентября 2015

Забавный метод в Postgres (совсем не школьный):

SELECT * 
 FROM main_table m left join (
   select (max(s::character varying)::subtable).* from subtable s group by main_table_id 
 ) s ON s.main_table_id = m.id

Объяснение:
Вы выбираете полную запись как одно поле:

select s from subtable s

Вы разыгрываете это как персонажа, изменяющегося, чтобы иметь возможность использовать максимальный агрегат (или мин ...)

 select max(s::character varying) from subtable s group by main_table_id

Вы получаете только одну строку из main_table_id, содержащую varchar, представляющий вашу запись, поэтому мы должны снова привести ее в «subtable» и взорвать ее -> (myvarchar :: subtable). *

select (max(s::character varying)::subtable).* from subtable s group by main_table_id 

Вы получаете хорошо сформированный подтаблицу таблицы всего за одну строку с помощью main_table_id

0 голосов
/ 20 марта 2009

Если вы просто проверяете, есть ли во второй таблице что-то, что соответствует элементам в первой таблице, вы можете использовать внешнее соединение с предложением group by и агрегатом:

select t1.[name], count(t1.[name]) as t2count
   from table1 t1
   left outer join table2 t2 on t1.fk = t2.pk
group by t1.[name]

Тогда все, что имеет 0 для t2count, будет тем, у которого ничего нет в table2

edit: на самом деле, я не помню, будет ли в t2count нулевое значение или 0 ... это должно быть одно из этих значений.

...