如何从视图中删除“重复”的行?

4

我有一个视图,在将主表连接时正常工作:

LEFT OUTER JOIN OFFICE ON CLIENT.CASE_OFFICE = OFFICE.TABLE_CODE.

然而,我需要添加以下连接:
LEFT OUTER JOIN OFFICE_MIS ON CLIENT.REFERRAL_OFFICE = OFFICE_MIS.TABLE_CODE 

尽管我添加了“DISTINCT”,但我仍然得到了一个“重复”的行。我之所以说“重复”,是因为第二行有一个不同的值。
但是,如果我将“LEFT OUTER”更改为“INNER JOIN”,那么我将失去所有客户端的这些“重复”行。
我做错了什么?如何从我的视图中删除这些“重复”行?

注意:

此问题在本例中不适用:

如何删除重复行?


1
您介意整理一下您的问题,并使用更明确的示例来使用代码块吗? - hythlodayr
5个回答

8
如果行中有任何不同的列,DISTINCT 将无法帮助您。显然,您连接的其中一个表对于另一个表中的单个行具有多个行。为了获得一行返回,您必须消除您连接到的表中的其他多行。
最简单的方法是增强 where 子句或 JOIN 限制,仅加入您想要的单个记录。通常需要确定一个规则,该规则将始终从其他表中选择“正确”的条目。
让我们假设您有一个简单的问题,例如:
Person:  Jane
Pets: Cat, Dog

如果您在此处创建一个简单的连接,您将会收到两条关于 Jane 的记录:

Jane|Cat
Jane|Dog

如果你的目的是列出所有人和宠物的组合,那么这完全正确。但是,如果你的目的是列出有宠物的人,或者列出人和他们其中一只宠物,那么你现在就遇到了问题。为此,你需要一个规则。

SELECT Person.Name, Pets.Name
FROM Person
  LEFT JOIN Pets pets1 ON pets1.PersonID = Person.ID
WHERE 0 = (SELECT COUNT(pets2.ID) 
             FROM Pets pets2
             WHERE pets2.PersonID = pets1.PersonID
                AND pets2.ID < pets1.ID);

这个操作是应用一个规则来限制连接中的Pets记录,只保留ID最小的Pet(在Pets表中排名第一)。WHERE子句实际上是说“当没有属于同一个人的宠物具有更低的ID值时”。

这将产生一个记录结果:

Jane|Cat

您需要应用于视图的规则取决于您所拥有的列中的数据以及哪些“多个”记录应在该列中显示。但这会隐藏一些数据,这可能不是您想要的。例如,上述规则隐藏了Jane拥有一只狗的事实。它使Jane只有一只猫,而这是不正确的。
如果您开始过滤有效数据,则可能需要重新考虑视图的内容以及您试图通过视图实现的目标。

那是一种有趣的做法。比起我答案中的选择 top 1 子查询,它更快吗? - dotjoe
我不确定它是否比选择顶部更快,但我想展示一个应用规则的通用示例。上面的选择也可以有完全不同的WHERE子句,或者可能对JOIN进行限制,例如“where Pets.Name ='Cat'”。概念是需要规则,并且它必须针对正在开发的视图和需要呈现的数据的上下文进行具体化。 - Jay S

3

所以你添加了一个左外连接,匹配了两行?我假设OFFICE_MIS.TABLE_CODE在该表中不是唯一的?你需要将该连接限制为仅获取一行。这取决于你要查找哪一行,但你可以像这样做...

LEFT OUTER JOIN OFFICE_MIS ON 
  OFFICE_MIS.ID = /* whatever the primary key is? */
    (select top 1 om2.ID
    from OFFICE_MIS om2
    where CLIENT.REFERRAL_OFFICE = om2.TABLE_CODE
    order by om2.ID /* change the order to fit your needs */)

2

不要使用 DISTINCT,你可以使用 GROUP BY

  • 按照想要作为唯一值返回的所有字段进行分组。
  • 使用 MIN/MAX/AVG 或任何其他函数,为可能返回多个值的字段提供一个结果。

示例:

SELECT Office.Field1, Client.Field1, MIN(Office.Field1), MIN(Client.Field2)  
FROM YourQuery  
GROUP BY Office.Field1, Client.Field1

2
如果第二行有一个不同的值,那么它并不是重复的,应该包括在内。

其实并不是。主表只有一行,而我在视图中只需要一行,即使数据有误也是如此。两行数据在我的报表中引发了混乱。 - Fet

1

你可以尝试使用Distinct Top 1,但正如Hunter所指出的,如果有一个列不同,那么它应该被包含,或者如果你不关心或不需要这个列,你应该将其删除。任何其他建议可能需要更具体的信息。

编辑:当使用Distinct Top 1时,你需要有一个适当的group by语句。你实际上会使用Top 1部分。Distinct在其中是因为如果有一个平局,你将得到一个错误,而没有一些避免平局的方法。我见过的最常见的两种方法是在Top 1中添加Distinct,或者你可以在查询中添加一个唯一的列,这样SQL就有了选择哪条记录在否则会平局的情况下选择哪条记录的方法。


我已经使用了DISTINCT。我不能使用DISTINCT TOP 1 - 我有500,000条记录,需要对它们进行报告。 - Fet
非常感谢您,Rich B。我会采纳您的建议。 - Fet
谢谢Bryan。我会采纳您的建议。 - Fet
@Lieven:你的解决方案到目前为止对我很有效。否则,我无法完全更改涉及5个表之间JOIN和3个这样的查询之间UNION的查询。谢谢。 - Kumar Kush

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接