Интересно много-много sql join - PullRequest
5 голосов
/ 21 октября 2008

У меня есть три связанных таблицы «A (id, val)», «B (id, val)» и таблица ссылок со значением «AB (помощь, ставка, val)»

Я запрашиваю у B, чтобы вернуть значения A, например:

SELECT A.* 
FROM A INNER JOIN AB ON A.id = AB.aid INNER JOIN B ON AB.bid = B.id
WHERE B.val = 'foo';

У каждого А есть много Б, и у каждого Б много А.

И уловка, на которой я разбираюсь, заключается в необходимости фильтровать набор так, чтобы запрос возвращал строки только тогда, когда AB.val является максимумом для любой данной пары A / B

например. если у меня есть данные:

A

id   val
1    something
2    somethingelse

B

id   val
1    foo
2    bar

AB

aid  bid  val
1    1    3
1    2    2
2    1    1
2    2    4

Я бы хотел выбрать только первую и последнюю строки AB, так как они являются максимальными значениями для каждого из A, а затем иметь возможность запросить B.val = 'foo', чтобы вернуть только первую строку. Я понятия не имею, как можно ограничиться только строкой max val в таблице AB.

Лучшее, что я смог получить, это

SELECT * 
FROM A 
INNER JOIN 
  (SELECT aid, bid, MAX(val) AS val FROM AB GROUP BY aid) as AB
  ON A.id = AB.aid 
INNER JOIN B ON AB.id = B.id
WHERE B.val = 'foo'

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

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

(Для тех, кто интересуется, фактическое использование этого для бэкэнда словаря, где A - это таблица слов, а B - таблица фонем. AB - это таблица WordPhoneme со столбцом 'position'. Запрос состоит в том, чтобы найти все слова заканчивающийся указанной фонемой (фонема - это звук слова, по своему употреблению аналогичный международному фонетическому алфавиту)

Ответы [ 5 ]

2 голосов
/ 21 октября 2008

Я думаю, вам нужно сделать еще одно объединение, чтобы сначала получить максимальное значение ab для каждого a.id.

Примерно так:

select a.*
from a
left join (
    select aid, max(val) as val 
    from ab 
    group by aid
) abmax on abmax.aid=a.id
inner join ab on ab.aid=abmax.aid and ab.val=abmax.val
inner join b on b.id=ab.bid
where b.val='foo'
1 голос
/ 21 октября 2008

Я часто использую следующий трюк, чтобы получить наибольшее в группе:

SELECT a.*
FROM ab AS ab1
  LEFT OUTER JOIN ab AS ab2 ON (ab1.aid = ab2.aid AND ab1.val < ab2.val)
  JOIN a ON (ab1.aid = a.id)
  JOIN b ON (ab1.bid = b.id)
WHERE ab2.aid IS NULL
  AND b.val = 'foo';

Хитрость заключается в том, чтобы присоединиться к таблице АБ к себе во внешнем соединении. Вернуть ab1, где нет строк с одинаковым значением для помощи и большим значением для val. Следовательно, ab1 имеет наибольшее значение в группе строк с заданным значением для помощи.

1 голос
/ 21 октября 2008

Вот еще один способ, который я только что проверил:

select a.*
from ab
   inner join b on(ab.bid=b.id)
   inner join a on (ab.aid=a.id)
where ab.val = (select max(val) from ab AS ab2 where ab2.aid = ab.aid)
   and b.val='foo'
0 голосов
/ 21 октября 2008
SELECT *
FROM
(
  SELECT
    A.*,
    (SELECT top 1 AB.BID FROM AB WHERE A.AID = AB.AID ORDER BY AB.val desc) as BID
  FROM A
) as Aplus
JOIN B ON Aplus.BID = B.BID
0 голосов
/ 21 октября 2008

Я не уверен, какой sql вы используете, но в MS SQL я создаю табличную функцию базы данных, которая возвращает максимальные значения из таблицы A, затем присоединяю это к таблице B. Я считаю, что это гораздо проще понять, чем сложные объединения Я оглядываюсь назад на свои вопросы на более позднем этапе.

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