关于sql:使用左连接选择一对多关系中的第一条记录

Select first record in a One-to-Many relation using left join

我正在尝试使用左连接来连接两个表。 结果集必须只包含"右"连接表中的第一条记录。

可以说我有两张表A和B如下;

表"A"

1
2
3
4
5
6
7
code | emp_no

101  | 12222
102  | 23333
103  | 34444
104  | 45555
105  | 56666

表"B"

1
2
3
4
5
6
code | city       | county
101  | Glen Oaks  | Queens
101  | Astoria    | Queens
101  | Flushing   | Queens
102  | Ridgewood  | Brooklyn
103  | Bayside    | NEW York

预期产出:

1
2
3
4
5
6
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中选择第一个匹配的记录并忽略所有其他行。

请帮忙!

谢谢


玩了一下之后,事实证明这比我想象的要复杂!假设table_b有一些唯一的列(例如,单字段主键),看起来你可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
       )
;


另一种选择:OUTER APPLY

如果数据库支持,OUTER APPLY是一个高效且简洁的选项。

1
2
3
4
5
6
7
8
9
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上)。


最高投票的答案对我来说似乎不正确,而且似乎过于复杂。
只需按子查询中表B上的代码字段进行分组,然后选择每个分组的最大Id。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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)


如果您使用的是SQL Server 2005或更高版本,则可以使用排名来实现所需。特别是,ROW_NUMBER()似乎很好地满足了您的需求:

1
2
3
4
5
6
7
8
9
10
11
12
13
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

要么

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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


我修改了ruakh的答案,这似乎与mysql完美配合。

1
2
3
4
5
6
7
8
9
10
11
12
13
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
           )
;

在Oracle中,您可以:

1
2
3
4
5
6
7
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


这是如何:

1
2
3
4
 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]

嘿,如果这个城市和县是独一无二的,那就用它们吧

1
2
3
4
5
6
7
   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)

但重点是你必须在那里放一些表达来告诉查询处理器首先意味着什么。