SQL LEFT JOIN只返回第一行
SQL LEFT JOIN只返回第一行
假设我们有这样的数据集:
表:DataTable1
ID ExperienceId LanguageId ... ------------------------------------------- 1 1 1 2 1 2 3 1 3 4 2 1 5 2 2 6 2 3 7 3 1 8 3 2 9 3 3 ...
表:DataTable2
ID SomeId OtherId LanguageId ... ------------------------------------------- 1 459 1 1 2 459 1 2 3 459 1 3 4 245 2 1 5 245 2 2 6 245 2 3 7 295 3 1 8 295 3 2 9 295 3 3 ...
我想连接这些表,并仅获取SomeId列,忽略LanguageId列。为了更清楚地说明:
SELECT t2.SomeId AS RequiredId -- ...主要是来自t2的其他数据 FROM DataTable1 AS t1 LEFT JOIN DataTable2 AS t2 ON t2.OtherId = t1.ExperienceId AND t2.LanguageId = (SELECT TOP 1 t1.LanguageId ORDER BY t1.LanguageId)
如果查询没有错误,这个查询应该返回以下行:
SomeId ... ---------------- 459 ... 245 ... 295 ... ...
现在它返回了三倍的相同数据(只有LanguageId不同)。
如果我确定它总是存在,我会尝试用WHERE t1.LanguageId = 1
进行过滤,但我不确定。行可以具有从1到3的LanguageId,也可以仅具有ID 2等。行肯定会至少有一个LanguageId。
现在我的问题是:如何连接具有唯一值的表,忽略一个完全不相关的列?
问题出现的原因是在SQL语句中使用了LEFT JOIN关键字,但是需要获取的结果只是LEFT JOIN连接中的第一行数据。解决方法有两种:一种是将查询的结果再套一层查询,另一种是在查询中不提取需要的列。
第一种方法的SQL语句如下:
SELECT RequiredId, <all_the_other_fields> from ( SELECT t2.SomeId AS RequiredId -- ...other data mainly from t2 FROM DataTable1 AS t1 LEFT JOIN DataTable2 AS t2 ON t2.OtherId = t1.ExperienceId AND t2.LanguageId = (SELECT TOP 1 t1.LanguageId ORDER BY t1.LanguageId) ) group by RequiredId, <all_the_other_fields>
第二种方法的SQL语句如下:
SELECT distinct t2.SomeId AS RequiredId -- ...other data mainly from t2 BUT not the Language id FROM DataTable1 AS t1 LEFT JOIN DataTable2 AS t2 ON t2.OtherId = t1.ExperienceId AND t2.LanguageId = (SELECT TOP 1 t1.LanguageId ORDER BY t1.LanguageId)
感谢回答者的第一种方法,它解决了我的问题。之前在使用EF时遇到了问题,直到我看到我的GROUP BY子句在内部查询中而不是外部查询中。我改变了这一点,现在它可以正常工作了。
在这段代码中,出现了一个问题:需要使用 LEFT JOIN
来获取 DataTable1
和 DataTable2
的关联数据,但是只需要 DataTable2
中的第一行数据。
问题的原因是,使用 LEFT JOIN
时,会返回所有匹配条件的数据行。但是在实际需求中,只需要获取 DataTable2
中和 DataTable1
匹配的第一行数据。
解决这个问题的方法是,使用 OUTER APPLY
子查询,并在子查询中使用 TOP 1
和 ORDER BY
来限制结果集只返回第一行数据。这样就可以达到只获取第一行数据的目的。
下面是修改后的代码示例:
SELECT t1.SomeId AS RequiredId, -- ...other data mainly from t1 t2.LanguageId FROM DataTable1 AS t1 OUTER APPLY ( SELECT TOP 1 t2.LanguageId FROM DataTable2 AS t2 WHERE t2.OtherId = t1.ExperienceId AND t2.LanguageId = t1.LanguageId ORDER BY t2.LanguageId ) AS t2
问题的出现原因是在使用SQL的LEFT JOIN操作时,需要从两个表中联接数据,但只需要获取其中一个表的第一行数据。在没有特定方法的情况下,LEFT JOIN操作会返回所有匹配的行,而不仅仅是第一行。
为了解决这个问题,可以使用CTE(通用表达式)和ROW_NUMBER函数来获取每个someid分组中的第一行数据,并将其与datatable1进行LEFT JOIN操作。以下是解决方法的代码:
;with cte as (select *, row_number() over (partition by someid order by languageid) rn from datatable2) select * from datatable1 dt left join cte c on dt.experienceid = c.otherid and c.rn = 1
以上代码使用CTE创建了一个临时表cte,其中包含datatable2表的所有数据,并根据someid分组和languageid排序。ROW_NUMBER函数在每个分组中为每行分配一个唯一的行号。然后,使用LEFT JOIN操作将datatable1和cte表连接,条件是experienceid等于otherid,并且行号rn等于1,这样就只返回了datatable1中的第一行数据。