从左外连接获取不同的行

Naz*_*gul 20 sql sql-server sql-server-2005 linq-to-sql

我正在构建一个动态生成sql的应用程序来搜索特定表的行(这是主域类,如Employee).

Table1,Table2和Table1Table2Map有三个表.Table1与Table2有多对多的关系,并通过Table1Table2Map表进行映射.但由于Table1是我的主要表格,因此这种关系几乎就像一对一.

我的应用程序生成一个sql,它基本上给出了一个包含所有这些表中的行的结果集.select子句和连接不会更改,而where子句是基于用户交互生成的.在任何情况下,我都不希望在我的结果集中重复使用Table1,因为它是结果显示的主表.现在,生成的查询是这样的:

select distinct Table1.Id as Id, Table1.Name, Table2.Description from Table1
left outer join Table1Table2Map on (Table1Table2Map.Table1Id = Table1.Id)
left outer join Table2 on (Table2.Id = Table1Table2Map.Table2Id)
Run Code Online (Sandbox Code Playgroud)

为简单起见,我排除了where子句.问题是Table2中Table1中有多行,即使我已经说明了Table1的不同.Id结果集有重复的Table1行,因为它必须选择Table2中的所有匹配行.

为了详细说明,请考虑对于Table1中Id = 1的行,Table1Table2Map(1,1)和(1,2)中有两行将Table1映射到Table2中的两行,其中ID为1,2.上述查询返回这种情况下重复的行.现在我希望查询只返回Id 1一次的Table1行.这是因为Table2中只有一行类似于Table1中相应条目的活动值(此信息在Mapping表中).有没有办法可以避免获取Table1的重复行.

我认为我试图解决问题的方式存在一些基本问题,但我无法弄清楚它是什么.提前致谢.

ang*_*son 25

尝试:

left outer join (select distinct YOUR_COLUMNS_HERE ...) SUBQUERY_ALIAS on ...
Run Code Online (Sandbox Code Playgroud)

换句话说,不要直接加入表,加入一个限制你加入的行的子查询.

  • 请你举一个完整的例子,这样会更清楚,因为我迷失在这里..谢谢:) (2认同)
  • 下面是一个更完整的示例,其中按描述添加了附加过滤器: `SELECT t1.Id, t1.Name, tAlias.Description FROM t1 LEFT JOIN ( SELECT Id, Name FROM t2 WHERE Description LIKE 'Hello%' GROUP BY Id, Name ) AS tAlias ON t1.Id = tAlias.Id AND t1.Name = tAlias.Name` (2认同)

kom*_*mer 12

你可以使用 GROUP BY on Table1.Id,这将摆脱额外的行.你不需要担心加入方面的任何机制.

我在一个巨大的查询中提出了这个解决方案,而且这个解决方案并没有太多影响查询时间.

注意:我在被问到3年后回答这个问题,但这可能对我相信的人有所帮助.


Joh*_*ibb 7

您可以将左连接重写为外部适用,以便您可以按如下方式使用前1和顺序:

select Table1.Id as Id, Table1.Name, Table2.Description 
from Table1
outer apply (
   select top 1 *
   from Table1Table2Map
   where (Table1Table2Map.Table1Id = Table1.Id) and Table1Table2Map.IsActive = 1
   order by somethingCol 
) t1t2
outer apply (
   select top 1 *
   from Table2
   where (Table2.Id = Table1Table2Map.Table2Id)
) t2;
Run Code Online (Sandbox Code Playgroud)

请注意,没有"top"或"order by"的外部应用完全等同于左外部连接,它只是为您提供更多控制.(交叉申请相当于内部联接).

你也可以使用row_number()函数做类似的事情:

 select * from (
      select distinct Table1.Id as Id, Table1.Name, Table2.Description,
        rowNum = row_number() over ( partition by table1.id order by something )
      from Table1
      left outer join Table1Table2Map on (Table1Table2Map.Table1Id = Table1.Id)
      left outer join Table2 on (Table2.Id = Table1Table2Map.Table2Id)
 ) x
 where rowNum = 1;
Run Code Online (Sandbox Code Playgroud)

如果IsActive标志可以将您的其他表缩小到一行,则大多数情况不适用,但它们可能会对您有用.