如何在多个重复行中仅返回1行,同时返回不重复的行?

8

我有一个临时表,它看起来像这样:

RequestID   | CreatedDate          | HistoryStatus           
CF-0000001  | 8/26/2009 1:07:01 PM | For Review   
CF-0000001  | 8/26/2009 1:07:01 PM | Completed  
CF-0000112  | 8/26/2009 1:07:01 PM | For Review   
CF-0000113  | 8/26/2009 1:07:01 PM | For Review  
CF-0000114  | 8/26/2009 1:07:01 PM | Completed  
CF-0000115  | 8/26/2009 1:07:01 PM | Completed   

我希望最终表格的样子是这样的:

RequestID   | CreatedDate          | HistoryStatus           
CF-0000001  | 8/26/2009 1:07:01 PM | Completed  
CF-0000112  | 8/26/2009 1:07:01 PM | For Review  
CF-0000113  | 8/26/2009 1:07:01 PM | For Review  
CF-0000114  | 8/26/2009 1:07:01 PM | Completed  
CF-0000115  | 8/26/2009 1:07:01 PM | Completed

即,重复的CF-0000001应该被删除。

如果有多个重复行,我该如何返回或选择仅一个行,并且仍然返回不是重复的行?


6
两张表格是相同的,请修正期望输出。 - shahkalpesh
1
如果RequestID和CreatedDate都相同,应该返回哪一行?或者这并不重要吗? - eksortso
我的解决方案假设日期实际上是不同的,这样你就可以选择最大日期 - 如果不是,需要一种方法来排列状态以知道哪个应该获胜 - 硬编码似乎不太优雅... - D'Arcy Rittich
8个回答

12
如果您想显示基于RequestID和CreatedDate的重复行中的一行,并显示最新的HistoryStatus,请尝试以下操作。
with t as (select row_number()over(partition by RequestID,CreatedDate order by RequestID) as rnum,* from tbltmp)
Select RequestID,CreatedDate,HistoryStatus from t a where  rnum in (SELECT Max(rnum) FROM t GROUP BY RequestID,CreatedDate having t.RequestID=a.RequestID)

如果您想仅考虑CreatedDate选择重复行中的一行并显示最新的HistoryStatus,则可以尝试下面的查询。

with t as (select row_number()over(partition by CreatedDate order by RequestID) as rnum,* from tbltmp)
Select RequestID,CreatedDate,HistoryStatus from t  where  rnum = (SELECT Max(rnum) FROM t)

如果您想选择其中一个重复的行,并仅考虑请求ID,显示最新的HistoryStatus,则使用以下查询

with t as (select row_number()over(partition by RequestID order by RequestID) as rnum,* from tbltmp)
Select RequestID,CreatedDate,HistoryStatus from t a where  rnum in (SELECT Max(rnum) FROM t GROUP BY RequestID,CreatedDate having t.RequestID=a.RequestID)

以上所有查询都是我在SQL Server 2005中编写的。


好的,我在复制粘贴你的示例代码时不小心给你点了反对。但系统不允许我撤销它,所以我改成“赞同”了,这是你的好运气 :-) - Sukotto

5

从标题来看,我猜您只需要每个唯一行的一个结果?如果是这种情况,请查看GROUP BY子句(或SELECT DISTINCT)。


4
select t.*
from (
    select RequestID, max(CreatedDate) as MaxCreatedDate
    from table1
    group by RequestID
) tm
inner join table1 t on tm.RequestID = t.RequestID and tm.MaxCreatedDate = t.CreatedDate

此查询将再次返回“重复项”。当 RequestID ='CF-0000001' 时,CreatedDate 的值相同。 - eksortso
尽管数据没有显示出来,但我实际上假设时间会不同,否则就无法知道在有重复项时应返回哪个状态,而不是硬编码...这个问题表述得不太好。 - D'Arcy Rittich

3
如果您的查询中存在一对多关系,则可能会在其中一侧出现重复行。
假设如下:
TABLE TEAM
ID       TEAM_NAME
0        BULLS
1        LAKERS


TABLE PLAYER
ID       TEAM_ID     PLAYER_NAME
0        0           JORDAN
1        0           PIPPEN

您需要执行类似以下的查询:

SELECT 
    TEAM.TEAM_NAME, 
    PLAYER.PLAYER_NAME 
FROM TEAM
INNER JOIN PLAYER

你将会获得

TEAM_NAME   PLAYER_NAME
BULLS       JORDAN
BULLS       PIPPEN

您可能会遇到重复的团队名称。即使使用DISTINCT子句,结果集中也会包含重复的团队名称。

如果您不想在查询中出现重复的TEAM_NAME,请执行以下操作:

SELECT ID, TEAM_NAME FROM TEAM

对于遇到的每个团队ID,执行以下操作:
SELECT PLAYER_NAME FROM PLAYER WHERE TEAM_ID = <PUT_TEAM_ID_RIGHT_HERE>

这样做可以避免在一侧出现重复的引用

谢谢,


0
select * from temptable
where rnum --unique key
 in 

( 
 SELECT RNUM --unique key
  FROM temptable
 WHERE (  HistoryStatus
) IN (SELECT                HistoryStatus

                             FROM temptable
                            GROUP BY                
HistoryStatus 
                           HAVING COUNT(*) <= 1));

我没有测试过这段代码。我使用了类似的代码,它可以正常工作。 语法是Oracle。


0

使用命名空间和子查询,您可以实现它:

declare @data table (RequestID varchar(20), CreatedDate datetime, HistoryStatus varchar(20))
insert into @data values ('CF-0000001','8/26/2009 1:07:01 PM','For Review');
insert into @data values ('CF-0000001','8/26/2009 1:07:01 PM','Completed');  
insert into @data values ('CF-0000112','8/26/2009 1:07:01 PM','For Review');   
insert into @data values ('CF-0000113','8/26/2009 1:07:01 PM','For Review');  
insert into @data values ('CF-0000114','8/26/2009 1:07:01 PM','Completed');  
insert into @data values ('CF-0000115','8/26/2009 1:07:01 PM','Completed');

select d1.RequestID,d1.CreatedDate,d1.HistoryStatus 
from @data d1 
where d1.HistoryStatus = 'Completed'
union all 
select d2.RequestID,d2.CreatedDate,d2.HistoryStatus 
from @data d2 
where d2.HistoryStatus = 'For Review' 
    and d2.RequestID not in (
        select RequestID 
        from @data 
        where HistoryStatus = 'Completed' 
            and CreatedDate = d2.CreatedDate
    )

上述查询返回

CF-0000001, 2009-08-26 13:07:01.000,    Completed
CF-0000114, 2009-08-26 13:07:01.000,    Completed
CF-0000115, 2009-08-26 13:07:01.000,    Completed
CF-0000112, 2009-08-26 13:07:01.000,    For Review
CF-0000113, 2009-08-26 13:07:01.000,    For Review

-1
如果这是一个SQL问题,并且我理解你的问题(不是完全清楚),只需在查询中添加distinct即可。
   Select Distinct * From TempTable

1
那不会对Chebu有帮助,因为HistoryStatus中的值是不同的。 - eksortso

-3

如果您想从两行重复的列中获取仅一个不同记录,则可以使用 Oracle 自己维护的“rowid”列作为主键,因此首先尝试该方法。

"select rowid,RequestID,CreatedDate,HistoryStatus  from temptable;"

然后,您可以使用SELECT语句按“rowid”列的值仅获取第二行。


这假设使用Oracle,那么如何“通过rowid的值获取第二行”?如果有人需要查看结果集才能弄清楚这是什么,那这不是一个非常有趣的“解决方案”。如果您知道如何编写查询来执行此操作(而无需人为选择rowid),请[编辑]您的问题。 - Mat

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