Выберите первую запись в соотношении "один-ко-многим", используя левое соединение

Я пытаюсь присоединиться к двум таблицам, используя левое соединение. И набор результатов должен включать только первую запись из "правой" объединенной таблицы.

Предположим, что у меня есть две таблицы 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)

Но дело в том, что вам нужно добавить какое-то выражение, чтобы сообщить процессору запросов, что значит быть первым.