使用左连接select一对多关系中的第一条logging
我试图使用左连接来连接两个表。 结果集只能包含“右”连接表中的第一条logging。
假设我有两个表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”的logging(匹配什么logging并不重要)在左连接之后(它是一对多的映射)
我需要从表B中select第一个匹配的logging,并忽略所有其他行。
请帮忙!
谢谢
玩了一下后,结果比我想象的要复杂得多! 假设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 ) ;
另一种select: 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 ;
这会导致不确定的第一个匹配logging的左连接。 我的testing显示它比任何其他发布的解决scheme(在MS SQL Server 2012上)更快。
如果您使用的是SQL Server 2005或更高版本,则可以使用排名实现您想要的function。 尤其是, 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
答案最高的答案似乎并不正确,似乎过于复杂。 只需按子查询中表B的代码字段进行分组,然后select每个分组的最大ID即可。
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)
我修改了从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 ) ;
在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
这是如何:
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)
但关键是你必须在那里放置一些expression式来告诉查询处理器首先意味着什么。