Выберите первую запись в соотношении "один-ко-многим", используя левое соединение
Я пытаюсь присоединиться к двум таблицам, используя левое соединение. И набор результатов должен включать только первую запись из "правой" объединенной таблицы.
Предположим, что у меня есть две таблицы A и B, как показано ниже:
Таблица "A"
code | emp_no
101 | 12222
102 | 23333
103 | 34444
104 | 45555
105 | 56666
Таблица "B"
code | city | county
101 | Glen Oaks | Queens
101 | Astoria | Queens
101 | Flushing | Queens
102 | Ridgewood | Brooklyn
103 | Bayside | New York
Ожидаемый результат:
code | emp_no | city | county
101 | 12222 | Glen Oaks | Queens
102 | 23333 | Ridgewood | Brooklyn
103 | 34444 | Bayside | New York
104 | 45555 | NULL | NULL
105 | 56666 | NULL | NULL
Если вы заметили, что мой результат имеет только одну сопоставленную запись из таблицы "B" (не имеет значения, какая запись сопоставляется) после левого соединения (и это сопоставление от одного до многих)
Мне нужно выбрать первую совпадающую запись из таблицы B и игнорировать все остальные строки.
Пожалуйста, помогите!
Спасибо
Ответы
Ответ 1
Поиграв немного, это оказывается сложнее, чем я ожидал! Предполагая, что table_b
имеет один единственный столбец, который уникален (например, первичный ключ с одним полем), похоже, что вы можете это сделать:
SELECT table_a.code,
table_a.emp_no,
table_b.city,
table_b.county
FROM table_a
LEFT
JOIN table_b
ON table_b.code = table_a.code
AND table_b.field_that_is_unique =
( SELECT TOP 1
field_that_is_unique
FROM table_b
WHERE table_b.code = table_a.code
)
;
Ответ 2
Другая опция: OUTER APPLY
Если поддерживается базой данных, OUTER APPLY
является эффективным и кратким вариантом.
SELECT *
FROM
Table_A a
OUTER APPLY
(SELECT TOP 1 *
FROM Table_B b_1
WHERE b_1.code = a.code
) b
;
Это приводит к левому соединению к неопределенной первой согласованной записи. Мои тесты показывают, что это быстрее, чем любое другое опубликованное решение (на MS SQL Server 2012).
Ответ 3
Если вы используете SQL Server 2005 или более позднюю версию, вы можете использовать рейтинг для достижения что ты хочешь. В частности, ROW_NUMBER()
, подойдет вашим потребностям:
WITH B_ranked AS (
SELECT
*,
rnk = ROW_NUMBER() OVER (PARTITION BY code ORDER BY city)
FROM B
)
SELECT
A.code,
A.emp_no,
B.city,
B.county
FROM A
LEFT JOIN B_ranked AS B ON A.code = B.code AND b.rnk = 1
ИЛИ
WITH B_unique_code AS (
select * from(
SELECT
*,
rnk = ROW_NUMBER() OVER (PARTITION BY code ORDER BY city)
FROM B
) AS s
where rnk = 1
)
SELECT
A.code,
A.emp_no,
B.city,
B.county
FROM A
LEFT JOIN B_unique_code AS B ON A.code = B.code
Ответ 4
Я изменил ответ от ruakh, и это, похоже, отлично работает с mysql.
SELECT
table_a.code,
table_a.emp_no,
table_b.city,
table_b.county
FROM table_a a
LEFT JOIN table_b b
ON b.code = a.code
AND b.id = ( SELECT id FROM table_b
WHERE table_b.code = table_a.code
LIMIT 1
)
;
Ответ 5
Самый высокий проголосовавший ответ мне кажется неправильным, и он кажется слишком сложным.
Просто введите поле кода в таблице B в свой подзапрос и выберите максимальный идентификатор для каждой группы.
SELECT
table_a.code,
table_a.emp_no,
table_b.city,
table_b.county
FROM
table_a
LEFT JOIN
table_b
ON table_b.code = table_a.code
AND table_b.field_that_is_unique IN
(SELECT MAX(field_that_is_unique)
FROM table_b
GROUP BY table_b.code)
Ответ 6
В Oracle вы можете сделать:
WITH first_b AS (SELECT code, min(rowid) AS rid FROM b GROUP BY code))
SELECT a.code, a.emp_no, b.city, b.county
FROM a
INNER JOIN first_b
ON first_b.code = a.code
INNER JOIN b
ON b.rowid = first_b.rid
Ответ 7
вот как:
Select * From TableA a
Left Join TableB b
On b.Code = a.Code
And [Here put criteria predicate that 'defines' what the first record is]
Эй, если город и графство уникальны, используйте их
Select * From TableA a
Left Join TableB b
On b.Code = a.Code
And b.City + b.county =
(Select Min(city + county)
From TableB
Where Code = b.Code)
Но дело в том, что вам нужно добавить какое-то выражение, чтобы сообщить процессору запросов, что значит быть первым.